diff options
| author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-04-29 12:55:44 +0000 | 
|---|---|---|
| committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-04-29 12:55:44 +0000 | 
| commit | b84c7cd55bbb93415024fdc07543149d11874221 (patch) | |
| tree | 4aa16292d4923739e4d17a4c4dd292dc92ec8571 /target/linux/generic-2.6/files/drivers/net/phy | |
| parent | 544232b227971ead225e37e1e42ac2a2eeef2d7a (diff) | |
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/files/drivers/net/phy')
| -rw-r--r-- | target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c | 81 | ||||
| -rw-r--r-- | target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h | 27 | 
2 files changed, 85 insertions, 23 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 cb0d377d2..f28df4398 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 b51e84a73..81516b708 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),  | 
