diff options
author | Ayaz Abdulla <aabdulla@nvidia.com> | 2006-02-04 13:13:17 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-02-20 05:59:18 -0500 |
commit | ee407b02f3f1992bc746876c26f8175c8783562b (patch) | |
tree | a005421bd26f8ca0178d4e9a3a7a79486a45f9de /drivers | |
parent | bd71c2b17468a2531fb4c81ec1d73520845e97e1 (diff) |
[PATCH] forcedeth: Add vlan support
This forcedeth patch adds support for vlan stripping/inserting in hardware.
Signed-off-By: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/forcedeth.c | 76 |
1 files changed, 71 insertions, 5 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3682ec61e8a8..0fbe342c2ac9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -102,6 +102,7 @@ | |||
102 | * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. | 102 | * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. |
103 | * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single | 103 | * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single |
104 | * 0.49: 10 Dec 2005: Fix tso for large buffers. | 104 | * 0.49: 10 Dec 2005: Fix tso for large buffers. |
105 | * 0.50: 20 Jan 2006: Add 8021pq tagging support. | ||
105 | * | 106 | * |
106 | * Known bugs: | 107 | * Known bugs: |
107 | * We suspect that on some hardware no TX done interrupts are generated. | 108 | * We suspect that on some hardware no TX done interrupts are generated. |
@@ -113,7 +114,7 @@ | |||
113 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few | 114 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few |
114 | * superfluous timer interrupts from the nic. | 115 | * superfluous timer interrupts from the nic. |
115 | */ | 116 | */ |
116 | #define FORCEDETH_VERSION "0.49" | 117 | #define FORCEDETH_VERSION "0.50" |
117 | #define DRV_NAME "forcedeth" | 118 | #define DRV_NAME "forcedeth" |
118 | 119 | ||
119 | #include <linux/module.h> | 120 | #include <linux/module.h> |
@@ -153,6 +154,7 @@ | |||
153 | #define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ | 154 | #define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ |
154 | #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ | 155 | #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ |
155 | #define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ | 156 | #define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ |
157 | #define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ | ||
156 | 158 | ||
157 | enum { | 159 | enum { |
158 | NvRegIrqStatus = 0x000, | 160 | NvRegIrqStatus = 0x000, |
@@ -254,6 +256,8 @@ enum { | |||
254 | #define NVREG_TXRXCTL_DESC_1 0 | 256 | #define NVREG_TXRXCTL_DESC_1 0 |
255 | #define NVREG_TXRXCTL_DESC_2 0x02100 | 257 | #define NVREG_TXRXCTL_DESC_2 0x02100 |
256 | #define NVREG_TXRXCTL_DESC_3 0x02200 | 258 | #define NVREG_TXRXCTL_DESC_3 0x02200 |
259 | #define NVREG_TXRXCTL_VLANSTRIP 0x00040 | ||
260 | #define NVREG_TXRXCTL_VLANINS 0x00080 | ||
257 | NvRegMIIStatus = 0x180, | 261 | NvRegMIIStatus = 0x180, |
258 | #define NVREG_MIISTAT_ERROR 0x0001 | 262 | #define NVREG_MIISTAT_ERROR 0x0001 |
259 | #define NVREG_MIISTAT_LINKCHANGE 0x0008 | 263 | #define NVREG_MIISTAT_LINKCHANGE 0x0008 |
@@ -303,6 +307,8 @@ enum { | |||
303 | #define NVREG_POWERSTATE_D1 0x0001 | 307 | #define NVREG_POWERSTATE_D1 0x0001 |
304 | #define NVREG_POWERSTATE_D2 0x0002 | 308 | #define NVREG_POWERSTATE_D2 0x0002 |
305 | #define NVREG_POWERSTATE_D3 0x0003 | 309 | #define NVREG_POWERSTATE_D3 0x0003 |
310 | NvRegVlanControl = 0x300, | ||
311 | #define NVREG_VLANCONTROL_ENABLE 0x2000 | ||
306 | }; | 312 | }; |
307 | 313 | ||
308 | /* Big endian: should work, but is untested */ | 314 | /* Big endian: should work, but is untested */ |
@@ -314,7 +320,7 @@ struct ring_desc { | |||
314 | struct ring_desc_ex { | 320 | struct ring_desc_ex { |
315 | u32 PacketBufferHigh; | 321 | u32 PacketBufferHigh; |
316 | u32 PacketBufferLow; | 322 | u32 PacketBufferLow; |
317 | u32 Reserved; | 323 | u32 TxVlan; |
318 | u32 FlagLen; | 324 | u32 FlagLen; |
319 | }; | 325 | }; |
320 | 326 | ||
@@ -355,6 +361,8 @@ typedef union _ring_type { | |||
355 | #define NV_TX2_CHECKSUM_L3 (1<<27) | 361 | #define NV_TX2_CHECKSUM_L3 (1<<27) |
356 | #define NV_TX2_CHECKSUM_L4 (1<<26) | 362 | #define NV_TX2_CHECKSUM_L4 (1<<26) |
357 | 363 | ||
364 | #define NV_TX3_VLAN_TAG_PRESENT (1<<18) | ||
365 | |||
358 | #define NV_RX_DESCRIPTORVALID (1<<16) | 366 | #define NV_RX_DESCRIPTORVALID (1<<16) |
359 | #define NV_RX_MISSEDFRAME (1<<17) | 367 | #define NV_RX_MISSEDFRAME (1<<17) |
360 | #define NV_RX_SUBSTRACT1 (1<<18) | 368 | #define NV_RX_SUBSTRACT1 (1<<18) |
@@ -385,6 +393,9 @@ typedef union _ring_type { | |||
385 | #define NV_RX2_ERROR (1<<30) | 393 | #define NV_RX2_ERROR (1<<30) |
386 | #define NV_RX2_AVAIL (1<<31) | 394 | #define NV_RX2_AVAIL (1<<31) |
387 | 395 | ||
396 | #define NV_RX3_VLAN_TAG_PRESENT (1<<16) | ||
397 | #define NV_RX3_VLAN_TAG_MASK (0x0000FFFF) | ||
398 | |||
388 | /* Miscelaneous hardware related defines: */ | 399 | /* Miscelaneous hardware related defines: */ |
389 | #define NV_PCI_REGSZ 0x270 | 400 | #define NV_PCI_REGSZ 0x270 |
390 | 401 | ||
@@ -511,6 +522,7 @@ struct fe_priv { | |||
511 | u32 irqmask; | 522 | u32 irqmask; |
512 | u32 desc_ver; | 523 | u32 desc_ver; |
513 | u32 txrxctl_bits; | 524 | u32 txrxctl_bits; |
525 | u32 vlanctl_bits; | ||
514 | 526 | ||
515 | void __iomem *base; | 527 | void __iomem *base; |
516 | 528 | ||
@@ -540,6 +552,9 @@ struct fe_priv { | |||
540 | dma_addr_t tx_dma[TX_RING]; | 552 | dma_addr_t tx_dma[TX_RING]; |
541 | unsigned int tx_dma_len[TX_RING]; | 553 | unsigned int tx_dma_len[TX_RING]; |
542 | u32 tx_flags; | 554 | u32 tx_flags; |
555 | |||
556 | /* vlan fields */ | ||
557 | struct vlan_group *vlangrp; | ||
543 | }; | 558 | }; |
544 | 559 | ||
545 | /* | 560 | /* |
@@ -1031,6 +1046,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1031 | u32 bcnt; | 1046 | u32 bcnt; |
1032 | u32 size = skb->len-skb->data_len; | 1047 | u32 size = skb->len-skb->data_len; |
1033 | u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); | 1048 | u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); |
1049 | u32 tx_flags_vlan = 0; | ||
1034 | 1050 | ||
1035 | /* add fragments to entries count */ | 1051 | /* add fragments to entries count */ |
1036 | for (i = 0; i < fragments; i++) { | 1052 | for (i = 0; i < fragments; i++) { |
@@ -1111,10 +1127,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1111 | #endif | 1127 | #endif |
1112 | tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); | 1128 | tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); |
1113 | 1129 | ||
1130 | /* vlan tag */ | ||
1131 | if (np->vlangrp && vlan_tx_tag_present(skb)) { | ||
1132 | tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); | ||
1133 | } | ||
1134 | |||
1114 | /* set tx flags */ | 1135 | /* set tx flags */ |
1115 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { | 1136 | if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { |
1116 | np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); | 1137 | np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); |
1117 | } else { | 1138 | } else { |
1139 | np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan); | ||
1118 | np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); | 1140 | np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); |
1119 | } | 1141 | } |
1120 | 1142 | ||
@@ -1342,6 +1364,8 @@ static void nv_rx_process(struct net_device *dev) | |||
1342 | { | 1364 | { |
1343 | struct fe_priv *np = netdev_priv(dev); | 1365 | struct fe_priv *np = netdev_priv(dev); |
1344 | u32 Flags; | 1366 | u32 Flags; |
1367 | u32 vlanflags = 0; | ||
1368 | |||
1345 | 1369 | ||
1346 | for (;;) { | 1370 | for (;;) { |
1347 | struct sk_buff *skb; | 1371 | struct sk_buff *skb; |
@@ -1357,6 +1381,7 @@ static void nv_rx_process(struct net_device *dev) | |||
1357 | } else { | 1381 | } else { |
1358 | Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); | 1382 | Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); |
1359 | len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); | 1383 | len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); |
1384 | vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow); | ||
1360 | } | 1385 | } |
1361 | 1386 | ||
1362 | dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", | 1387 | dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", |
@@ -1474,7 +1499,11 @@ static void nv_rx_process(struct net_device *dev) | |||
1474 | skb->protocol = eth_type_trans(skb, dev); | 1499 | skb->protocol = eth_type_trans(skb, dev); |
1475 | dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", | 1500 | dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", |
1476 | dev->name, np->cur_rx, len, skb->protocol); | 1501 | dev->name, np->cur_rx, len, skb->protocol); |
1477 | netif_rx(skb); | 1502 | if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) { |
1503 | vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK); | ||
1504 | } else { | ||
1505 | netif_rx(skb); | ||
1506 | } | ||
1478 | dev->last_rx = jiffies; | 1507 | dev->last_rx = jiffies; |
1479 | np->stats.rx_packets++; | 1508 | np->stats.rx_packets++; |
1480 | np->stats.rx_bytes += len; | 1509 | np->stats.rx_bytes += len; |
@@ -2217,6 +2246,34 @@ static struct ethtool_ops ops = { | |||
2217 | .get_perm_addr = ethtool_op_get_perm_addr, | 2246 | .get_perm_addr = ethtool_op_get_perm_addr, |
2218 | }; | 2247 | }; |
2219 | 2248 | ||
2249 | static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) | ||
2250 | { | ||
2251 | struct fe_priv *np = get_nvpriv(dev); | ||
2252 | |||
2253 | spin_lock_irq(&np->lock); | ||
2254 | |||
2255 | /* save vlan group */ | ||
2256 | np->vlangrp = grp; | ||
2257 | |||
2258 | if (grp) { | ||
2259 | /* enable vlan on MAC */ | ||
2260 | np->txrxctl_bits |= NVREG_TXRXCTL_VLANSTRIP | NVREG_TXRXCTL_VLANINS; | ||
2261 | } else { | ||
2262 | /* disable vlan on MAC */ | ||
2263 | np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANSTRIP; | ||
2264 | np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANINS; | ||
2265 | } | ||
2266 | |||
2267 | writel(np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); | ||
2268 | |||
2269 | spin_unlock_irq(&np->lock); | ||
2270 | }; | ||
2271 | |||
2272 | static void nv_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) | ||
2273 | { | ||
2274 | /* nothing to do */ | ||
2275 | }; | ||
2276 | |||
2220 | static int nv_open(struct net_device *dev) | 2277 | static int nv_open(struct net_device *dev) |
2221 | { | 2278 | { |
2222 | struct fe_priv *np = netdev_priv(dev); | 2279 | struct fe_priv *np = netdev_priv(dev); |
@@ -2265,6 +2322,7 @@ static int nv_open(struct net_device *dev) | |||
2265 | writel(np->linkspeed, base + NvRegLinkSpeed); | 2322 | writel(np->linkspeed, base + NvRegLinkSpeed); |
2266 | writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); | 2323 | writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); |
2267 | writel(np->txrxctl_bits, base + NvRegTxRxControl); | 2324 | writel(np->txrxctl_bits, base + NvRegTxRxControl); |
2325 | writel(np->vlanctl_bits, base + NvRegVlanControl); | ||
2268 | pci_push(base); | 2326 | pci_push(base); |
2269 | writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); | 2327 | writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); |
2270 | reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, | 2328 | reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, |
@@ -2496,6 +2554,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2496 | #endif | 2554 | #endif |
2497 | } | 2555 | } |
2498 | 2556 | ||
2557 | np->vlanctl_bits = 0; | ||
2558 | if (id->driver_data & DEV_HAS_VLAN) { | ||
2559 | np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE; | ||
2560 | dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; | ||
2561 | dev->vlan_rx_register = nv_vlan_rx_register; | ||
2562 | dev->vlan_rx_kill_vid = nv_vlan_rx_kill_vid; | ||
2563 | } | ||
2564 | |||
2499 | err = -ENOMEM; | 2565 | err = -ENOMEM; |
2500 | np->base = ioremap(addr, NV_PCI_REGSZ); | 2566 | np->base = ioremap(addr, NV_PCI_REGSZ); |
2501 | if (!np->base) | 2567 | if (!np->base) |
@@ -2737,11 +2803,11 @@ static struct pci_device_id pci_tbl[] = { | |||
2737 | }, | 2803 | }, |
2738 | { /* MCP55 Ethernet Controller */ | 2804 | { /* MCP55 Ethernet Controller */ |
2739 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), | 2805 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), |
2740 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, | 2806 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, |
2741 | }, | 2807 | }, |
2742 | { /* MCP55 Ethernet Controller */ | 2808 | { /* MCP55 Ethernet Controller */ |
2743 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), | 2809 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), |
2744 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, | 2810 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, |
2745 | }, | 2811 | }, |
2746 | {0,}, | 2812 | {0,}, |
2747 | }; | 2813 | }; |