Commit cdb5bf02 authored by Sreenivasa Honnur's avatar Sreenivasa Honnur Committed by Jeff Garzik

S2io: Support for vlan_rx_kill_vid entry point

- Resubmit #3
- Added s2io_vlan_rx_kill_vid entry point function for unregistering vlan.
- Fix to aggregate vlan packets. IP offset is incremented by
  4 bytes if the packet contains vlan header.
Signed-off-by: default avatarSurjit Reang <surjit.reang@neterion.com>
Signed-off-by: default avatarRamkrishna Vepa <ram.vepa@neterion.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 6cfc482b
...@@ -388,6 +388,26 @@ static void s2io_vlan_rx_register(struct net_device *dev, ...@@ -388,6 +388,26 @@ static void s2io_vlan_rx_register(struct net_device *dev,
/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
static int vlan_strip_flag; static int vlan_strip_flag;
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
{
int i;
struct s2io_nic *nic = dev->priv;
unsigned long flags[MAX_TX_FIFOS];
struct mac_info *mac_control = &nic->mac_control;
struct config_param *config = &nic->config;
for (i = 0; i < config->tx_fifo_num; i++)
spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]);
if (nic->vlgrp)
vlan_group_set_device(nic->vlgrp, vid, NULL);
for (i = config->tx_fifo_num - 1; i >= 0; i--)
spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock,
flags[i]);
}
/* /*
* Constants to be programmed into the Xena's registers, to configure * Constants to be programmed into the Xena's registers, to configure
* the XAUI. * the XAUI.
...@@ -3047,7 +3067,7 @@ static void rx_intr_handler(struct ring_info *ring_data) ...@@ -3047,7 +3067,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
struct lro *lro = &nic->lro0_n[i]; struct lro *lro = &nic->lro0_n[i];
if (lro->in_use) { if (lro->in_use) {
update_L3L4_header(nic, lro); update_L3L4_header(nic, lro);
queue_rx_frame(lro->parent); queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro); clear_lro_session(lro);
} }
} }
...@@ -7522,7 +7542,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) ...@@ -7522,7 +7542,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{ {
lro_append_pkt(sp, lro, lro_append_pkt(sp, lro,
skb, tcp_len); skb, tcp_len);
queue_rx_frame(lro->parent); queue_rx_frame(lro->parent,
lro->vlan_tag);
clear_lro_session(lro); clear_lro_session(lro);
sp->mac_control.stats_info-> sp->mac_control.stats_info->
sw_stat.flush_max_pkts++; sw_stat.flush_max_pkts++;
...@@ -7533,7 +7554,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) ...@@ -7533,7 +7554,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
lro->frags_len; lro->frags_len;
sp->mac_control.stats_info-> sp->mac_control.stats_info->
sw_stat.sending_both++; sw_stat.sending_both++;
queue_rx_frame(lro->parent); queue_rx_frame(lro->parent,
lro->vlan_tag);
clear_lro_session(lro); clear_lro_session(lro);
goto send_up; goto send_up;
case 0: /* sessions exceeded */ case 0: /* sessions exceeded */
...@@ -7559,31 +7581,12 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) ...@@ -7559,31 +7581,12 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
*/ */
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
} }
} else { } else
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
}
sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
if (!sp->lro) {
skb->protocol = eth_type_trans(skb, dev);
if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
vlan_strip_flag)) {
/* Queueing the vlan frame to the upper layer */
if (napi)
vlan_hwaccel_receive_skb(skb, sp->vlgrp,
RXD_GET_VLAN_TAG(rxdp->Control_2));
else
vlan_hwaccel_rx(skb, sp->vlgrp,
RXD_GET_VLAN_TAG(rxdp->Control_2));
} else {
if (napi)
netif_receive_skb(skb);
else
netif_rx(skb);
}
} else {
send_up: send_up:
queue_rx_frame(skb); queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
}
dev->last_rx = jiffies; dev->last_rx = jiffies;
aggregate: aggregate:
atomic_dec(&sp->rx_bufs_left[ring_no]); atomic_dec(&sp->rx_bufs_left[ring_no]);
...@@ -8005,6 +8008,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -8005,6 +8008,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->vlan_rx_register = s2io_vlan_rx_register; dev->vlan_rx_register = s2io_vlan_rx_register;
dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
/* /*
* will use eth_mac_addr() for dev->set_mac_address * will use eth_mac_addr() for dev->set_mac_address
...@@ -8306,7 +8310,8 @@ module_init(s2io_starter); ...@@ -8306,7 +8310,8 @@ module_init(s2io_starter);
module_exit(s2io_closer); module_exit(s2io_closer);
static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
struct tcphdr **tcp, struct RxD_t *rxdp) struct tcphdr **tcp, struct RxD_t *rxdp,
struct s2io_nic *sp)
{ {
int ip_off; int ip_off;
u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
...@@ -8317,18 +8322,19 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, ...@@ -8317,18 +8322,19 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
return -1; return -1;
} }
/* TODO: /* Checking for DIX type or DIX type with VLAN */
* By default the VLAN field in the MAC is stripped by the card, if this if ((l2_type == 0)
* feature is turned off in rx_pa_cfg register, then the ip_off field || (l2_type == 4)) {
* has to be shifted by a further 2 bytes
*/
switch (l2_type) {
case 0: /* DIX type */
case 4: /* DIX type with VLAN */
ip_off = HEADER_ETHERNET_II_802_3_SIZE; ip_off = HEADER_ETHERNET_II_802_3_SIZE;
break; /*
* If vlan stripping is disabled and the frame is VLAN tagged,
* shift the offset by the VLAN header size bytes.
*/
if ((!vlan_strip_flag) &&
(rxdp->Control_1 & RXD_FRAME_VLAN_TAG))
ip_off += HEADER_VLAN_SIZE;
} else {
/* LLC, SNAP etc are considered non-mergeable */ /* LLC, SNAP etc are considered non-mergeable */
default:
return -1; return -1;
} }
...@@ -8356,7 +8362,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) ...@@ -8356,7 +8362,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
} }
static void initiate_new_session(struct lro *lro, u8 *l2h, static void initiate_new_session(struct lro *lro, u8 *l2h,
struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len, u16 vlan_tag)
{ {
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
lro->l2h = l2h; lro->l2h = l2h;
...@@ -8367,6 +8373,7 @@ static void initiate_new_session(struct lro *lro, u8 *l2h, ...@@ -8367,6 +8373,7 @@ static void initiate_new_session(struct lro *lro, u8 *l2h,
lro->sg_num = 1; lro->sg_num = 1;
lro->total_len = ntohs(ip->tot_len); lro->total_len = ntohs(ip->tot_len);
lro->frags_len = 0; lro->frags_len = 0;
lro->vlan_tag = vlan_tag;
/* /*
* check if we saw TCP timestamp. Other consistency checks have * check if we saw TCP timestamp. Other consistency checks have
* already been done. * already been done.
...@@ -8498,15 +8505,16 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, ...@@ -8498,15 +8505,16 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
struct iphdr *ip; struct iphdr *ip;
struct tcphdr *tcph; struct tcphdr *tcph;
int ret = 0, i; int ret = 0, i;
u16 vlan_tag = 0;
if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
rxdp))) { rxdp, sp))) {
DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n", DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
ip->saddr, ip->daddr); ip->saddr, ip->daddr);
} else { } else
return ret; return ret;
}
vlan_tag = RXD_GET_VLAN_TAG(rxdp->Control_2);
tcph = (struct tcphdr *)*tcp; tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph); *tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) { for (i=0; i<MAX_LRO_SESSIONS; i++) {
...@@ -8566,7 +8574,8 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, ...@@ -8566,7 +8574,8 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
switch (ret) { switch (ret) {
case 3: case 3:
initiate_new_session(*lro, buffer, ip, tcph, *tcp_len); initiate_new_session(*lro, buffer, ip, tcph, *tcp_len,
vlan_tag);
break; break;
case 2: case 2:
update_L3L4_header(sp, *lro); update_L3L4_header(sp, *lro);
...@@ -8594,15 +8603,25 @@ static void clear_lro_session(struct lro *lro) ...@@ -8594,15 +8603,25 @@ static void clear_lro_session(struct lro *lro)
memset(lro, 0, lro_struct_size); memset(lro, 0, lro_struct_size);
} }
static void queue_rx_frame(struct sk_buff *skb) static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag)
{ {
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct s2io_nic *sp = dev->priv;
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
if (napi) if (sp->vlgrp && vlan_tag
&& (vlan_strip_flag)) {
/* Queueing the vlan frame to the upper layer */
if (sp->config.napi)
vlan_hwaccel_receive_skb(skb, sp->vlgrp, vlan_tag);
else
vlan_hwaccel_rx(skb, sp->vlgrp, vlan_tag);
} else {
if (sp->config.napi)
netif_receive_skb(skb); netif_receive_skb(skb);
else else
netif_rx(skb); netif_rx(skb);
}
} }
static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
......
...@@ -546,6 +546,7 @@ struct RxD_t { ...@@ -546,6 +546,7 @@ struct RxD_t {
#define RXD_OWN_XENA s2BIT(7) #define RXD_OWN_XENA s2BIT(7)
#define RXD_T_CODE (s2BIT(12)|s2BIT(13)|s2BIT(14)|s2BIT(15)) #define RXD_T_CODE (s2BIT(12)|s2BIT(13)|s2BIT(14)|s2BIT(15))
#define RXD_FRAME_PROTO vBIT(0xFFFF,24,8) #define RXD_FRAME_PROTO vBIT(0xFFFF,24,8)
#define RXD_FRAME_VLAN_TAG s2BIT(24)
#define RXD_FRAME_PROTO_IPV4 s2BIT(27) #define RXD_FRAME_PROTO_IPV4 s2BIT(27)
#define RXD_FRAME_PROTO_IPV6 s2BIT(28) #define RXD_FRAME_PROTO_IPV6 s2BIT(28)
#define RXD_FRAME_IP_FRAG s2BIT(29) #define RXD_FRAME_IP_FRAG s2BIT(29)
...@@ -829,10 +830,11 @@ struct lro { ...@@ -829,10 +830,11 @@ struct lro {
int sg_num; int sg_num;
int in_use; int in_use;
__be16 window; __be16 window;
u16 vlan_tag;
u32 cur_tsval; u32 cur_tsval;
__be32 cur_tsecr; __be32 cur_tsecr;
u8 saw_ts; u8 saw_ts;
}; } ____cacheline_aligned;
/* These flags represent the devices temporary state */ /* These flags represent the devices temporary state */
enum s2io_device_state_t enum s2io_device_state_t
...@@ -1129,7 +1131,7 @@ static int ...@@ -1129,7 +1131,7 @@ static int
s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
struct RxD_t *rxdp, struct s2io_nic *sp); struct RxD_t *rxdp, struct s2io_nic *sp);
static void clear_lro_session(struct lro *lro); static void clear_lro_session(struct lro *lro);
static void queue_rx_frame(struct sk_buff *skb); static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag);
static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro); static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
struct sk_buff *skb, u32 tcp_len); struct sk_buff *skb, u32 tcp_len);
......
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