update mvswitch for 2.6.25 and 2.6.26 as well
authorFelix Fietkau <nbd@openwrt.org>
Mon, 21 Jul 2008 18:20:09 +0000 (18:20 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 21 Jul 2008 18:20:09 +0000 (18:20 +0000)
SVN-Revision: 11896

target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.c
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.h
target/linux/generic-2.6/files-2.6.26/drivers/net/phy/mvswitch.c
target/linux/generic-2.6/files-2.6.26/drivers/net/phy/mvswitch.h

index be9e6afd2d14fbff7ecc5ab30bd39c8e0247aa3b..78e5afe9bd4ac3a0f90da2c7b6a935e113b01d40 100644 (file)
@@ -78,8 +78,8 @@ mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
        if (__vlan_hwaccel_get_tag(skb, &vid))
                goto error;
 
-       if ((skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
-               if (pskb_expand_head(skb, MV_HEADER_SIZE, 0, GFP_ATOMIC))
+       if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
+               if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC))
                        goto error_expand;
                if (skb->len < 62)
                        skb->len = 62;
@@ -216,6 +216,20 @@ mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 }
 
 
+static int
+mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val)
+{
+       int i = 100;
+       u16 r;
+
+       do {
+               r = r16(pdev, addr, reg) & mask;
+               if (r == val)
+                       return 0;
+       } while(--i > 0);
+       return -ETIMEDOUT;
+}
+
 static int
 mvswitch_config_init(struct phy_device *pdev)
 {
@@ -231,6 +245,7 @@ mvswitch_config_init(struct phy_device *pdev)
        pdev->supported = ADVERTISED_100baseT_Full;
        pdev->advertising = ADVERTISED_100baseT_Full;
        dev->phy_ptr = priv;
+       dev->irq = PHY_POLL;
 
        /* initialize default vlans */
        for (i = 0; i < MV_PORTS; i++)
@@ -242,25 +257,22 @@ mvswitch_config_init(struct phy_device *pdev)
 
        msleep(2); /* wait for the status change to settle in */
 
-       /* put the device in reset and set ATU flags */
+       /* put the ATU in reset */
+       w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET);
+
+       i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0);
+       if (i < 0) {
+               printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
+               return i;
+       }
+
+       /* set the ATU flags */
        w16(pdev, MV_SWITCHREG(ATU_CTRL),
-               MV_ATUCTL_RESET |
+               MV_ATUCTL_NO_LEARN |
                MV_ATUCTL_ATU_1K |
                MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */
        );
 
-       i = 100; /* timeout */
-       do {
-               if (!(r16(pdev, MV_SWITCHREG(ATU_CTRL)) & MV_ATUCTL_RESET))
-                       break;
-               msleep(1);
-       } while (--i > 0);
-
-       if (!i) {
-               printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
-               return -ETIMEDOUT;
-       }
-
        /* initialize the cpu port */
        w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
 #ifdef HEADER_MODE
@@ -288,7 +300,7 @@ mvswitch_config_init(struct phy_device *pdev)
                }
                /* leave port unconfigured if it's not part of a vlan */
                if (!vlmap)
-                       break;
+                       continue;
 
                /* add the cpu port to the allowed destinations list */
                vlmap |= (1 << MV_CPUPORT);
@@ -299,19 +311,17 @@ mvswitch_config_init(struct phy_device *pdev)
                /* apply vlan settings */
                w16(pdev, MV_PORTREG(VLANMAP, i),
                        MV_PORTVLAN_PORTS(vlmap) |
-                       MV_PORTVLAN_ID(pvid)
+                       MV_PORTVLAN_ID(i)
                );
 
                /* re-enable port */
-               w16(pdev, MV_PORTREG(CONTROL, i), MV_PORTCTRL_ENABLED);
+               w16(pdev, MV_PORTREG(CONTROL, i),
+                       MV_PORTCTRL_ENABLED
+               );
        }
 
-       /* build the target list for the cpu port */
-       for (i = 0; i < MV_PORTS; i++)
-               vlmap |= (1 << i);
-
        w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
-               MV_PORTVLAN_PORTS(vlmap)
+               MV_PORTVLAN_ID(MV_CPUPORT)
        );
 
        /* set the port association vector */
@@ -343,11 +353,28 @@ mvswitch_config_init(struct phy_device *pdev)
 }
 
 static int
-mvswitch_read_status(struct phy_device *phydev)
+mvswitch_read_status(struct phy_device *pdev)
 {
-       phydev->speed = SPEED_100;
-       phydev->duplex = DUPLEX_FULL;
-       phydev->state = PHY_UP;
+       pdev->speed = SPEED_100;
+       pdev->duplex = DUPLEX_FULL;
+       pdev->state = PHY_UP;
+
+       /* XXX ugly workaround: we can't force the switch
+        * to gracefully handle hosts moving from one port to another,
+        * so we have to regularly clear the ATU database */
+
+       /* wait for the ATU to become available */
+       mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
+       /* flush the ATU */
+       w16(pdev, MV_SWITCHREG(ATU_OP),
+               MV_ATUOP_INPROGRESS |
+               MV_ATUOP_FLUSH_ALL
+       );
+
+       /* wait for operation to complete */
+       mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
        return 0;
 }
 
index a172e372652e95e072b8af7bc1ebacbd07ff10fc..1563eec4d5800ab940d9e96cd4d368d5486c5e44 100644 (file)
@@ -123,7 +123,21 @@ enum {
        MV_ATUCTL_ATUMASK   = (3 << 12),
        MV_ATUCTL_NO_LEARN  = (1 << 14),
        MV_ATUCTL_RESET     = (1 << 15),
-}
+};
+
+enum {
+#define MV_ATUOP_DBNUM(_n)     ((_n) & 0x0f)
+
+       MV_ATUOP_NOOP       = (0 << 12),
+       MV_ATUOP_FLUSH_ALL  = (1 << 12),
+       MV_ATUOP_FLUSH_U    = (2 << 12),
+       MV_ATUOP_LOAD_DB    = (3 << 12),
+       MV_ATUOP_GET_NEXT   = (4 << 12),
+       MV_ATUOP_FLUSH_DB   = (5 << 12),
+       MV_ATUOP_FLUSH_DB_UU= (6 << 12),
+
+       MV_ATUOP_INPROGRESS = (1 << 15),
+};
 
 #define MV_IDENT_MASK          0xfff0
 #define MV_IDENT_VALUE         0x0600
index be9e6afd2d14fbff7ecc5ab30bd39c8e0247aa3b..78e5afe9bd4ac3a0f90da2c7b6a935e113b01d40 100644 (file)
@@ -78,8 +78,8 @@ mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
        if (__vlan_hwaccel_get_tag(skb, &vid))
                goto error;
 
-       if ((skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
-               if (pskb_expand_head(skb, MV_HEADER_SIZE, 0, GFP_ATOMIC))
+       if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
+               if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC))
                        goto error_expand;
                if (skb->len < 62)
                        skb->len = 62;
@@ -216,6 +216,20 @@ mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 }
 
 
+static int
+mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val)
+{
+       int i = 100;
+       u16 r;
+
+       do {
+               r = r16(pdev, addr, reg) & mask;
+               if (r == val)
+                       return 0;
+       } while(--i > 0);
+       return -ETIMEDOUT;
+}
+
 static int
 mvswitch_config_init(struct phy_device *pdev)
 {
@@ -231,6 +245,7 @@ mvswitch_config_init(struct phy_device *pdev)
        pdev->supported = ADVERTISED_100baseT_Full;
        pdev->advertising = ADVERTISED_100baseT_Full;
        dev->phy_ptr = priv;
+       dev->irq = PHY_POLL;
 
        /* initialize default vlans */
        for (i = 0; i < MV_PORTS; i++)
@@ -242,25 +257,22 @@ mvswitch_config_init(struct phy_device *pdev)
 
        msleep(2); /* wait for the status change to settle in */
 
-       /* put the device in reset and set ATU flags */
+       /* put the ATU in reset */
+       w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET);
+
+       i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0);
+       if (i < 0) {
+               printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
+               return i;
+       }
+
+       /* set the ATU flags */
        w16(pdev, MV_SWITCHREG(ATU_CTRL),
-               MV_ATUCTL_RESET |
+               MV_ATUCTL_NO_LEARN |
                MV_ATUCTL_ATU_1K |
                MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */
        );
 
-       i = 100; /* timeout */
-       do {
-               if (!(r16(pdev, MV_SWITCHREG(ATU_CTRL)) & MV_ATUCTL_RESET))
-                       break;
-               msleep(1);
-       } while (--i > 0);
-
-       if (!i) {
-               printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
-               return -ETIMEDOUT;
-       }
-
        /* initialize the cpu port */
        w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
 #ifdef HEADER_MODE
@@ -288,7 +300,7 @@ mvswitch_config_init(struct phy_device *pdev)
                }
                /* leave port unconfigured if it's not part of a vlan */
                if (!vlmap)
-                       break;
+                       continue;
 
                /* add the cpu port to the allowed destinations list */
                vlmap |= (1 << MV_CPUPORT);
@@ -299,19 +311,17 @@ mvswitch_config_init(struct phy_device *pdev)
                /* apply vlan settings */
                w16(pdev, MV_PORTREG(VLANMAP, i),
                        MV_PORTVLAN_PORTS(vlmap) |
-                       MV_PORTVLAN_ID(pvid)
+                       MV_PORTVLAN_ID(i)
                );
 
                /* re-enable port */
-               w16(pdev, MV_PORTREG(CONTROL, i), MV_PORTCTRL_ENABLED);
+               w16(pdev, MV_PORTREG(CONTROL, i),
+                       MV_PORTCTRL_ENABLED
+               );
        }
 
-       /* build the target list for the cpu port */
-       for (i = 0; i < MV_PORTS; i++)
-               vlmap |= (1 << i);
-
        w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
-               MV_PORTVLAN_PORTS(vlmap)
+               MV_PORTVLAN_ID(MV_CPUPORT)
        );
 
        /* set the port association vector */
@@ -343,11 +353,28 @@ mvswitch_config_init(struct phy_device *pdev)
 }
 
 static int
-mvswitch_read_status(struct phy_device *phydev)
+mvswitch_read_status(struct phy_device *pdev)
 {
-       phydev->speed = SPEED_100;
-       phydev->duplex = DUPLEX_FULL;
-       phydev->state = PHY_UP;
+       pdev->speed = SPEED_100;
+       pdev->duplex = DUPLEX_FULL;
+       pdev->state = PHY_UP;
+
+       /* XXX ugly workaround: we can't force the switch
+        * to gracefully handle hosts moving from one port to another,
+        * so we have to regularly clear the ATU database */
+
+       /* wait for the ATU to become available */
+       mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
+       /* flush the ATU */
+       w16(pdev, MV_SWITCHREG(ATU_OP),
+               MV_ATUOP_INPROGRESS |
+               MV_ATUOP_FLUSH_ALL
+       );
+
+       /* wait for operation to complete */
+       mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
        return 0;
 }
 
index a172e372652e95e072b8af7bc1ebacbd07ff10fc..1563eec4d5800ab940d9e96cd4d368d5486c5e44 100644 (file)
@@ -123,7 +123,21 @@ enum {
        MV_ATUCTL_ATUMASK   = (3 << 12),
        MV_ATUCTL_NO_LEARN  = (1 << 14),
        MV_ATUCTL_RESET     = (1 << 15),
-}
+};
+
+enum {
+#define MV_ATUOP_DBNUM(_n)     ((_n) & 0x0f)
+
+       MV_ATUOP_NOOP       = (0 << 12),
+       MV_ATUOP_FLUSH_ALL  = (1 << 12),
+       MV_ATUOP_FLUSH_U    = (2 << 12),
+       MV_ATUOP_LOAD_DB    = (3 << 12),
+       MV_ATUOP_GET_NEXT   = (4 << 12),
+       MV_ATUOP_FLUSH_DB   = (5 << 12),
+       MV_ATUOP_FLUSH_DB_UU= (6 << 12),
+
+       MV_ATUOP_INPROGRESS = (1 << 15),
+};
 
 #define MV_IDENT_MASK          0xfff0
 #define MV_IDENT_VALUE         0x0600