summaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.6/files
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-04-29 12:55:44 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-04-29 12:55:44 +0000
commitb84c7cd55bbb93415024fdc07543149d11874221 (patch)
tree4aa16292d4923739e4d17a4c4dd292dc92ec8571 /target/linux/generic-2.6/files
parent544232b227971ead225e37e1e42ac2a2eeef2d7a (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')
-rw-r--r--target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c81
-rw-r--r--target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h27
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),