From b84c7cd55bbb93415024fdc07543149d11874221 Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Tue, 29 Apr 2008 12:55:44 +0000
Subject: 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
---
 .../200-ar2313_enable_mvswitch.patch               | 31 ++++++---
 .../generic-2.6/files/drivers/net/phy/mvswitch.c   | 81 ++++++++++++++++------
 .../generic-2.6/files/drivers/net/phy/mvswitch.h   | 27 +++++++-
 .../patches-2.6.23/630-phy_packets.patch           | 37 +++++++---
 4 files changed, 133 insertions(+), 43 deletions(-)

diff --git a/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch b/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch
index b209aee0c..09c17977d 100644
--- a/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch
+++ b/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch
@@ -1,32 +1,41 @@
 Index: linux-2.6.23.16/drivers/net/ar2313/ar2313.c
 ===================================================================
---- linux-2.6.23.16.orig/drivers/net/ar2313/ar2313.c	2008-04-20 10:26:15.000000000 +0200
-+++ linux-2.6.23.16/drivers/net/ar2313/ar2313.c	2008-04-20 10:26:16.000000000 +0200
-@@ -955,7 +955,7 @@
+--- linux-2.6.23.16.orig/drivers/net/ar2313/ar2313.c	2008-04-29 14:51:39.000000000 +0200
++++ linux-2.6.23.16/drivers/net/ar2313/ar2313.c	2008-04-29 14:52:14.000000000 +0200
+@@ -219,7 +219,7 @@
+ 	dev->do_ioctl = &ar2313_ioctl;
+ 
+ 	// SAMEER: do we need this?
+-	dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA;
++	dev->features |= NETIF_F_HIGHDMA | NETIF_F_HW_CSUM;
+ 
+ 	tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev);
+ 	tasklet_disable(&sp->rx_tasklet);
+@@ -953,9 +953,9 @@
+ 						((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN);
+ 
  				dev->stats.rx_bytes += skb->len;
- 				skb->protocol = eth_type_trans(skb, dev);
+-				skb->protocol = eth_type_trans(skb, dev);
++
  				/* pass the packet to upper layers */
 -				netif_rx(skb);
 +				sp->rx(skb);
  
  				skb_new->dev = dev;
  				/* 16 bit align */
-@@ -1370,6 +1370,11 @@
+@@ -1370,6 +1370,8 @@
  		return PTR_ERR(phydev);
  	}
  
-+	if (phydev->netif_rx)
-+		sp->rx = phydev->netif_rx;
-+	else
-+		sp->rx = netif_rx;
++	sp->rx = phydev->netif_rx;
 +
  	/* mask with MAC supported features */
  	phydev->supported &= (SUPPORTED_10baseT_Half
  		| SUPPORTED_10baseT_Full
 Index: linux-2.6.23.16/drivers/net/ar2313/ar2313.h
 ===================================================================
---- linux-2.6.23.16.orig/drivers/net/ar2313/ar2313.h	2008-04-20 10:26:15.000000000 +0200
-+++ linux-2.6.23.16/drivers/net/ar2313/ar2313.h	2008-04-20 10:26:16.000000000 +0200
+--- linux-2.6.23.16.orig/drivers/net/ar2313/ar2313.h	2008-04-29 14:51:39.000000000 +0200
++++ linux-2.6.23.16/drivers/net/ar2313/ar2313.h	2008-04-29 14:52:15.000000000 +0200
 @@ -107,6 +107,8 @@
   */
  struct ar2313_private {
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 */
 };
@@ -88,6 +102,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),
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 5d7f97195..930139b55 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,
-- 
cgit v1.2.3