X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/3814202702cc6ab529c1a0977ea5615c87ce48a8..d2d50ad0de3e25c7ff27beb44a5fdf2db16b5e3a:/package/switch/src/switch-robo.c

diff --git a/package/switch/src/switch-robo.c b/package/switch/src/switch-robo.c
index 5bcd85bd1..ec9e33733 100644
--- a/package/switch/src/switch-robo.c
+++ b/package/switch/src/switch-robo.c
@@ -21,7 +21,6 @@
  * 02110-1301, USA.
  */
 
-#include <linux/autoconf.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/if.h>
@@ -35,12 +34,17 @@
 #include "switch-core.h"
 #include "etc53xx.h"
 
+#ifdef CONFIG_BCM47XX
+#include <nvram.h>
+#endif
+
 #define DRIVER_NAME		"bcm53xx"
 #define DRIVER_VERSION		"0.02"
 #define PFX			"roboswitch: "
 
 #define ROBO_PHY_ADDR		0x1E	/* robo switch phy address */
 #define ROBO_PHY_ADDR_TG3	0x01	/* Tigon3 PHY address */
+#define ROBO_PHY_ADDR_BCM63XX	0x00	/* BCM63XX PHY address */
 
 /* MII registers */
 #define REG_MII_PAGE	0x10	/* MII Page register */
@@ -57,12 +61,12 @@
 #define  ROBO_DEVICE_ID_5395	0x95
 #define  ROBO_DEVICE_ID_5397	0x97
 #define  ROBO_DEVICE_ID_5398	0x98
+#define  ROBO_DEVICE_ID_53115	0x3115
 
 /* Private et.o ioctls */
 #define SIOCGETCPHYRD           (SIOCDEVPRIVATE + 9)
 #define SIOCSETCPHYWR           (SIOCDEVPRIVATE + 10)
 
-
 /* Data structure for a Roboswitch device. */
 struct robo_switch {
 	char *device;			/* The device name string (ethX) */
@@ -88,7 +92,11 @@ static int do_ioctl(int cmd, void *buf)
 		robo.ifr.ifr_data = (caddr_t) buf;
 
 	set_fs(KERNEL_DS);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+	ret = robo.dev->netdev_ops->ndo_do_ioctl(robo.dev, &robo.ifr, cmd);
+#else
 	ret = robo.dev->do_ioctl(robo.dev, &robo.ifr, cmd);
+#endif
 	set_fs(old_fs);
 
 	return ret;
@@ -113,7 +121,7 @@ static u16 mdio_read(__u16 phy_id, __u8 reg)
 			       "[%s:%d] SIOCGETCPHYRD failed!\n", __FILE__, __LINE__);
 			return 0xffff;
 		}
-	
+
 		return args[1];
 	} else {
 		struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &robo.ifr.ifr_data;
@@ -143,7 +151,7 @@ static void mdio_write(__u16 phy_id, __u8 reg, __u16 val)
 
 			return;
 		}
-		
+
 		if (do_ioctl(SIOCSETCPHYWR, args) < 0) {
 			printk(KERN_ERR PFX
 			       "[%s:%d] SIOCGETCPHYWR failed!\n", __FILE__, __LINE__);
@@ -167,13 +175,13 @@ static void mdio_write(__u16 phy_id, __u8 reg, __u16 val)
 static int robo_reg(__u8 page, __u8 reg, __u8 op)
 {
 	int i = 3;
-	
+
 	/* set page number */
-	mdio_write(robo.phy_addr, REG_MII_PAGE, 
+	mdio_write(robo.phy_addr, REG_MII_PAGE,
 		(page << 8) | REG_MII_PAGE_ENABLE);
-	
+
 	/* set register address */
-	mdio_write(robo.phy_addr, REG_MII_ADDR, 
+	mdio_write(robo.phy_addr, REG_MII_ADDR,
 		(reg << 8) | op);
 
 	/* check if operation completed */
@@ -183,7 +191,7 @@ static int robo_reg(__u8 page, __u8 reg, __u8 op)
 	}
 
 	printk(KERN_ERR PFX "[%s:%d] timeout in robo_reg!\n", __FILE__, __LINE__);
-	
+
 	return 0;
 }
 
@@ -191,9 +199,9 @@ static int robo_reg(__u8 page, __u8 reg, __u8 op)
 static void robo_read(__u8 page, __u8 reg, __u16 *val, int count)
 {
 	int i;
-	
+
 	robo_reg(page, reg, REG_MII_ADDR_READ);
-	
+
 	for (i = 0; i < count; i++)
 		val[i] = mdio_read(robo.phy_addr, REG_MII_DATA0 + i);
 }
@@ -202,14 +210,14 @@ static void robo_read(__u8 page, __u8 reg, __u16 *val, int count)
 static __u16 robo_read16(__u8 page, __u8 reg)
 {
 	robo_reg(page, reg, REG_MII_ADDR_READ);
-	
+
 	return mdio_read(robo.phy_addr, REG_MII_DATA0);
 }
 
 static __u32 robo_read32(__u8 page, __u8 reg)
 {
 	robo_reg(page, reg, REG_MII_ADDR_READ);
-	
+
 	return mdio_read(robo.phy_addr, REG_MII_DATA0) +
 		(mdio_read(robo.phy_addr, REG_MII_DATA0 + 1) << 16);
 }
@@ -227,7 +235,7 @@ static void robo_write32(__u8 page, __u8 reg, __u32 val32)
 	/* write data */
 	mdio_write(robo.phy_addr, REG_MII_DATA0, val32 & 65535);
 	mdio_write(robo.phy_addr, REG_MII_DATA0 + 1, val32 >> 16);
-	
+
 	robo_reg(page, reg, REG_MII_ADDR_WRITE);
 }
 
@@ -237,7 +245,7 @@ static int robo_vlan5350(void)
 	/* set vlan access id to 15 and read it back */
 	__u16 val16 = 15;
 	robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
-	
+
 	/* 5365 will refuse this as it does not have this reg */
 	return (robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) == val16);
 }
@@ -246,6 +254,9 @@ static int robo_switch_enable(void)
 {
 	unsigned int i, last_port;
 	u16 val;
+#ifdef CONFIG_BCM47XX
+	char buf[20];
+#endif
 
 	val = robo_read16(ROBO_CTRL_PAGE, ROBO_SWITCH_MODE);
 	if (!(val & (1 << 1))) {
@@ -266,9 +277,13 @@ static int robo_switch_enable(void)
 			robo_write16(ROBO_CTRL_PAGE, i, 0);
 	}
 
-	/* WAN port LED */
-	robo_write16(ROBO_CTRL_PAGE, 0x16, 0x1F);
-
+#ifdef CONFIG_BCM47XX
+	/* WAN port LED, except for Netgear WGT634U */
+	if (nvram_getenv("nvram_type", buf, sizeof(buf)) >= 0) {
+		if (strcmp(buf, "cfe") != 0)
+			robo_write16(ROBO_CTRL_PAGE, 0x16, 0x1F);
+	}
+#endif
 	return 0;
 }
 
@@ -279,6 +294,7 @@ static void robo_switch_reset(void)
 	    (robo.devid == ROBO_DEVICE_ID_5398)) {
 		/* Trigger a software reset. */
 		robo_write16(ROBO_CTRL_PAGE, 0x79, 0x83);
+		mdelay(500);
 		robo_write16(ROBO_CTRL_PAGE, 0x79, 0);
 	}
 }
@@ -287,12 +303,16 @@ static int robo_probe(char *devname)
 {
 	__u32 phyid;
 	unsigned int i;
-	int err;
+	int err = 1;
 
 	printk(KERN_INFO PFX "Probing device %s: ", devname);
 	strcpy(robo.ifr.ifr_name, devname);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
 	if ((robo.dev = dev_get_by_name(devname)) == NULL) {
+#else
+	if ((robo.dev = dev_get_by_name(&init_net, devname)) == NULL) {
+#endif
 		printk("No such device\n");
 		return 1;
 	}
@@ -310,13 +330,14 @@ static int robo_probe(char *devname)
 		/* got phy address check for robo address */
 		struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &robo.ifr.ifr_data;
 		if ((mii->phy_id != ROBO_PHY_ADDR) &&
+		    (mii->phy_id != ROBO_PHY_ADDR_BCM63XX) &&
 		    (mii->phy_id != ROBO_PHY_ADDR_TG3)) {
 			printk("Invalid phy address (%d)\n", mii->phy_id);
-			return 1;
+			goto done;
 		}
 		robo.use_et = 0;
 		/* The robo has a fixed PHY address that is different from the
-		 * Tigon3 PHY address. */
+		 * Tigon3 and BCM63xx PHY address. */
 		robo.phy_addr = ROBO_PHY_ADDR;
 	}
 
@@ -324,8 +345,8 @@ static int robo_probe(char *devname)
 		(mdio_read(robo.phy_addr, 0x3) << 16);
 
 	if (phyid == 0xffffffff || phyid == 0x55210022) {
-		printk("No Robo switch in managed mode found\n");
-		return 1;
+		printk("No Robo switch in managed mode found, phy_id = 0x%08x\n", phyid);
+		goto done;
 	}
 
 	/* Get the device ID */
@@ -342,10 +363,18 @@ static int robo_probe(char *devname)
 	robo_switch_reset();
 	err = robo_switch_enable();
 	if (err)
-		return err;
+		goto done;
+	err = 0;
 
-	printk("found!\n");
-	return 0;
+	printk("found a 5%s%x!%s\n", robo.devid & 0xff00 ? "" : "3", robo.devid,
+		robo.is_5350 ? " It's a 5350." : "");
+
+done:
+	if (err) {
+		dev_put(robo.dev);
+		robo.dev = NULL;
+	}
+	return err;
 }
 
 
@@ -356,7 +385,7 @@ static int handle_vlan_port_read(void *driver, char *buf, int nr)
 	int j;
 
 	val16 = (nr) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
-	
+
 	if (robo.is_5350) {
 		u32 val32;
 		robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
@@ -378,7 +407,7 @@ static int handle_vlan_port_read(void *driver, char *buf, int nr)
 			}
 			len += sprintf(buf + len, "\n");
 		}
-	} else { 
+	} else {
 		robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
 		/* actual read */
 		val16 = robo_read16(ROBO_VLAN_PAGE, ROBO_VLAN_READ);
@@ -411,7 +440,7 @@ static int handle_vlan_port_write(void *driver, char *buf, int nr)
 	switch_vlan_config *c = switch_parse_vlan(d, buf);
 	int j;
 	__u16 val16;
-	
+
 	if (c == NULL)
 		return -EINVAL;
 
@@ -422,6 +451,17 @@ static int handle_vlan_port_write(void *driver, char *buf, int nr)
 	}
 
 	/* write config now */
+
+	if (robo.devid != ROBO_DEVICE_ID_5325) {
+		__u8 regoff = ((robo.devid == ROBO_DEVICE_ID_5395) ||
+			(robo.devid == ROBO_DEVICE_ID_53115)) ? 0x20 : 0;
+
+		robo_write32(ROBO_ARLIO_PAGE, 0x63 + regoff, (c->untag << 9) | c->port);
+		robo_write16(ROBO_ARLIO_PAGE, 0x61 + regoff, nr);
+		robo_write16(ROBO_ARLIO_PAGE, 0x60 + regoff, 1 << 7);
+		return 0;
+	}
+
 	val16 = (nr) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
 	if (robo.is_5350) {
 		robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350,
@@ -459,11 +499,16 @@ static int handle_enable_vlan_read(void *driver, char *buf, int nr)
 static int handle_enable_vlan_write(void *driver, char *buf, int nr)
 {
 	int disable = ((buf[0] != '1') ? 1 : 0);
-	
+
 	robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 :
 		(1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
 	robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 :
-		(1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
+		(robo.devid == ROBO_DEVICE_ID_5325 ? (1 << 1) :
+		0) | (1 << 2) | (1 << 3)); /* RSV multicast */
+
+	if (robo.devid != ROBO_DEVICE_ID_5325)
+		return 0;
+
 	robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 :
 		(1 << 6) /* drop invalid VID frames */);
 	robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 :
@@ -478,7 +523,7 @@ static int handle_reset(void *driver, char *buf, int nr)
 	switch_vlan_config *c = switch_parse_vlan(d, buf);
 	int j;
 	__u16 val16;
-	
+
 	if (c == NULL)
 		return -EINVAL;
 
@@ -520,10 +565,11 @@ static int __init robo_init(void)
 
 	device = strdup("ethX");
 	for (device[3] = '0'; (device[3] <= '3') && notfound; device[3]++) {
-		notfound = robo_probe(device);
+		if (! switch_device_registered (device))
+			notfound = robo_probe(device);
 	}
 	device[3]--;
-	
+
 	if (notfound) {
 		kfree(device);
 		return -ENODEV;
@@ -561,6 +607,10 @@ static int __init robo_init(void)
 			.port_handlers		= NULL,
 			.vlan_handlers		= vlan,
 		};
+		if (robo.devid != ROBO_DEVICE_ID_5325) {
+			driver.ports = 9;
+			driver.cpuport = 8;
+		}
 
 		return switch_register_driver(&driver);
 	}
@@ -569,6 +619,8 @@ static int __init robo_init(void)
 static void __exit robo_exit(void)
 {
 	switch_unregister_driver(DRIVER_NAME);
+	if (robo.dev)
+		dev_put(robo.dev);
 	kfree(robo.device);
 }