Commit 6cfc482b authored by Sreenivasa Honnur's avatar Sreenivasa Honnur Committed by Jeff Garzik

S2io: Multiqueue network device support - FIFO selection based on L4 ports

- Resubmit #2
- Transmit fifo selection based on TCP/UDP ports.
- Added tx_steering_type loadable parameter for transmit fifo selection.
  0x0 NO_STEERING: Default FIFO is selected.
  0x1 TX_PRIORITY_STEERING: FIFO is selected based on skb->priority.
  0x2 TX_DEFAULT_STEERING: FIFO is selected based on L4 Ports.
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 3a3d5756
...@@ -458,7 +458,7 @@ MODULE_VERSION(DRV_VERSION); ...@@ -458,7 +458,7 @@ MODULE_VERSION(DRV_VERSION);
/* Module Loadable parameters. */ /* Module Loadable parameters. */
S2IO_PARM_INT(tx_fifo_num, 1); S2IO_PARM_INT(tx_fifo_num, FIFO_DEFAULT_NUM);
S2IO_PARM_INT(rx_ring_num, 1); S2IO_PARM_INT(rx_ring_num, 1);
S2IO_PARM_INT(multiq, 0); S2IO_PARM_INT(multiq, 0);
S2IO_PARM_INT(rx_ring_mode, 1); S2IO_PARM_INT(rx_ring_mode, 1);
...@@ -470,6 +470,8 @@ S2IO_PARM_INT(shared_splits, 0); ...@@ -470,6 +470,8 @@ S2IO_PARM_INT(shared_splits, 0);
S2IO_PARM_INT(tmac_util_period, 5); S2IO_PARM_INT(tmac_util_period, 5);
S2IO_PARM_INT(rmac_util_period, 5); S2IO_PARM_INT(rmac_util_period, 5);
S2IO_PARM_INT(l3l4hdr_size, 128); S2IO_PARM_INT(l3l4hdr_size, 128);
/* 0 is no steering, 1 is Priority steering, 2 is Default steering */
S2IO_PARM_INT(tx_steering_type, TX_DEFAULT_STEERING);
/* Frequency of Rx desc syncs expressed as power of 2 */ /* Frequency of Rx desc syncs expressed as power of 2 */
S2IO_PARM_INT(rxsync_frequency, 3); S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
...@@ -4114,7 +4116,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -4114,7 +4116,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
struct fifo_info *fifo = NULL; struct fifo_info *fifo = NULL;
struct mac_info *mac_control; struct mac_info *mac_control;
struct config_param *config; struct config_param *config;
int do_spin_lock = 1;
int offload_type; int offload_type;
int enable_per_list_interrupt = 0;
struct swStat *stats = &sp->mac_control.stats_info->sw_stat; struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
mac_control = &sp->mac_control; mac_control = &sp->mac_control;
...@@ -4136,15 +4140,52 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -4136,15 +4140,52 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
} }
queue = 0; queue = 0;
/* Get Fifo number to Transmit based on vlan priority */
if (sp->vlgrp && vlan_tx_tag_present(skb)) if (sp->vlgrp && vlan_tx_tag_present(skb))
vlan_tag = vlan_tx_tag_get(skb); vlan_tag = vlan_tx_tag_get(skb);
if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) {
if (skb->protocol == htons(ETH_P_IP)) {
struct iphdr *ip;
struct tcphdr *th;
ip = ip_hdr(skb);
if ((ip->frag_off & htons(IP_OFFSET|IP_MF)) == 0) {
th = (struct tcphdr *)(((unsigned char *)ip) +
ip->ihl*4);
if (ip->protocol == IPPROTO_TCP) {
queue_len = sp->total_tcp_fifos;
queue = (ntohs(th->source) +
ntohs(th->dest)) &
sp->fifo_selector[queue_len - 1];
if (queue >= queue_len)
queue = queue_len - 1;
} else if (ip->protocol == IPPROTO_UDP) {
queue_len = sp->total_udp_fifos;
queue = (ntohs(th->source) +
ntohs(th->dest)) &
sp->fifo_selector[queue_len - 1];
if (queue >= queue_len)
queue = queue_len - 1;
queue += sp->udp_fifo_idx;
if (skb->len > 1024)
enable_per_list_interrupt = 1;
do_spin_lock = 0;
}
}
}
} else if (sp->config.tx_steering_type == TX_PRIORITY_STEERING)
/* get fifo number based on skb->priority value */ /* get fifo number based on skb->priority value */
queue = config->fifo_mapping[skb->priority & (MAX_TX_FIFOS - 1)]; queue = config->fifo_mapping
[skb->priority & (MAX_TX_FIFOS - 1)];
fifo = &mac_control->fifos[queue]; fifo = &mac_control->fifos[queue];
if (do_spin_lock)
spin_lock_irqsave(&fifo->tx_lock, flags); spin_lock_irqsave(&fifo->tx_lock, flags);
else {
if (unlikely(!spin_trylock_irqsave(&fifo->tx_lock, flags)))
return NETDEV_TX_LOCKED;
}
#ifdef CONFIG_NETDEVICES_MULTIQUEUE #ifdef CONFIG_NETDEVICES_MULTIQUEUE
if (sp->config.multiq) { if (sp->config.multiq) {
if (__netif_subqueue_stopped(dev, fifo->fifo_no)) { if (__netif_subqueue_stopped(dev, fifo->fifo_no)) {
...@@ -4188,7 +4229,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -4188,7 +4229,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Control_1 |= TXD_GATHER_CODE_FIRST; txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
txdp->Control_1 |= TXD_LIST_OWN_XENA; txdp->Control_1 |= TXD_LIST_OWN_XENA;
txdp->Control_2 |= TXD_INT_NUMBER(fifo->fifo_no); txdp->Control_2 |= TXD_INT_NUMBER(fifo->fifo_no);
if (enable_per_list_interrupt)
if (put_off & (queue_len >> 5))
txdp->Control_2 |= TXD_INT_TYPE_PER_LIST;
if (vlan_tag) { if (vlan_tag) {
txdp->Control_2 |= TXD_VLAN_ENABLE; txdp->Control_2 |= TXD_VLAN_ENABLE;
txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag); txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
...@@ -7622,13 +7665,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, ...@@ -7622,13 +7665,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
u8 *dev_multiq) u8 *dev_multiq)
{ {
if ((tx_fifo_num > MAX_TX_FIFOS) || if ((tx_fifo_num > MAX_TX_FIFOS) ||
(tx_fifo_num < FIFO_DEFAULT_NUM)) { (tx_fifo_num < 1)) {
DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos " DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos "
"(%d) not supported\n", tx_fifo_num); "(%d) not supported\n", tx_fifo_num);
tx_fifo_num =
((tx_fifo_num > MAX_TX_FIFOS)? MAX_TX_FIFOS : if (tx_fifo_num < 1)
((tx_fifo_num < FIFO_DEFAULT_NUM) ? FIFO_DEFAULT_NUM : tx_fifo_num = 1;
tx_fifo_num)); else
tx_fifo_num = MAX_TX_FIFOS;
DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num); DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num);
DBG_PRINT(ERR_DBG, "tx fifos\n"); DBG_PRINT(ERR_DBG, "tx fifos\n");
} }
...@@ -7639,10 +7684,23 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, ...@@ -7639,10 +7684,23 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
multiq = 0; multiq = 0;
} }
#endif #endif
/* if multiqueue is enabled configure all fifos */ if (multiq)
if (multiq) {
tx_fifo_num = MAX_TX_FIFOS;
*dev_multiq = multiq; *dev_multiq = multiq;
if (tx_steering_type && (1 == tx_fifo_num)) {
if (tx_steering_type != TX_DEFAULT_STEERING)
DBG_PRINT(ERR_DBG,
"s2io: Tx steering is not supported with "
"one fifo. Disabling Tx steering.\n");
tx_steering_type = NO_STEERING;
}
if ((tx_steering_type < NO_STEERING) ||
(tx_steering_type > TX_DEFAULT_STEERING)) {
DBG_PRINT(ERR_DBG, "s2io: Requested transmit steering not "
"supported\n");
DBG_PRINT(ERR_DBG, "s2io: Disabling transmit steering\n");
tx_steering_type = NO_STEERING;
} }
if ( rx_ring_num > 8) { if ( rx_ring_num > 8) {
...@@ -7773,7 +7831,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -7773,7 +7831,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
} }
#ifdef CONFIG_NETDEVICES_MULTIQUEUE #ifdef CONFIG_NETDEVICES_MULTIQUEUE
if (dev_multiq) if (dev_multiq)
dev = alloc_etherdev_mq(sizeof(struct s2io_nic), MAX_TX_FIFOS); dev = alloc_etherdev_mq(sizeof(struct s2io_nic), tx_fifo_num);
else else
#endif #endif
dev = alloc_etherdev(sizeof(struct s2io_nic)); dev = alloc_etherdev(sizeof(struct s2io_nic));
...@@ -7824,11 +7882,33 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -7824,11 +7882,33 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
config = &sp->config; config = &sp->config;
config->napi = napi; config->napi = napi;
config->tx_steering_type = tx_steering_type;
/* Tx side parameters. */ /* Tx side parameters. */
if (config->tx_steering_type == TX_PRIORITY_STEERING)
config->tx_fifo_num = MAX_TX_FIFOS;
else
config->tx_fifo_num = tx_fifo_num; config->tx_fifo_num = tx_fifo_num;
/* Initialize the fifos used for tx steering */
if (config->tx_fifo_num < 5) {
if (config->tx_fifo_num == 1)
sp->total_tcp_fifos = 1;
else
sp->total_tcp_fifos = config->tx_fifo_num - 1;
sp->udp_fifo_idx = config->tx_fifo_num - 1;
sp->total_udp_fifos = 1;
sp->other_fifo_idx = sp->total_tcp_fifos - 1;
} else {
sp->total_tcp_fifos = (tx_fifo_num - FIFO_UDP_MAX_NUM -
FIFO_OTHER_MAX_NUM);
sp->udp_fifo_idx = sp->total_tcp_fifos;
sp->total_udp_fifos = FIFO_UDP_MAX_NUM;
sp->other_fifo_idx = sp->udp_fifo_idx + FIFO_UDP_MAX_NUM;
}
config->multiq = dev_multiq; config->multiq = dev_multiq;
for (i = 0; i < MAX_TX_FIFOS; i++) { for (i = 0; i < config->tx_fifo_num; i++) {
config->tx_cfg[i].fifo_len = tx_fifo_len[i]; config->tx_cfg[i].fifo_len = tx_fifo_len[i];
config->tx_cfg[i].fifo_priority = i; config->tx_cfg[i].fifo_priority = i;
} }
...@@ -7837,6 +7917,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -7837,6 +7917,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
for (i = 0; i < MAX_TX_FIFOS; i++) for (i = 0; i < MAX_TX_FIFOS; i++)
config->fifo_mapping[i] = fifo_map[config->tx_fifo_num - 1][i]; config->fifo_mapping[i] = fifo_map[config->tx_fifo_num - 1][i];
/* map the hashing selector table to the configured fifos */
for (i = 0; i < config->tx_fifo_num; i++)
sp->fifo_selector[i] = fifo_selector[i];
config->tx_intr_type = TXD_INT_TYPE_UTILZ; config->tx_intr_type = TXD_INT_TYPE_UTILZ;
for (i = 0; i < config->tx_fifo_num; i++) { for (i = 0; i < config->tx_fifo_num; i++) {
config->tx_cfg[i].f_no_snoop = config->tx_cfg[i].f_no_snoop =
...@@ -8113,6 +8198,20 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -8113,6 +8198,20 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n", DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n",
dev->name); dev->name);
switch (sp->config.tx_steering_type) {
case NO_STEERING:
DBG_PRINT(ERR_DBG, "%s: No steering enabled for"
" transmit\n", dev->name);
break;
case TX_PRIORITY_STEERING:
DBG_PRINT(ERR_DBG, "%s: Priority steering enabled for"
" transmit\n", dev->name);
break;
case TX_DEFAULT_STEERING:
DBG_PRINT(ERR_DBG, "%s: Default steering enabled for"
" transmit\n", dev->name);
}
if (sp->lro) if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name); dev->name);
......
...@@ -360,7 +360,10 @@ struct stat_block { ...@@ -360,7 +360,10 @@ struct stat_block {
#define MAX_TX_FIFOS 8 #define MAX_TX_FIFOS 8
#define MAX_RX_RINGS 8 #define MAX_RX_RINGS 8
#define FIFO_DEFAULT_NUM 1 #define FIFO_DEFAULT_NUM 5
#define FIFO_UDP_MAX_NUM 2 /* 0 - even, 1 -odd ports */
#define FIFO_OTHER_MAX_NUM 1
#define MAX_RX_DESC_1 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 127 ) #define MAX_RX_DESC_1 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 127 )
#define MAX_RX_DESC_2 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 ) #define MAX_RX_DESC_2 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 )
...@@ -379,6 +382,8 @@ static int fifo_map[][MAX_TX_FIFOS] = { ...@@ -379,6 +382,8 @@ static int fifo_map[][MAX_TX_FIFOS] = {
{0, 1, 2, 3, 4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7},
}; };
static u16 fifo_selector[MAX_TX_FIFOS] = {0, 1, 3, 3, 7, 7, 7, 7};
/* Maintains Per FIFO related information. */ /* Maintains Per FIFO related information. */
struct tx_fifo_config { struct tx_fifo_config {
#define MAX_AVAILABLE_TXDS 8192 #define MAX_AVAILABLE_TXDS 8192
...@@ -431,6 +436,12 @@ struct config_param { ...@@ -431,6 +436,12 @@ struct config_param {
/* Tx Side */ /* Tx Side */
u32 tx_fifo_num; /*Number of Tx FIFOs */ u32 tx_fifo_num; /*Number of Tx FIFOs */
/* 0-No steering, 1-Priority steering, 2-Default fifo map */
#define NO_STEERING 0
#define TX_PRIORITY_STEERING 0x1
#define TX_DEFAULT_STEERING 0x2
u8 tx_steering_type;
u8 fifo_mapping[MAX_TX_FIFOS]; u8 fifo_mapping[MAX_TX_FIFOS];
struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
...@@ -895,6 +906,27 @@ struct s2io_nic { ...@@ -895,6 +906,27 @@ struct s2io_nic {
*/ */
int rx_csum; int rx_csum;
/* Below variables are used for fifo selection to transmit a packet */
u16 fifo_selector[MAX_TX_FIFOS];
/* Total fifos for tcp packets */
u8 total_tcp_fifos;
/*
* Beginning index of udp for udp packets
* Value will be equal to
* (tx_fifo_num - FIFO_UDP_MAX_NUM - FIFO_OTHER_MAX_NUM)
*/
u8 udp_fifo_idx;
u8 total_udp_fifos;
/*
* Beginning index of fifo for all other packets
* Value will be equal to (tx_fifo_num - FIFO_OTHER_MAX_NUM)
*/
u8 other_fifo_idx;
/* after blink, the adapter must be restored with original /* after blink, the adapter must be restored with original
* values. * values.
*/ */
......
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