Commit df245a2a authored by Scott Feldman's avatar Scott Feldman Committed by Jeff Garzik

[E100] Add support for VLAN hw offload

On Thu, 20 Mar 2003, Scott Feldman wrote:


* Add support for VLAN hw offload
parent bd974bb3
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/if.h> #include <linux/if.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/if_vlan.h>
#define E100_REGS_LEN 1 #define E100_REGS_LEN 1
/* /*
...@@ -358,7 +359,7 @@ struct driver_stats { ...@@ -358,7 +359,7 @@ struct driver_stats {
#define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */ #define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */
#define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */ #define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */
#define CB_STATUS_OK BIT_13 /* CB OK Bit */ #define CB_STATUS_OK BIT_13 /* CB OK Bit */
#define CB_STATUS_UNDERRUN BIT_12 /* CB A Bit */ #define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */
#define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */ #define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */
/*misc command bits */ /*misc command bits */
...@@ -851,6 +852,7 @@ struct ethtool_lpbk_data{ ...@@ -851,6 +852,7 @@ struct ethtool_lpbk_data{
}; };
struct e100_private { struct e100_private {
struct vlan_group *vlgrp;
u32 flags; /* board management flags */ u32 flags; /* board management flags */
u32 tx_per_underrun; /* number of good tx frames per underrun */ u32 tx_per_underrun; /* number of good tx frames per underrun */
unsigned int tx_count; /* count of tx frames, so we can request an interrupt */ unsigned int tx_count; /* count of tx frames, so we can request an interrupt */
......
...@@ -521,6 +521,25 @@ e100_config_wol(struct e100_private *bdp) ...@@ -521,6 +521,25 @@ e100_config_wol(struct e100_private *bdp)
spin_unlock_bh(&(bdp->config_lock)); spin_unlock_bh(&(bdp->config_lock));
} }
void
e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable)
{
spin_lock_bh(&(bdp->config_lock));
if (enable) {
if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE;
E100_CONFIG(bdp, 22);
}
} else {
if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE;
E100_CONFIG(bdp, 22);
}
}
spin_unlock_bh(&(bdp->config_lock));
}
/** /**
* e100_config_loopback_mode * e100_config_loopback_mode
* @bdp: atapter's private data struct * @bdp: atapter's private data struct
......
...@@ -163,5 +163,5 @@ extern void e100_config_force_dplx(struct e100_private *bdp); ...@@ -163,5 +163,5 @@ extern void e100_config_force_dplx(struct e100_private *bdp);
extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode); extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable); extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable); extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable);
#endif /* _E100_CONFIG_INC_ */ #endif /* _E100_CONFIG_INC_ */
...@@ -146,6 +146,10 @@ char e100_driver_version[]="2.2.21-k1"; ...@@ -146,6 +146,10 @@ char e100_driver_version[]="2.2.21-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100"; char e100_short_driver_name[] = "e100";
static int e100nics = 0; static int e100nics = 0;
static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group
*grp);
static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
...@@ -651,6 +655,9 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) ...@@ -651,6 +655,9 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto err_pci; goto err_pci;
} }
dev->vlan_rx_register = e100_vlan_rx_register;
dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
dev->irq = pcid->irq; dev->irq = pcid->irq;
dev->open = &e100_open; dev->open = &e100_open;
dev->hard_start_xmit = &e100_xmit_frame; dev->hard_start_xmit = &e100_xmit_frame;
...@@ -660,9 +667,11 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) ...@@ -660,9 +667,11 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
dev->set_multicast_list = &e100_set_multi; dev->set_multicast_list = &e100_set_multi;
dev->set_mac_address = &e100_set_mac; dev->set_mac_address = &e100_set_mac;
dev->do_ioctl = &e100_ioctl; dev->do_ioctl = &e100_ioctl;
if (bdp->flags & USE_IPCB) {
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; if (bdp->flags & USE_IPCB)
} dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
e100nics++; e100nics++;
e100_get_speed_duplex_caps(bdp); e100_get_speed_duplex_caps(bdp);
...@@ -1998,17 +2007,15 @@ e100_rx_srv(struct e100_private *bdp) ...@@ -1998,17 +2007,15 @@ e100_rx_srv(struct e100_private *bdp)
} else { } else {
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
} }
switch (netif_rx(skb)) {
case NET_RX_BAD:
case NET_RX_DROP:
case NET_RX_CN_MOD:
case NET_RX_CN_HIGH:
break;
default:
bdp->drv_stats.net_stats.rx_bytes += skb->len;
break;
}
if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
} else {
netif_rx(skb);
}
dev->last_rx = jiffies;
bdp->drv_stats.net_stats.rx_bytes += skb->len;
rfd_cnt++; rfd_cnt++;
} /* end of rfd loop */ } /* end of rfd loop */
...@@ -2101,6 +2108,11 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) ...@@ -2101,6 +2108,11 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
} }
if(bdp->vlgrp && vlan_tx_tag_present(skb)) {
(tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE;
(tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb));
}
tcb->tcb_hdr.cb_status = 0; tcb->tcb_hdr.cb_status = 0;
tcb->tcb_thrshld = bdp->tx_thld; tcb->tcb_thrshld = bdp->tx_thld;
tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
...@@ -4022,6 +4034,45 @@ e100_non_tx_background(unsigned long ptr) ...@@ -4022,6 +4034,45 @@ e100_non_tx_background(unsigned long ptr)
spin_unlock_bh(&(bdp->bd_non_tx_lock)); spin_unlock_bh(&(bdp->bd_non_tx_lock));
} }
static void
e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
struct e100_private *bdp = netdev->priv;
e100_disable_clear_intr(bdp);
bdp->vlgrp = grp;
if(grp) {
/* enable VLAN tag insert/strip */
e100_config_vlan_drop(bdp, true);
} else {
/* disable VLAN tag insert/strip */
e100_config_vlan_drop(bdp, false);
}
e100_config(bdp);
e100_set_intr_mask(bdp);
}
static void
e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
/* We don't do Vlan filtering */
return;
}
static void
e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
{
struct e100_private *bdp = netdev->priv;
if(bdp->vlgrp)
bdp->vlgrp->vlan_devices[vid] = NULL;
/* We don't do Vlan filtering */
return;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int static int
e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment