summaryrefslogtreecommitdiff
path: root/cleopatre
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre')
-rw-r--r--cleopatre/buildroot/package/ethtool/ethtool.mk6
-rw-r--r--cleopatre/buildroot/package/ethtool/ethtool.patch256
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c26
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c367
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.h91
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/include/linux/ethtool.h17
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/include/linux/phy.h6
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/net/core/ethtool.c6
8 files changed, 728 insertions, 47 deletions
diff --git a/cleopatre/buildroot/package/ethtool/ethtool.mk b/cleopatre/buildroot/package/ethtool/ethtool.mk
index d94de7933a..dd5a15f1af 100644
--- a/cleopatre/buildroot/package/ethtool/ethtool.mk
+++ b/cleopatre/buildroot/package/ethtool/ethtool.mk
@@ -18,7 +18,11 @@ $(ETHTOOL_DIR)/.unpacked: $(DL_DIR)/$(ETHTOOL_SOURCE)
$(ETHTOOL_CAT) $(DL_DIR)/$(ETHTOOL_SOURCE) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
touch $@
-$(ETHTOOL_DIR)/.configured: $(ETHTOOL_DIR)/.unpacked
+$(ETHTOOL_DIR)/.patched: $(ETHTOOL_DIR)/.unpacked
+ toolchain/patch-kernel.sh $(ETHTOOL_DIR) package/ethtool/ \*.patch
+ touch $@
+
+$(ETHTOOL_DIR)/.configured: $(ETHTOOL_DIR)/.patched
(cd $(ETHTOOL_DIR); rm -rf config.cache; \
$(TARGET_CONFIGURE_OPTS) \
$(TARGET_CONFIGURE_ARGS) \
diff --git a/cleopatre/buildroot/package/ethtool/ethtool.patch b/cleopatre/buildroot/package/ethtool/ethtool.patch
new file mode 100644
index 0000000000..36bcfaf64c
--- /dev/null
+++ b/cleopatre/buildroot/package/ethtool/ethtool.patch
@@ -0,0 +1,256 @@
+diff -B -w -ur ethtool-6-spidcom/ethtool.c ethtool-6/ethtool.c
+--- ethtool-6-spidcom/ethtool.c 2010-10-01 18:01:46.000000000 +0200
++++ ethtool-6/ethtool.c 2010-10-01 17:46:05.000000000 +0200
+@@ -90,6 +90,7 @@
+ MODE_GOFFLOAD,
+ MODE_SOFFLOAD,
+ MODE_GSTATS,
++ MODE_SVLAN_SPIDCOM,
+ } mode = MODE_GSET;
+
+ static struct option {
+@@ -109,6 +110,11 @@
+ " [ wol p|u|m|b|a|g|s|d... ]\n"
+ " [ sopass %%x:%%x:%%x:%%x:%%x:%%x ]\n"
+ " [ msglvl %%d ] \n" },
++ { "-vl", "--vlanoptions", MODE_SVLAN_SPIDCOM, "vlan administration",
++ " [ print ] \n"
++ " [ set-phy-vid %%d:%%d ] \n"
++ " [ set-phy-prio %%d:%%d ] \n"
++ " [ set-phy-state %%d:on|off ]\n" },
+ { "-a", "--show-pause", MODE_GPAUSE, "Show pause options" },
+ { "-A", "--pause", MODE_SPAUSE, "Set pause options",
+ " [ autoneg on|off ]\n"
+@@ -155,6 +161,7 @@
+ { "-i", "--driver", MODE_GDRV, "Show driver information" },
+ { "-d", "--register-dump", MODE_GREGS, "Do a register dump",
+ " [ raw on|off ]\n"
++ " [ hex on|off ]\n"
+ " [ file FILENAME ]\n" },
+ { "-e", "--eeprom-dump", MODE_GEEPROM, "Do a EEPROM dump",
+ " [ raw on|off ]\n"
+@@ -193,6 +200,13 @@
+
+ static char *devname = NULL;
+
++static struct ethtool_vlanparam evlanparam;
++static int svlan_changed = 0;
++static char *svlan_state_wanted = NULL;
++static char *svlan_vid_wanted = NULL;
++static char *svlan_prio_wanted = NULL;
++static int svlan_print_wanted = -1;
++
+ static int goffload_changed = 0;
+ static int off_csum_rx_wanted = -1;
+ static int off_csum_tx_wanted = -1;
+@@ -312,6 +326,12 @@
+ { "gso", CMDL_BOOL, &off_gso_wanted, NULL },
+ };
+
++static struct cmdline_info cmdline_svlan[] = {
++ { "set-phy-vid", CMDL_STR, &svlan_vid_wanted, NULL },
++ { "set-phy-prio", CMDL_STR, &svlan_prio_wanted, NULL },
++ { "set-phy-state", CMDL_STR, &svlan_state_wanted, NULL },
++};
++
+ static struct cmdline_info cmdline_pause[] = {
+ { "autoneg", CMDL_BOOL, &pause_autoneg_wanted, &epause.autoneg },
+ { "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
+@@ -430,7 +450,8 @@
+ (mode == MODE_GOFFLOAD) ||
+ (mode == MODE_SOFFLOAD) ||
+ (mode == MODE_GSTATS) ||
+- (mode == MODE_PHYS_ID)) {
++ (mode == MODE_PHYS_ID) ||
++ (mode == MODE_SVLAN_SPIDCOM)) {
+ devname = argp[i];
+ break;
+ }
+@@ -509,6 +530,21 @@
+ i = argc;
+ break;
+ }
++ if (mode == MODE_SVLAN_SPIDCOM) {
++ int l;
++ parse_generic_cmdline(argc, argp, i,
++ &svlan_changed,
++ cmdline_svlan,
++ ARRAY_SIZE(cmdline_svlan));
++
++ for (l = 3; l < argc; l++) {
++ if (!strcmp(argp[l], "print")) {
++ svlan_print_wanted = 1;
++ }
++ }
++ i = argc;
++ break;
++ }
+ if (mode != MODE_SSET)
+ show_usage(1);
+ if (!strcmp(argp[i], "speed")) {
+@@ -1226,6 +1262,114 @@
+ return 0;
+ }
+
++static int do_svlan(int fd, struct ifreq *ifr)
++{
++ int err, changed = 0;
++
++ evlanparam.cmd = ETHTOOL_RVLAN_TABLE;
++ ifr->ifr_data = (caddr_t)&evlanparam;
++ err = ioctl(fd, SIOCETHTOOL, ifr);
++ if (err) {
++ perror("Cannot get current device settings");
++ return 0;
++ }
++
++ if (svlan_changed) {
++ if (svlan_vid_wanted != NULL) {
++ unsigned int phy, vid;
++ //format is [ set-phy-vid %%u:%%u ]
++ sscanf (svlan_vid_wanted, "%u:%u", &phy, &vid);
++
++ // VID is 12 bits.
++ if (phy >= MAX_VLAN_SUPPORTED) {
++ perror("Cannot set vlan parameters : phy range from 0 to 4\n");
++ return 0;
++ }
++
++ if (vid > 0xFFF) {
++ perror("Cannot set vlan parameters : VID range from 0 to 4095\n");
++ return 0;
++ }
++
++ evlanparam.vlan_table[phy].vlan = (evlanparam.vlan_table[phy].vlan & ~0x0fff) | vid;
++ }
++
++ if (svlan_prio_wanted != NULL) {
++ unsigned int phy, prio;
++ //format is [ set-phy-prio %%u:%%u ]
++ sscanf (svlan_prio_wanted, "%u:%u", &phy, &prio);
++
++ // prio is 3 bits.
++ if (phy >= MAX_VLAN_SUPPORTED) {
++ perror("Cannot set vlan parameters : phy range from 0 to 4\n");
++ return 0;
++ }
++
++ if (prio > 7) {
++ perror("Cannot set vlan parameters : prio range from 0 to 7\n");
++ return 0;
++ }
++
++ evlanparam.vlan_table[phy].vlan = (evlanparam.vlan_table[phy].vlan & ~0xe000) | (prio << 13);
++ }
++
++ if (svlan_state_wanted != NULL) {
++ unsigned int phy;
++ char *state;
++ char *ptr;
++ //format is [ set-phy-state %%d:on|off ]
++ if ((ptr = strchr (svlan_state_wanted, ':')) == NULL)
++ {
++ perror ("Bad format for phy state setting\n");
++ return 0;
++ }
++ *ptr = '\0';
++ sscanf (svlan_state_wanted, "%u", &phy);
++ state = ptr + 1;
++ // VID is 12 bits.
++ if (phy >= MAX_VLAN_SUPPORTED) {
++ perror("Cannot set vlan parameters : phy range from 0 to 4\n");
++ return 0;
++ }
++
++ if (!strcmp (state, "on"))
++ evlanparam.vlan_table[phy].state = VLAN_ON;
++ else if (!strcmp(state, "off"))
++ evlanparam.vlan_table[phy].state = VLAN_OFF;
++ else
++ show_usage(1);
++ }
++
++ evlanparam.cmd = ETHTOOL_SVLAN_TABLE;
++ ifr->ifr_data = (caddr_t)&evlanparam;
++ err = ioctl(fd, SIOCETHTOOL, ifr);
++ if (err) {
++ perror("Cannot set vlan parameters : socket fail\n");
++ return 0;
++ }
++ }
++
++ if (svlan_print_wanted != -1) {
++ int i;
++
++ fprintf(stdout, "vlan table:\n");
++ fprintf(stdout, " %3s | %5s | %5s | %5s\n", "phy", "vid", "prio", "state");
++
++ for (i=0; i<MAX_VLAN_SUPPORTED; i++)
++ {
++ fprintf(stdout, " %3d | %5d | %5d | %5s\n", i,
++ evlanparam.vlan_table[i].vlan & 0x0fff,
++ (evlanparam.vlan_table[i].vlan >> 13),
++ (evlanparam.vlan_table[i].state == VLAN_ON) ? "on" : "off");
++ }
++ fprintf(stdout, "\n");
++ }
++
++ return 0;
++}
++
++
++
+ static int doit(void)
+ {
+ struct ifreq ifr;
+@@ -1249,6 +1393,8 @@
+ return do_gset(fd, &ifr);
+ } else if (mode == MODE_SSET) {
+ return do_sset(fd, &ifr);
++ } else if (mode == MODE_SVLAN_SPIDCOM) {
++ return do_svlan(fd, &ifr);
+ } else if (mode == MODE_GREGS) {
+ return do_gregs(fd, &ifr);
+ } else if (mode == MODE_NWAY_RST) {
+@@ -1648,6 +1794,9 @@
+
+ fprintf(stdout, "Settings for %s:\n", devname);
+
++ if (phyad_wanted != -1)
++ ecmd.phy_address = phyad_wanted;
++
+ ecmd.cmd = ETHTOOL_GSET;
+ ifr->ifr_data = (caddr_t)&ecmd;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+diff -B -w -ur ethtool-6-spidcom/ethtool-copy.h ethtool-6/ethtool-copy.h
+--- ethtool-6-spidcom/ethtool-copy.h 2010-10-01 18:01:46.000000000 +0200
++++ ethtool-6/ethtool-copy.h 2010-10-01 17:46:05.000000000 +0200
+@@ -221,6 +221,19 @@
+ ETH_SS_STATS,
+ };
+
++#define MAX_VLAN_SUPPORTED 5
++#define VLAN_OFF 0
++#define VLAN_ON 1
++
++struct ethtool_vlanparam {
++ u32 cmd; /* ETHTOOL_RVLAN_TABLE, ETHTOOL_SVLAN_TABLE*/
++
++ struct {
++ u8 state;
++ u16 vlan;
++ }vlan_table[MAX_VLAN_SUPPORTED];
++};
++
+ /* for passing string sets for data tagging */
+ struct ethtool_gstrings {
+ __u32 cmd; /* ETHTOOL_GSTRINGS */
+@@ -414,6 +427,8 @@
+ #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
+ #define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */
+ #define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
++#define ETHTOOL_RVLAN_TABLE 0x00000029 /* Read VLAN Table (SPIDCOM Code) */
++#define ETHTOOL_SVLAN_TABLE 0x0000002a /* WriteVLAN Table (SPIDCOM Code) */
+
+ /* compatibility with older code */
+ #define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
index 89c997844f..53a25c1326 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
@@ -27,7 +27,7 @@
*/
#define DRV_NAME "Synop3504"
-#define DRV_VERSION "3.1"
+#define DRV_VERSION "3.2"
#define DRV_RELDATE "nov 17, 2009"
//#define TRACE_FRAME 1
@@ -646,6 +646,30 @@ static int synop3504_ethtool_ioctl(struct net_device *dev, void *useraddr)
return -EFAULT;
return 0;
}
+ case ETHTOOL_RVLAN_TABLE:
+ {
+ struct ethtool_vlanparam ecmd;
+
+ if (priv->phydev->drv->read_vlan_table (priv->phydev, &ecmd))
+ return -EFAULT;
+
+ if(copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case ETHTOOL_SVLAN_TABLE:
+ {
+ struct ethtool_vlanparam ecmd;
+
+ if(copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+
+ if (priv->phydev->drv->write_vlan_table (priv->phydev, &ecmd))
+ return -EFAULT;
+
+ return 0;
+ }
default:
break;
}
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c
index be4c3387f5..b7feecd0a2 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c
@@ -1,14 +1,23 @@
-/*
- * Driver for ICPlus PHYs
+/* Cleopatre project {{{
*
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 SPiDCOM Technologies
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
*
- */
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * }}} */
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -31,44 +40,309 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-MODULE_DESCRIPTION("ICPlus IP175C PHY driver");
-MODULE_AUTHOR("Michael Barkowski");
+#include "icplus.h"
+
+//#define TRACE(...) printk(DRV_NAME": " __VA_ARGS__)
+#define TRACE(...)
+
+MODULE_DESCRIPTION("ICPlus ip175C/D PHY driver");
+MODULE_AUTHOR("SPiDCOM Technologies");
MODULE_LICENSE("GPL");
-static int ip175c_config_init(struct phy_device *phydev)
+
+/** Private structure for our phy device */
+struct ip175x_priv
+{
+ struct phy_device *phydev;
+ uint32_t model;
+ uint16_t vlan_valid;
+};
+
+
+int ip175x_read_vlan_table (struct phy_device *phydev, struct ethtool_vlanparam *ecmd)
+{
+ struct ip175x_priv *priv = phydev->priv;
+ u16 reg;
+ int port;
+
+ switch(priv->model)
+ {
+ case ICPLUS_MODEL_IP175D:
+ // Read VLAN_MODE[5:0] field in PHY22, MII0.
+ reg = phydev->bus->read(phydev->bus,
+ IP175D_VLAN_CLS_REG_PHY,
+ IP175D_VLAN_CLS_REG_NUM);
+ TRACE ("IP175D_VLAN_CLS_REG (%d:%d)= %x\n",IP175D_VLAN_CLS_REG_PHY, IP175D_VLAN_CLS_REG_NUM, reg);
+ for (port = 0; port < MAX_VLAN_SUPPORTED; port++)
+ {
+ ecmd->vlan_table[port].state = (reg & (1 << port)) != 0 ? VLAN_ON : VLAN_OFF;
+ ecmd->vlan_table[port].vlan = phydev->bus->read(phydev->bus,
+ IP175D_VLAN_INFO_REG_PHY,
+ IP175D_VLAN_INFO_REG_NUM(port));
+ TRACE("IP175D_VLAN_INFO_REG (%d:%d) =%x\n", IP175D_VLAN_INFO_REG_PHY, IP175D_VLAN_INFO_REG_NUM(port), ecmd->vlan_table[port].vlan);
+ }
+ break;
+
+ default :
+ // Feature not supported
+ return -EOPNOTSUPP;
+
+ }
+
+ return 0;
+}
+
+int ip175x_write_vlan_table (struct phy_device *phydev, struct ethtool_vlanparam *ecmd)
+{
+ struct ip175x_priv *priv = phydev->priv;
+ uint8_t add_tag[IP175D_VLAN_TABLE_SIZE];
+ uint8_t remove_tag[IP175D_VLAN_TABLE_SIZE];
+ uint8_t vlan_member[IP175D_VLAN_TABLE_SIZE];
+
+ memset(add_tag, 0, sizeof(add_tag));
+ memset(remove_tag, 0, sizeof(remove_tag));
+ memset(vlan_member, 0, sizeof(vlan_member));
+
+ switch(priv->model)
+ {
+ case ICPLUS_MODEL_IP175D:
+ {
+ int i, j;
+
+ // entry from 0 to 4 are reserved for port-based or tag-based.
+ for (i=0; i < MAX_VLAN_SUPPORTED; i++)
+ {
+ // Write VLAN_INFO_x ( PVID )
+ phydev->bus->write( phydev->bus,
+ IP175D_VLAN_INFO_REG_PHY,
+ IP175D_VLAN_INFO_REG_NUM(i),
+ (ecmd->vlan_table[i].vlan & 0xFFF));
+ TRACE("IP175D_VLAN_INFO_REG w%d:%d=%x\n", IP175D_VLAN_INFO_REG_PHY, IP175D_VLAN_INFO_REG_NUM(i), (ecmd->vlan_table[i].vlan & 0xFFF));
+
+ // Write the VID_x
+ phydev->bus->write( phydev->bus,
+ IP175D_VLAN_ID_REG_PHY,
+ IP175D_VLAN_ID_REG_NUM(i),
+ (ecmd->vlan_table[i].vlan & 0xFFF));
+ TRACE("IP175D_VLAN_ID_REG w%d:%d=%x\n", IP175D_VLAN_ID_REG_PHY, IP175D_VLAN_ID_REG_NUM(i), (ecmd->vlan_table[i].vlan & 0xFFF));
+
+ if (ecmd->vlan_table[i].state == VLAN_ON)
+ SETBIT(priv->vlan_valid,i);
+ else
+ CLEARBIT(priv->vlan_valid,i);
+ }
+
+ // entry 5, is connected to spc300. special entry. always in tag mode.
+ SETBIT(priv->vlan_valid,IP175D_VLAN_TABLE_COMMON_PHY);
+ vlan_member[IP175D_VLAN_TABLE_COMMON_PHY] = 0x3F; // Maybe this line is not usefull.
+ phydev->bus->write(phydev->bus,
+ IP175D_VLAN_INFO_REG_PHY,
+ IP175D_VLAN_INFO_REG_NUM(IP175D_VLAN_TABLE_COMMON_PHY),
+ 0); // PVID_5 = 0
+
+ // entry 6.
+ SETBIT(priv->vlan_valid,IP175D_VLAN_TABLE_NO_TAG_LINE);
+ SETBIT(vlan_member[IP175D_VLAN_TABLE_NO_TAG_LINE],IP175D_VLAN_TABLE_COMMON_PHY);
+ phydev->bus->write(phydev->bus,
+ IP175D_VLAN_ID_REG_PHY,
+ IP175D_VLAN_ID_REG_NUM(IP175D_VLAN_TABLE_NO_TAG_LINE),
+ 0); // Write the PVID_6 (= PVID_5)
+
+ for (i=0; i < MAX_VLAN_SUPPORTED; i++)
+ {
+ if (ecmd->vlan_table[i].state == VLAN_ON)
+ {
+ SETBIT(add_tag[i],IP175D_VLAN_TABLE_COMMON_PHY); // Add tag from outside to spc300.
+ remove_tag[i] = 0x1F; // Remove tag from spc300 to outside and from other port also.
+ SETBIT(vlan_member[i],IP175D_VLAN_TABLE_COMMON_PHY);
+ SETBIT(vlan_member[i],i);
+
+ for (j=i+1; j < MAX_VLAN_SUPPORTED; j++)
+ {
+ // The same VID can forward the packet between them.
+ if ((ecmd->vlan_table[i].vlan == ecmd->vlan_table[j].vlan) &&
+ (ecmd->vlan_table[j].state == VLAN_ON)
+ )
+ {
+ SETBIT(vlan_member[i],j);
+ SETBIT(vlan_member[j],i);
+ }
+ }
+ }
+ else
+ {
+ // The no-VID can forward the packet between them.
+ SETBIT(vlan_member[IP175D_VLAN_TABLE_NO_TAG_LINE], i);
+ }
+ }
+
+ for (i=0; i < MAX_VLAN_SUPPORTED; i++)
+ {
+ if (ecmd->vlan_table[i].state == VLAN_OFF)
+ {
+ // The no-VID have the same forward rules.
+ vlan_member[i] = vlan_member[IP175D_VLAN_TABLE_NO_TAG_LINE];
+ }
+ }
+
+ for (i=0; i < IP175D_VLAN_TABLE_SIZE; i+=2)
+ {
+ uint16_t reg;
+
+ reg = ((vlan_member[i+1] << 8) & 0xFF00) + (vlan_member[i+0] & 0x00FF);
+ phydev->bus->write( phydev->bus,
+ IP175D_VLAN_MEMBER_REG_PHY,
+ IP175D_VLAN_MEMBER_REG_NUM(i),
+ reg); // VLAN_MEMBER
+
+ reg = ((add_tag[i+1] << 8) & 0xFF00) + (add_tag[i+0] & 0x00FF);
+ phydev->bus->write( phydev->bus,
+ IP175D_ADD_TAG_REG_PHY,
+ IP175D_ADD_TAG_REG_NUM(i),
+ reg); // ADD_TAG
+
+ reg = ((remove_tag[i+1] << 8) & 0xFF00) + (remove_tag[i+0] & 0x00FF);
+ phydev->bus->write( phydev->bus,
+ IP175D_REMOVE_TAG_REG_PHY,
+ IP175D_REMOVE_TAG_REG_NUM(i),
+ reg); // REMOVE_TAG
+ }
+
+ // Global register
+ phydev->bus->write(phydev->bus,
+ IP175D_VLAN_CLS_REG_PHY,
+ IP175D_VLAN_CLS_REG_NUM,
+ UNVID_MODE_FORWARD_TO_CPU | (priv->vlan_valid & 0x3F)); // Write the VLAN_Mode (TAGGED BASED)
+
+ phydev->bus->write(phydev->bus,
+ IP175D_VLAN_VALID_REG_PHY,
+ IP175D_VLAN_VALID_REG_NUM,
+ priv->vlan_valid); // Write the VLAN_VALID
+ }
+ break;
+
+ default :
+ // Feature not supported
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+
+static int ip175x_get_model(struct phy_device *phydev)
+{
+ struct ip175x_priv *priv;
+ priv = (struct ip175x_priv *)phydev->priv;
+
+ if (!phydev)
+ {
+ printk (KERN_ERR "%s: no PHY found\n", DRV_NAME);
+ return -EINVAL;
+ }
+
+ if(0x175D == phydev->bus->read(phydev->bus, 20, 0))
+ {
+ priv->model = ICPLUS_MODEL_IP175D;
+ TRACE("PHY model is IC+ IP175D \n");
+ }
+ else
+ {
+ priv->model = ICPLUS_MODEL_IP175C;
+ TRACE("PHY model is IC+ ip175C \n");
+ }
+ return 0;
+}
+
+static int ip175x_probe(struct phy_device *phydev)
+{
+ struct ip175x_priv *priv;
+ int err;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+ priv->phydev = phydev;
+
+ err = ip175x_get_model(phydev);
+ if (err < 0)
+ goto error;
+
+ return 0;
+
+error:
+ kfree(priv);
+ return err;
+}
+
+
+static int ip175x_config_init(struct phy_device *phydev)
{
int err, i;
+ struct ip175x_priv *priv;
static int full_reset_performed = 0;
- printk("ICPlus IP175C : Driver Initialization - PHY addr = %d\n", phydev->addr);
+ priv = (struct ip175x_priv *)phydev->priv;
+
+ printk("ICPlus ip175x : Driver Initialization - PHY addr = %d\n", phydev->addr);
if (full_reset_performed == 0) {
- /* master reset */
- err = phydev->bus->write(phydev->bus, 30, 0, 0x175c);
- if (err < 0)
- return err;
+ if (priv->model == ICPLUS_MODEL_IP175C){
+ /* master reset */
+ err = phydev->bus->write(phydev->bus, 30, 0, IP175C_RESET_VAL);
+ if (err < 0)
+ return err;
+
+ /* ensure no bus delays overlap reset period */
+ err = phydev->bus->read(phydev->bus, 30, 0);
+ if (err < 0)
+ return err;
- /* ensure no bus delays overlap reset period */
- err = phydev->bus->read(phydev->bus, 30, 0);
+ /* data sheet specifies reset period is 2 msec */
+ mdelay(2);
- /* data sheet specifies reset period is 2 msec */
- mdelay(2);
+ /* enable ip175x mode */
+ err = phydev->bus->write(phydev->bus, 29, 31, IP175C_RESET_VAL);
+ if (err < 0)
+ return err;
- /* enable IP175C mode */
- err = phydev->bus->write(phydev->bus, 29, 31, 0x175c);
- if (err < 0)
- return err;
+ /* Set MII0 speed and duplex (in PHY mode) */
+ err = phydev->bus->write(phydev->bus, 29, 22, 0x420);
+ if (err < 0)
+ return err;
+ }
+ else if (priv->model == ICPLUS_MODEL_IP175D)
+ {
+ // Reset the Switch
+ err = phydev->bus->write(phydev->bus,
+ IP175D_SOFT_RESET_REG_PHY,
+ IP175D_SOFT_RESET_REG_NUM,
+ IP175D_RESET_VAL);
+ if (err < 0)
+ return err;
+ mdelay(2);
- /* Set MII0 speed and duplex (in PHY mode) */
- err = phydev->bus->write(phydev->bus, 29, 22, 0x420);
- if (err < 0)
- return err;
+ // Reset Vlan Table. PHY22 MII0, MSB.
+ err = phydev->bus->write(phydev->bus, IP175D_VLAN_CLS_REG_PHY,
+ IP175D_VLAN_CLS_REG_NUM,
+ VLAN_TABLE_CLR);
+ if (err < 0)
+ return err;
+
+ // SET TPID Vlan. Ox8100.
+ err = phydev->bus->write(phydev->bus,
+ IP175D_VLAN_TPID_VAL_REG_PHY,
+ IP175D_VLAN_TPID_VAL_REG_NUM,
+ 0x8100);
+ if (err < 0)
+ return err;
+ }
/* reset switch ports */
for (i = 0; i < 5; i++) {
- err = phydev->bus->write(phydev->bus, i,
- MII_BMCR, BMCR_RESET);
+ err = phydev->bus->write(phydev->bus, i, MII_BMCR, BMCR_RESET);
if (err < 0)
return err;
}
@@ -92,14 +366,15 @@ static int ip175c_config_init(struct phy_device *phydev)
return 0;
}
-static int ip175c_read_status(struct phy_device *phydev)
+
+static int ip175x_read_status(struct phy_device *phydev)
{
int i, status;
if (phydev->addr == 4) /* WAN port */
genphy_read_status(phydev);
- if (phydev->addr == 5) /* MAC 5 */
+ if (phydev->addr == 5) /* MAC 5 */
{
/* Read all links status */
phydev->link = 0;
@@ -116,11 +391,10 @@ static int ip175c_read_status(struct phy_device *phydev)
phydev->link = 1;
}
}
-
return 0;
}
-static int ip175c_config_aneg(struct phy_device *phydev)
+static int ip175x_config_aneg(struct phy_device *phydev)
{
if (phydev->addr == 5) /* MAC 5 */
{
@@ -135,26 +409,29 @@ static int ip175c_config_aneg(struct phy_device *phydev)
return 0;
}
-static struct phy_driver ip175c_driver = {
+static struct phy_driver ip175x_driver = {
.phy_id = 0x02430d80,
- .name = "ICPlus IP175C",
+ .name = "ICPlus ip175x",
.phy_id_mask = 0x0ffffff0,
.features = PHY_BASIC_FEATURES,
- .config_init = &ip175c_config_init,
- .config_aneg = &ip175c_config_aneg,
- .read_status = &ip175c_read_status,
+ .config_init = &ip175x_config_init,
+ .probe = &ip175x_probe,
+ .config_aneg = &ip175x_config_aneg,
+ .read_status = &ip175x_read_status,
.driver = { .owner = THIS_MODULE,},
+ .read_vlan_table = &ip175x_read_vlan_table,
+ .write_vlan_table = &ip175x_write_vlan_table,
};
-static int __init ip175c_init(void)
+static int __init ip175x_init(void)
{
- return phy_driver_register(&ip175c_driver);
+ return phy_driver_register(&ip175x_driver);
}
-static void __exit ip175c_exit(void)
+static void __exit ip175x_exit(void)
{
- phy_driver_unregister(&ip175c_driver);
+ phy_driver_unregister(&ip175x_driver);
}
-module_init(ip175c_init);
-module_exit(ip175c_exit);
+module_init(ip175x_init);
+module_exit(ip175x_exit);
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.h b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.h
new file mode 100644
index 0000000000..b902e81251
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.h
@@ -0,0 +1,91 @@
+#ifndef _IP175_H
+#define _IP175_H
+
+#define DRV_NAME "ICPlus_IP175"
+#define DRV_VERSION "1.1"
+#define DRV_RELDATE "Sep 20th, 2010"
+
+/*****************************************************/
+/***************** ICPLUS_IP175D *******************/
+/*****************************************************/
+
+#define IP175D_VLAN_TABLE_SIZE 16
+#define IP175D_VLAN_TABLE_COMMON_PHY 5
+#define IP175D_VLAN_TABLE_NO_TAG_LINE 6
+
+#define IP175D_RESET_VAL 0x175D
+#define IP175C_RESET_VAL 0x175C
+
+
+#define SETBIT(x,y) ((x) |= (1<<(y)))
+#define CLEARBIT(x,y) ((x) &= (~(1<<(y))))
+
+/************************************
+ VLAN Group Control Register
+************************************/
+
+#define IP175D_SOFT_RESET_REG_PHY 20
+#define IP175D_SOFT_RESET_REG_NUM 2
+
+#define IP175D_VLAN_CLS_REG_PHY 22
+#define IP175D_VLAN_CLS_REG_NUM 0
+
+#define VLAN_TABLE_CLR 0x8000
+#define UNVID_MODE_DISCARD 0x0000
+#define UNVID_MODE_FORWARD_TO_CPU 0x1000
+#define UNVID_MODE_FLOOD_PACKET 0x2000
+#define UNVID_MODE_RESERVED 0x3000
+#define VLAN_CLS_USE_VID(p) (0)
+#define VLAN_CLS_USE_PVID(p) (1<(6+p))
+#define VLAN_MODE_PORT_BASED(p) (0)
+#define VLAN_MODE_TAGGED_BASED(p) (1<p)
+
+#define IP175D_VLAN_INGRESS_RULE_REG_PHY 22
+#define IP175D_VLAN_INGRESS_RULE_REG_NUM 1
+#define IP175D_VLAN_EGRESS_RULE_REG_PHY 22
+#define IP175D_VLAN_EGRESS_RULE_REG_NUM 2
+#define IP175D_VLAN_TPID_VAL_REG_PHY 22
+#define IP175D_VLAN_TPID_VAL_REG_NUM 3
+#define IP175D_VLAN_INFO_REG_PHY 22
+#define IP175D_VLAN_INFO_REG_NUM(p) (4+p)
+
+/************************************
+ VLAN TABLE REGISTER
+************************************/
+#define IP175D_VLAN_VALID_REG_PHY 22
+#define IP175D_VLAN_VALID_REG_NUM 10
+
+#define IP175D_QU_NUM_EN_REG_PHY 22
+#define IP175D_QU_NUM_EN_REG_NUM 11
+
+#define IP175D_STP_IDX_EN_REG_PHY 22
+#define IP175D_STP_IDX_EN_REG_NUM 12
+
+#define IP175D_REW_VLAN_PRI_EN_REG_PHY 22
+#define IP175D_REW_VLAN_PRI_EN_REG_NUM 13
+
+#define IP175D_VLAN_ID_REG_PHY 22
+#define IP175D_VLAN_ID_REG_NUM(i) (14+i)
+
+#define IP175D_VLAN_MEMBER_REG_PHY 23
+#define IP175D_VLAN_MEMBER_REG_NUM(i) (i/2)
+
+#define IP175D_ADD_TAG_REG_PHY 23
+#define IP175D_ADD_TAG_REG_NUM(i) (8+(i/2))
+
+#define IP175D_REMOVE_TAG_REG_PHY 23
+#define IP175D_REMOVE_TAG_REG_NUM(i) (16+(i/2))
+
+#define IP175D_VLAN_MISC_REG_PHY 23
+#define IP175D_VLAN_MISC_REG_NUM(i) (24+(i/2))
+
+
+/************************************
+************************************/
+
+enum {
+ ICPLUS_MODEL_IP175C = 0,
+ ICPLUS_MODEL_IP175D = 1,
+};
+
+#endif /* _IP175_H */
diff --git a/cleopatre/linux-2.6.25.10-spc300/include/linux/ethtool.h b/cleopatre/linux-2.6.25.10-spc300/include/linux/ethtool.h
index c8d2163578..5766b81ec0 100644
--- a/cleopatre/linux-2.6.25.10-spc300/include/linux/ethtool.h
+++ b/cleopatre/linux-2.6.25.10-spc300/include/linux/ethtool.h
@@ -224,6 +224,20 @@ enum ethtool_stringset {
ETH_SS_PRIV_FLAGS,
};
+#define MAX_VLAN_SUPPORTED 5
+#define VLAN_OFF 0
+#define VLAN_ON 1
+
+struct ethtool_vlanparam {
+ u32 cmd; /* ETHTOOL_RVLAN_TABLE, ETHTOOL_SVLAN_TABLE*/
+
+ struct {
+ u8 state;
+ u16 vlan;
+ }vlan_table[MAX_VLAN_SUPPORTED];
+};
+
+
/* for passing string sets for data tagging */
struct ethtool_gstrings {
__u32 cmd; /* ETHTOOL_GSTRINGS */
@@ -441,6 +455,9 @@ struct ethtool_ops {
#define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */
#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */
#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */
+#define ETHTOOL_RVLAN_TABLE 0x00000029 /* Read VLAN Table (SPIDCOM Code) */
+#define ETHTOOL_SVLAN_TABLE 0x0000002a /* WriteVLAN Table (SPIDCOM Code) */
+
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/cleopatre/linux-2.6.25.10-spc300/include/linux/phy.h b/cleopatre/linux-2.6.25.10-spc300/include/linux/phy.h
index 5e43ae7514..f26e273ee3 100644
--- a/cleopatre/linux-2.6.25.10-spc300/include/linux/phy.h
+++ b/cleopatre/linux-2.6.25.10-spc300/include/linux/phy.h
@@ -356,6 +356,12 @@ struct phy_driver {
void (*remove)(struct phy_device *phydev);
struct device_driver driver;
+
+ /* Read VLAN Table */
+ int (*read_vlan_table)(struct phy_device *phydev, struct ethtool_vlanparam *ecmd);
+
+ /* Write VLAN Table */
+ int (*write_vlan_table)(struct phy_device *phydev, struct ethtool_vlanparam *ecmd);
};
#define to_phy_driver(d) container_of(d, struct phy_driver, driver)
diff --git a/cleopatre/linux-2.6.25.10-spc300/net/core/ethtool.c b/cleopatre/linux-2.6.25.10-spc300/net/core/ethtool.c
index 1163eb2256..cfab496f1f 100644
--- a/cleopatre/linux-2.6.25.10-spc300/net/core/ethtool.c
+++ b/cleopatre/linux-2.6.25.10-spc300/net/core/ethtool.c
@@ -796,6 +796,11 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
+
+ if((ethcmd == ETHTOOL_RVLAN_TABLE)||
+ (ethcmd == ETHTOOL_SVLAN_TABLE))
+ return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
+
/* Allow some commands to be done by anyone */
switch(ethcmd) {
case ETHTOOL_GDRVINFO:
@@ -975,6 +980,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
netdev_features_change(dev);
return rc;
+
}
EXPORT_SYMBOL(ethtool_op_get_link);