aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorshemminger@osdl.org <shemminger@osdl.org>2005-09-27 18:02:57 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-28 11:49:32 -0400
commitd1f1370863f7fa3d76dc7d7779debdda854a5a60 (patch)
tree9b27703564b30b25f9c772ec3afa4fa1fc22b536 /drivers
parentd11c13e752c4e34777d33579ee0378e0178ef52d (diff)
[PATCH] sky2: add hardware VLAN acceleration support
Use the hardware to do VLAN. Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sky2.c101
-rw-r--r--drivers/net/sky2.h6
2 files changed, 93 insertions, 14 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 8527a49e3ff7..6d9c1db8896e 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -26,7 +26,6 @@
26/* 26/*
27 * TODO 27 * TODO
28 * - coalescing setting? 28 * - coalescing setting?
29 * - vlan support
30 * 29 *
31 * TOTEST 30 * TOTEST
32 * - variable ring size 31 * - variable ring size
@@ -48,9 +47,14 @@
48#include <linux/tcp.h> 47#include <linux/tcp.h>
49#include <linux/in.h> 48#include <linux/in.h>
50#include <linux/delay.h> 49#include <linux/delay.h>
50#include <linux/if_vlan.h>
51 51
52#include <asm/irq.h> 52#include <asm/irq.h>
53 53
54#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
55#define SKY2_VLAN_TAG_USED 1
56#endif
57
54#include "sky2.h" 58#include "sky2.h"
55 59
56#define DRV_NAME "sky2" 60#define DRV_NAME "sky2"
@@ -489,7 +493,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
489 /* Configure Rx MAC FIFO */ 493 /* Configure Rx MAC FIFO */
490 sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); 494 sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
491 sky2_write16(hw, SK_REG(port, RX_GMF_CTRL_T), 495 sky2_write16(hw, SK_REG(port, RX_GMF_CTRL_T),
492 GMF_OPER_ON | GMF_RX_F_FL_ON); 496 GMF_RX_CTRL_DEF);
493 497
494 /* Flush Rx MAC FIFO on any flowcontrol or error */ 498 /* Flush Rx MAC FIFO on any flowcontrol or error */
495 reg = GMR_FS_ANY_ERR; 499 reg = GMR_FS_ANY_ERR;
@@ -717,6 +721,41 @@ static void sky2_rx_clean(struct sky2_port *sky2)
717 } 721 }
718} 722}
719 723
724#ifdef SKY2_VLAN_TAG_USED
725static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
726{
727 struct sky2_port *sky2 = netdev_priv(dev);
728 struct sky2_hw *hw = sky2->hw;
729 u16 port = sky2->port;
730 unsigned long flags;
731
732 spin_lock_irqsave(&sky2->tx_lock, flags);
733
734 sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON);
735 sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON);
736 sky2->vlgrp = grp;
737
738 spin_unlock_irqrestore(&sky2->tx_lock, flags);
739}
740
741static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
742{
743 struct sky2_port *sky2 = netdev_priv(dev);
744 struct sky2_hw *hw = sky2->hw;
745 u16 port = sky2->port;
746 unsigned long flags;
747
748 spin_lock_irqsave(&sky2->tx_lock, flags);
749
750 sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF);
751 sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF);
752 if (sky2->vlgrp)
753 sky2->vlgrp->vlan_devices[vid] = NULL;
754
755 spin_unlock_irqrestore(&sky2->tx_lock, flags);
756}
757#endif
758
720#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 759#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
721static inline unsigned rx_size(const struct sky2_port *sky2) 760static inline unsigned rx_size(const struct sky2_port *sky2)
722{ 761{
@@ -894,7 +933,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
894{ 933{
895 struct sky2_port *sky2 = netdev_priv(dev); 934 struct sky2_port *sky2 = netdev_priv(dev);
896 struct sky2_hw *hw = sky2->hw; 935 struct sky2_hw *hw = sky2->hw;
897 struct sky2_tx_le *le; 936 struct sky2_tx_le *le = NULL;
898 struct ring_info *re; 937 struct ring_info *re;
899 unsigned long flags; 938 unsigned long flags;
900 unsigned i, len; 939 unsigned i, len;
@@ -961,8 +1000,23 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
961 sky2->tx_last_mss = mss; 1000 sky2->tx_last_mss = mss;
962 } 1001 }
963 1002
964 /* Handle TCP checksum offload */
965 ctrl = 0; 1003 ctrl = 0;
1004#ifdef SKY2_VLAN_TAG_USED
1005 /* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
1006 if (sky2->vlgrp && vlan_tx_tag_present(skb)) {
1007 if (!le) {
1008 le = get_tx_le(sky2);
1009 le->tx.addr = 0;
1010 le->opcode = OP_VLAN|HW_OWNER;
1011 le->ctrl = 0;
1012 } else
1013 le->opcode |= OP_VLAN;
1014 le->length = cpu_to_be16(vlan_tx_tag_get(skb));
1015 ctrl |= INS_VLAN;
1016 }
1017#endif
1018
1019 /* Handle TCP checksum offload */
966 if (skb->ip_summed == CHECKSUM_HW) { 1020 if (skb->ip_summed == CHECKSUM_HW) {
967 u16 hdr = skb->h.raw - skb->data; 1021 u16 hdr = skb->h.raw - skb->data;
968 u16 offset = hdr + skb->csum; 1022 u16 offset = hdr + skb->csum;
@@ -1436,10 +1490,7 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
1436 1490
1437 sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; 1491 sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
1438 1492
1439 if (!(status & GMR_FS_RX_OK) 1493 if (!(status & GMR_FS_RX_OK) || (status & GMR_FS_ANY_ERR))
1440 || (status & GMR_FS_ANY_ERR)
1441 || (length << 16) != (status & GMR_FS_LEN)
1442 || length > bufsize)
1443 goto error; 1494 goto error;
1444 1495
1445 if (length < RX_COPY_THRESHOLD) { 1496 if (length < RX_COPY_THRESHOLD) {
@@ -1539,6 +1590,9 @@ static int sky2_poll(struct net_device *dev0, int *budget)
1539 u16 length; 1590 u16 length;
1540 1591
1541 BUG_ON(le->link >= hw->ports); 1592 BUG_ON(le->link >= hw->ports);
1593 if (!hw->dev[le->link])
1594 goto skip;
1595
1542 sky2 = netdev_priv(hw->dev[le->link]); 1596 sky2 = netdev_priv(hw->dev[le->link]);
1543 status = le32_to_cpu(le->status); 1597 status = le32_to_cpu(le->status);
1544 length = le16_to_cpu(le->length); 1598 length = le16_to_cpu(le->length);
@@ -1546,12 +1600,27 @@ static int sky2_poll(struct net_device *dev0, int *budget)
1546 switch (le->opcode & ~HW_OWNER) { 1600 switch (le->opcode & ~HW_OWNER) {
1547 case OP_RXSTAT: 1601 case OP_RXSTAT:
1548 skb = sky2_receive(sky2, length, status); 1602 skb = sky2_receive(sky2, length, status);
1549 if (likely(skb)) { 1603 if (!skb)
1604 break;
1605#ifdef SKY2_VLAN_TAG_USED
1606 if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
1607 vlan_hwaccel_receive_skb(skb,
1608 sky2->vlgrp,
1609 be16_to_cpu(sky2->rx_tag));
1610 } else
1611#endif
1550 netif_receive_skb(skb); 1612 netif_receive_skb(skb);
1551 ++work_done;
1552 }
1553 break; 1613 break;
1554 1614
1615#ifdef SKY2_VLAN_TAG_USED
1616 case OP_RXVLAN:
1617 sky2->rx_tag = length;
1618 break;
1619
1620 case OP_RXCHKSVLAN:
1621 sky2->rx_tag = length;
1622 /* fall through */
1623#endif
1555 case OP_RXCHKS: 1624 case OP_RXCHKS:
1556 skb = sky2->rx_ring[sky2->rx_next].skb; 1625 skb = sky2->rx_ring[sky2->rx_next].skb;
1557 skb->ip_summed = CHECKSUM_HW; 1626 skb->ip_summed = CHECKSUM_HW;
@@ -1563,9 +1632,6 @@ static int sky2_poll(struct net_device *dev0, int *budget)
1563 tx_index(sky2->port, status, length)); 1632 tx_index(sky2->port, status, length));
1564 break; 1633 break;
1565 1634
1566 case OP_RXTIMESTAMP:
1567 break;
1568
1569 default: 1635 default:
1570 if (net_ratelimit()) 1636 if (net_ratelimit())
1571 printk(KERN_WARNING PFX 1637 printk(KERN_WARNING PFX
@@ -1574,6 +1640,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
1574 break; 1640 break;
1575 } 1641 }
1576 1642
1643 skip:
1577 hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; 1644 hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE;
1578 if (hw->st_idx == hwidx) { 1645 if (hw->st_idx == hwidx) {
1579 hwidx = sky2_read16(hw, STAT_PUT_IDX); 1646 hwidx = sky2_read16(hw, STAT_PUT_IDX);
@@ -2615,6 +2682,12 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
2615 dev->features |= NETIF_F_HIGHDMA; 2682 dev->features |= NETIF_F_HIGHDMA;
2616 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; 2683 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
2617 2684
2685#ifdef SKY2_VLAN_TAG_USED
2686 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
2687 dev->vlan_rx_register = sky2_vlan_rx_register;
2688 dev->vlan_rx_kill_vid = sky2_vlan_rx_kill_vid;
2689#endif
2690
2618 /* read the mac address */ 2691 /* read the mac address */
2619 memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN); 2692 memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
2620 2693
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 1a8a004e1060..ac91d91f130b 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1578,6 +1578,8 @@ enum {
1578 GMF_RST_SET = 1<<0, /* Set GMAC FIFO Reset */ 1578 GMF_RST_SET = 1<<0, /* Set GMAC FIFO Reset */
1579 1579
1580 RX_GMF_FL_THR_DEF = 0xa, /* flush threshold (default) */ 1580 RX_GMF_FL_THR_DEF = 0xa, /* flush threshold (default) */
1581
1582 GMF_RX_CTRL_DEF = GMF_OPER_ON | GMF_RX_F_FL_ON,
1581}; 1583};
1582 1584
1583 1585
@@ -1826,6 +1828,10 @@ struct sky2_port {
1826 u16 rx_put; /* next le index to use */ 1828 u16 rx_put; /* next le index to use */
1827 u16 rx_pending; 1829 u16 rx_pending;
1828 u16 rx_last_put; 1830 u16 rx_last_put;
1831#ifdef SKY2_VLAN_TAG_USED
1832 u16 rx_tag;
1833 struct vlan_group *vlgrp;
1834#endif
1829 1835
1830 dma_addr_t rx_le_map; 1836 dma_addr_t rx_le_map;
1831 dma_addr_t tx_le_map; 1837 dma_addr_t tx_le_map;