diff options
author | Felix Fietkau <nbd@openwrt.org> | 2008-04-29 12:55:44 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2008-04-29 12:55:44 +0000 |
commit | 653cf2c07823504a601aacf9fe310c3766995880 (patch) | |
tree | 4aa16292d4923739e4d17a4c4dd292dc92ec8571 /target/linux/generic-2.6 | |
parent | 8f54e06573d9d3693ca9bf5efebfe42c5362d02b (diff) | |
download | master-187ad058-653cf2c07823504a601aacf9fe310c3766995880.tar.gz master-187ad058-653cf2c07823504a601aacf9fe310c3766995880.tar.bz2 master-187ad058-653cf2c07823504a601aacf9fe310c3766995880.zip |
enable a different pseudo-vlan mode in the marvell switch (uses a proprietary header instead of a proprietary trailer) - fixes some mtu issues
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10975 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic-2.6')
3 files changed, 113 insertions, 32 deletions
diff --git a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c index cb0d377d27..f28df43989 100644 --- a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c +++ b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c @@ -30,6 +30,10 @@ #include <asm/uaccess.h> #include "mvswitch.h" +/* Undefine this to use trailer mode instead. + * I don't know if header mode works with all chips */ +#define HEADER_MODE 1 + MODULE_DESCRIPTION("Marvell 88E6060 Switch driver"); MODULE_AUTHOR("Felix Fietkau"); MODULE_LICENSE("GPL"); @@ -55,11 +59,11 @@ w16(struct phy_device *phydev, int addr, int reg, u16 val) phydev->bus->write(phydev->bus, addr, reg, val); } + static int mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev) { struct mvswitch_priv *priv; - struct vlan_ethhdr *eh; char *buf = NULL; u16 vid; @@ -70,30 +74,34 @@ mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len < 16)) goto error; - eh = (struct vlan_ethhdr *) skb->data; - if (be16_to_cpu(eh->h_vlan_proto) != 0x8100) +#ifdef HEADER_MODE + 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)) + goto error_expand; + if (skb->len < 62) + skb->len = 62; + } + buf = skb_push(skb, MV_HEADER_SIZE); +#else + if (__vlan_get_tag(skb, &vid)) goto error; - vid = be16_to_cpu(eh->h_vlan_TCI) & VLAN_VID_MASK; if (unlikely((vid > 15 || !priv->vlans[vid]))) goto error; if (skb->len <= 64) { - if (pskb_expand_head(skb, 0, 68 - skb->len, GFP_ATOMIC)) { - if (net_ratelimit()) - printk("%s: failed to expand/update skb for the switch\n", dev->name); - goto error; - } + if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC)) + goto error_expand; buf = skb->data + 64; - skb->len = 68; + skb->len = 64 + MV_TRAILER_SIZE; } else { if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) { - if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) { - if (net_ratelimit()) - printk("%s: failed to expand/update skb for the switch\n", dev->name); - goto error; - } + if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) + goto error_expand; } buf = skb_put(skb, 4); } @@ -103,18 +111,32 @@ mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev) skb->data += 4; skb->len -= 4; skb->mac_header += 4; +#endif if (!buf) goto error; - /* append the tag */ - *((u32 *) buf) = ( - (0x80 << 24) | - ((priv->vlans[vid] & 0x1f) << 16) + +#ifdef HEADER_MODE + /* prepend the tag */ + *((__be16 *) buf) = cpu_to_be16( + ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) | + ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M) ); +#else + /* append the tag */ + *((__be32 *) buf) = cpu_to_be32(( + (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) | + ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S) + )); +#endif return priv->hardstart(skb, dev); +error_expand: + if (net_ratelimit()) + printk("%s: failed to expand/update skb for the switch\n", dev->name); + error: /* any errors? drop the packet! */ dev_kfree_skb_any(skb); @@ -141,9 +163,14 @@ mvswitch_mangle_rx(struct sk_buff *skb, int napi) if (!priv->grp) goto error; - buf = skb->data + skb->len - 4; +#ifdef HEADER_MODE + buf = skb->data; + skb_pull(skb, MV_HEADER_SIZE); +#else + buf = skb->data + skb->len - MV_TRAILER_SIZE; if (buf[0] != 0x80) goto error; +#endif /* look for the vlan matching the incoming port */ for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) { @@ -154,6 +181,8 @@ mvswitch_mangle_rx(struct sk_buff *skb, int napi) if (vlan == -1) goto error; + skb->protocol = eth_type_trans(skb, skb->dev); + if (napi) return vlan_hwaccel_receive_skb(skb, priv->grp, vlan); else @@ -234,9 +263,13 @@ mvswitch_config_init(struct phy_device *pdev) /* initialize the cpu port */ w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT), - MV_PORTCTRL_ENABLED | +#ifdef HEADER_MODE + MV_PORTCTRL_HEADER | +#else MV_PORTCTRL_RXTR | - MV_PORTCTRL_TXTR + MV_PORTCTRL_TXTR | +#endif + MV_PORTCTRL_ENABLED ); /* wait for the phy change to settle in */ msleep(2); @@ -300,7 +333,11 @@ mvswitch_config_init(struct phy_device *pdev) pdev->netif_rx = mvswitch_netif_rx; dev->hard_start_xmit = mvswitch_mangle_tx; dev->vlan_rx_register = mvswitch_vlan_rx_register; +#ifdef HEADER_MODE + dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; +#else dev->features |= NETIF_F_HW_VLAN_RX; +#endif return 0; } diff --git a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h index b51e84a731..81516b708b 100644 --- a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h +++ b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h @@ -9,6 +9,19 @@ #ifndef __MVSWITCH_H #define __MVSWITCH_H +#define MV_HEADER_SIZE 2 +#define MV_HEADER_PORTS_M 0x001f +#define MV_HEADER_PORTS_S 0 +#define MV_HEADER_VLAN_M 0xf000 +#define MV_HEADER_VLAN_S 12 + +#define MV_TRAILER_SIZE 4 +#define MV_TRAILER_PORTS_M 0x1f +#define MV_TRAILER_PORTS_S 16 +#define MV_TRAILER_FLAGS_S 24 +#define MV_TRAILER_OVERRIDE 0x80 + + #define MV_PORTS 5 #define MV_WANPORT 4 #define MV_CPUPORT 5 @@ -36,7 +49,7 @@ enum { MV_PHY_INTR_EN = 0x12, MV_PHY_INTR_STATUS = 0x13, MV_PHY_INTR_PORT = 0x14, - MV_PHY_RECV_COUNTER = 0x15, + MV_PHY_RECV_COUNTER = 0x16, MV_PHY_LED_PARALLEL = 0x16, MV_PHY_LED_STREAM = 0x17, MV_PHY_LED_CTRL = 0x18, @@ -64,6 +77,7 @@ enum { MV_PORTCTRL_ENABLED = (3 << 0), MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */ MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */ + MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */ MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */ MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */ }; @@ -89,6 +103,17 @@ enum { #define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type enum { + MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */ + MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */ + MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */ + MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */ + MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */ + MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */ + MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */ + MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */ +}; + +enum { #define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4) MV_ATUCTL_ATU_256 = (0 << 12), MV_ATUCTL_ATU_512 = (1 << 12), diff --git a/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch b/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch index 5d7f97195f..930139b556 100644 --- a/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch +++ b/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch @@ -1,20 +1,39 @@ Index: linux-2.6.23.16/drivers/net/phy/phy_device.c =================================================================== ---- linux-2.6.23.16.orig/drivers/net/phy/phy_device.c 2008-02-11 07:06:32.000000000 +0100 -+++ linux-2.6.23.16/drivers/net/phy/phy_device.c 2008-04-20 05:42:28.000000000 +0200 -@@ -67,6 +67,8 @@ +--- linux-2.6.23.16.orig/drivers/net/phy/phy_device.c 2008-04-20 10:16:21.000000000 +0200 ++++ linux-2.6.23.16/drivers/net/phy/phy_device.c 2008-04-29 14:20:03.000000000 +0200 +@@ -44,6 +44,18 @@ + extern int mdio_bus_init(void); + extern void mdio_bus_exit(void); + ++static int generic_receive_skb(struct sk_buff *skb) ++{ ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ return netif_receive_skb(skb); ++} ++ ++static int generic_rx(struct sk_buff *skb) ++{ ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ return netif_rx(skb); ++} ++ + struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) + { + struct phy_device *dev; +@@ -67,6 +79,8 @@ dev->bus = bus; dev->state = PHY_DOWN; -+ dev->netif_receive_skb = &netif_receive_skb; -+ dev->netif_rx = &netif_rx; ++ dev->netif_receive_skb = &generic_receive_skb; ++ dev->netif_rx = &generic_rx; spin_lock_init(&dev->lock); Index: linux-2.6.23.16/include/linux/phy.h =================================================================== ---- linux-2.6.23.16.orig/include/linux/phy.h 2008-04-20 04:40:31.000000000 +0200 -+++ linux-2.6.23.16/include/linux/phy.h 2008-04-20 05:53:21.000000000 +0200 +--- linux-2.6.23.16.orig/include/linux/phy.h 2008-04-20 10:16:21.000000000 +0200 ++++ linux-2.6.23.16/include/linux/phy.h 2008-04-20 10:17:58.000000000 +0200 @@ -289,6 +289,17 @@ void (*adjust_link)(struct net_device *dev); @@ -35,8 +54,8 @@ Index: linux-2.6.23.16/include/linux/phy.h Index: linux-2.6.23.16/include/linux/netdevice.h =================================================================== ---- linux-2.6.23.16.orig/include/linux/netdevice.h 2008-02-11 07:06:32.000000000 +0100 -+++ linux-2.6.23.16/include/linux/netdevice.h 2008-04-20 06:33:25.000000000 +0200 +--- linux-2.6.23.16.orig/include/linux/netdevice.h 2008-04-20 10:16:21.000000000 +0200 ++++ linux-2.6.23.16/include/linux/netdevice.h 2008-04-20 10:17:58.000000000 +0200 @@ -426,6 +426,7 @@ void *ax25_ptr; /* AX.25 specific data */ struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data, |