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

S2io: Added napi support when MSIX is enabled.

- Added napi support when MSIX is enabled.
- Moved test_msi function from s2io_open to probe function.
Signed-off-by: default avatarSreenivasa Honnur <sreenivasa.honnur@neterion.com>
Signed-off-by: default avatarRamkrishna Vepa <ram.vepa@neterion.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent ac731ab6
...@@ -250,7 +250,7 @@ struct XENA_dev_config { ...@@ -250,7 +250,7 @@ struct XENA_dev_config {
u64 tx_mat0_n[0x8]; u64 tx_mat0_n[0x8];
#define TX_MAT_SET(fifo, msi) vBIT(msi, (8 * fifo), 8) #define TX_MAT_SET(fifo, msi) vBIT(msi, (8 * fifo), 8)
u8 unused_1[0x8]; u64 xmsi_mask_reg;
u64 stat_byte_cnt; u64 stat_byte_cnt;
#define STAT_BC(n) vBIT(n,4,12) #define STAT_BC(n) vBIT(n,4,12)
......
...@@ -2832,6 +2832,15 @@ static void free_rx_buffers(struct s2io_nic *sp) ...@@ -2832,6 +2832,15 @@ static void free_rx_buffers(struct s2io_nic *sp)
} }
} }
static int s2io_chk_rx_buffers(struct ring_info *ring)
{
if (fill_rx_buffers(ring) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
/** /**
* s2io_poll - Rx interrupt handler for NAPI support * s2io_poll - Rx interrupt handler for NAPI support
* @napi : pointer to the napi structure. * @napi : pointer to the napi structure.
...@@ -2845,57 +2854,72 @@ static void free_rx_buffers(struct s2io_nic *sp) ...@@ -2845,57 +2854,72 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed. * 0 on success and 1 if there are No Rx packets to be processed.
*/ */
static int s2io_poll(struct napi_struct *napi, int budget) static int s2io_poll_msix(struct napi_struct *napi, int budget)
{ {
struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); struct ring_info *ring = container_of(napi, struct ring_info, napi);
struct net_device *dev = nic->dev; struct net_device *dev = ring->dev;
int pkt_cnt = 0, org_pkts_to_process;
struct mac_info *mac_control;
struct config_param *config; struct config_param *config;
struct mac_info *mac_control;
int pkts_processed = 0;
u8 *addr = NULL, val8 = 0;
struct s2io_nic *nic = dev->priv;
struct XENA_dev_config __iomem *bar0 = nic->bar0; struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i; int budget_org = budget;
mac_control = &nic->mac_control;
config = &nic->config; config = &nic->config;
mac_control = &nic->mac_control;
nic->pkts_to_process = budget; if (unlikely(!is_s2io_card_up(nic)))
org_pkts_to_process = nic->pkts_to_process; return 0;
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); pkts_processed = rx_intr_handler(ring, budget);
readl(&bar0->rx_traffic_int); s2io_chk_rx_buffers(ring);
for (i = 0; i < config->rx_ring_num; i++) { if (pkts_processed < budget_org) {
rx_intr_handler(&mac_control->rings[i]); netif_rx_complete(dev, napi);
pkt_cnt = org_pkts_to_process - nic->pkts_to_process; /*Re Enable MSI-Rx Vector*/
if (!nic->pkts_to_process) { addr = (u8 *)&bar0->xmsi_mask_reg;
/* Quota for the current iteration has been met */ addr += 7 - ring->ring_no;
goto no_rx; val8 = (ring->ring_no == 0) ? 0x3f : 0xbf;
} writeb(val8, addr);
val8 = readb(addr);
} }
return pkts_processed;
}
static int s2io_poll_inta(struct napi_struct *napi, int budget)
{
struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
struct ring_info *ring;
struct net_device *dev = nic->dev;
struct config_param *config;
struct mac_info *mac_control;
int pkts_processed = 0;
int ring_pkts_processed, i;
struct XENA_dev_config __iomem *bar0 = nic->bar0;
int budget_org = budget;
netif_rx_complete(dev, napi); config = &nic->config;
mac_control = &nic->mac_control;
for (i = 0; i < config->rx_ring_num; i++) { if (unlikely(!is_s2io_card_up(nic)))
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) { return 0;
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
/* Re enable the Rx interrupts. */
writeq(0x0, &bar0->rx_traffic_mask);
readl(&bar0->rx_traffic_mask);
return pkt_cnt;
no_rx:
for (i = 0; i < config->rx_ring_num; i++) { for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) { ring = &mac_control->rings[i];
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); ring_pkts_processed = rx_intr_handler(ring, budget);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); s2io_chk_rx_buffers(ring);
pkts_processed += ring_pkts_processed;
budget -= ring_pkts_processed;
if (budget <= 0)
break; break;
}
} }
return pkt_cnt; if (pkts_processed < budget_org) {
netif_rx_complete(dev, napi);
/* Re enable the Rx interrupts for the ring */
writeq(0, &bar0->rx_traffic_mask);
readl(&bar0->rx_traffic_mask);
}
return pkts_processed;
} }
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
...@@ -2937,7 +2961,7 @@ static void s2io_netpoll(struct net_device *dev) ...@@ -2937,7 +2961,7 @@ static void s2io_netpoll(struct net_device *dev)
/* check for received packet and indicate up to network */ /* check for received packet and indicate up to network */
for (i = 0; i < config->rx_ring_num; i++) for (i = 0; i < config->rx_ring_num; i++)
rx_intr_handler(&mac_control->rings[i]); rx_intr_handler(&mac_control->rings[i], 0);
for (i = 0; i < config->rx_ring_num; i++) { for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) { if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
...@@ -2953,7 +2977,8 @@ static void s2io_netpoll(struct net_device *dev) ...@@ -2953,7 +2977,8 @@ static void s2io_netpoll(struct net_device *dev)
/** /**
* rx_intr_handler - Rx interrupt handler * rx_intr_handler - Rx interrupt handler
* @nic: device private variable. * @ring_info: per ring structure.
* @budget: budget for napi processing.
* Description: * Description:
* If the interrupt is because of a received frame or if the * If the interrupt is because of a received frame or if the
* receive ring contains fresh as yet un-processed frames,this function is * receive ring contains fresh as yet un-processed frames,this function is
...@@ -2961,15 +2986,15 @@ static void s2io_netpoll(struct net_device *dev) ...@@ -2961,15 +2986,15 @@ static void s2io_netpoll(struct net_device *dev)
* stopped and sends the skb to the OSM's Rx handler and then increments * stopped and sends the skb to the OSM's Rx handler and then increments
* the offset. * the offset.
* Return Value: * Return Value:
* NONE. * No. of napi packets processed.
*/ */
static void rx_intr_handler(struct ring_info *ring_data) static int rx_intr_handler(struct ring_info *ring_data, int budget)
{ {
int get_block, put_block; int get_block, put_block;
struct rx_curr_get_info get_info, put_info; struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp; struct RxD_t *rxdp;
struct sk_buff *skb; struct sk_buff *skb;
int pkt_cnt = 0; int pkt_cnt = 0, napi_pkts = 0;
int i; int i;
struct RxD1* rxdp1; struct RxD1* rxdp1;
struct RxD3* rxdp3; struct RxD3* rxdp3;
...@@ -2996,7 +3021,7 @@ static void rx_intr_handler(struct ring_info *ring_data) ...@@ -2996,7 +3021,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
DBG_PRINT(ERR_DBG, "%s: The skb is ", DBG_PRINT(ERR_DBG, "%s: The skb is ",
ring_data->dev->name); ring_data->dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
return; return 0;
} }
if (ring_data->rxd_mode == RXD_MODE_1) { if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1*)rxdp; rxdp1 = (struct RxD1*)rxdp;
...@@ -3033,9 +3058,10 @@ static void rx_intr_handler(struct ring_info *ring_data) ...@@ -3033,9 +3058,10 @@ static void rx_intr_handler(struct ring_info *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr; rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
} }
if(ring_data->nic->config.napi){ if (ring_data->nic->config.napi) {
ring_data->nic->pkts_to_process -= 1; budget--;
if (!ring_data->nic->pkts_to_process) napi_pkts++;
if (!budget)
break; break;
} }
pkt_cnt++; pkt_cnt++;
...@@ -3053,6 +3079,7 @@ static void rx_intr_handler(struct ring_info *ring_data) ...@@ -3053,6 +3079,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
} }
} }
} }
return(napi_pkts);
} }
/** /**
...@@ -3749,14 +3776,19 @@ static void restore_xmsi_data(struct s2io_nic *nic) ...@@ -3749,14 +3776,19 @@ static void restore_xmsi_data(struct s2io_nic *nic)
{ {
struct XENA_dev_config __iomem *bar0 = nic->bar0; struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64; u64 val64;
int i; int i, msix_index;
if (nic->device_type == XFRAME_I_DEVICE)
return;
for (i=0; i < MAX_REQUESTED_MSI_X; i++) { for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
msix_index = (i) ? ((i-1) * 8 + 1): 0;
writeq(nic->msix_info[i].addr, &bar0->xmsi_address); writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
writeq(nic->msix_info[i].data, &bar0->xmsi_data); writeq(nic->msix_info[i].data, &bar0->xmsi_data);
val64 = (s2BIT(7) | s2BIT(15) | vBIT(i, 26, 6)); val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6));
writeq(val64, &bar0->xmsi_access); writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) { if (wait_for_msix_trans(nic, msix_index)) {
DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
continue; continue;
} }
...@@ -3767,13 +3799,17 @@ static void store_xmsi_data(struct s2io_nic *nic) ...@@ -3767,13 +3799,17 @@ static void store_xmsi_data(struct s2io_nic *nic)
{ {
struct XENA_dev_config __iomem *bar0 = nic->bar0; struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64, addr, data; u64 val64, addr, data;
int i; int i, msix_index;
if (nic->device_type == XFRAME_I_DEVICE)
return;
/* Store and display */ /* Store and display */
for (i=0; i < MAX_REQUESTED_MSI_X; i++) { for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
val64 = (s2BIT(15) | vBIT(i, 26, 6)); msix_index = (i) ? ((i-1) * 8 + 1): 0;
val64 = (s2BIT(15) | vBIT(msix_index, 26, 6));
writeq(val64, &bar0->xmsi_access); writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) { if (wait_for_msix_trans(nic, msix_index)) {
DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
continue; continue;
} }
...@@ -3793,7 +3829,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) ...@@ -3793,7 +3829,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
u16 msi_control; /* Temp variable */ u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1; int ret, i, j, msix_indx = 1;
nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry), nic->entries = kmalloc(nic->num_entries * sizeof(struct msix_entry),
GFP_KERNEL); GFP_KERNEL);
if (!nic->entries) { if (!nic->entries) {
DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
...@@ -3802,10 +3838,12 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) ...@@ -3802,10 +3838,12 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
return -ENOMEM; return -ENOMEM;
} }
nic->mac_control.stats_info->sw_stat.mem_allocated nic->mac_control.stats_info->sw_stat.mem_allocated
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); += (nic->num_entries * sizeof(struct msix_entry));
memset(nic->entries, 0, nic->num_entries * sizeof(struct msix_entry));
nic->s2io_entries = nic->s2io_entries =
kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry), kmalloc(nic->num_entries * sizeof(struct s2io_msix_entry),
GFP_KERNEL); GFP_KERNEL);
if (!nic->s2io_entries) { if (!nic->s2io_entries) {
DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
...@@ -3813,11 +3851,13 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) ...@@ -3813,11 +3851,13 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
kfree(nic->entries); kfree(nic->entries);
nic->mac_control.stats_info->sw_stat.mem_freed nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); += (nic->num_entries * sizeof(struct msix_entry));
return -ENOMEM; return -ENOMEM;
} }
nic->mac_control.stats_info->sw_stat.mem_allocated nic->mac_control.stats_info->sw_stat.mem_allocated
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); += (nic->num_entries * sizeof(struct s2io_msix_entry));
memset(nic->s2io_entries, 0,
nic->num_entries * sizeof(struct s2io_msix_entry));
nic->entries[0].entry = 0; nic->entries[0].entry = 0;
nic->s2io_entries[0].entry = 0; nic->s2io_entries[0].entry = 0;
...@@ -3825,45 +3865,38 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) ...@@ -3825,45 +3865,38 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
nic->s2io_entries[0].type = MSIX_ALARM_TYPE; nic->s2io_entries[0].type = MSIX_ALARM_TYPE;
nic->s2io_entries[0].arg = &nic->mac_control.fifos; nic->s2io_entries[0].arg = &nic->mac_control.fifos;
for (i = 1; i < MAX_REQUESTED_MSI_X; i++) { for (i = 1; i < nic->num_entries; i++) {
nic->entries[i].entry = i; nic->entries[i].entry = ((i - 1) * 8) + 1;
nic->s2io_entries[i].entry = i; nic->s2io_entries[i].entry = ((i - 1) * 8) + 1;
nic->s2io_entries[i].arg = NULL; nic->s2io_entries[i].arg = NULL;
nic->s2io_entries[i].in_use = 0; nic->s2io_entries[i].in_use = 0;
} }
rx_mat = readq(&bar0->rx_mat); rx_mat = readq(&bar0->rx_mat);
for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) { for (j = 0; j < nic->config.rx_ring_num; j++) {
rx_mat |= RX_MAT_SET(j, msix_indx); rx_mat |= RX_MAT_SET(j, msix_indx);
nic->s2io_entries[msix_indx].arg nic->s2io_entries[j+1].arg = &nic->mac_control.rings[j];
= &nic->mac_control.rings[j]; nic->s2io_entries[j+1].type = MSIX_RING_TYPE;
nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; nic->s2io_entries[j+1].in_use = MSIX_FLG;
nic->s2io_entries[msix_indx].in_use = MSIX_FLG; msix_indx += 8;
} }
writeq(rx_mat, &bar0->rx_mat); writeq(rx_mat, &bar0->rx_mat);
readq(&bar0->rx_mat);
nic->avail_msix_vectors = 0; ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries);
ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
/* We fail init if error or we get less vectors than min required */ /* We fail init if error or we get less vectors than min required */
if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
nic->avail_msix_vectors = ret;
ret = pci_enable_msix(nic->pdev, nic->entries, ret);
}
if (ret) { if (ret) {
DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
kfree(nic->entries); kfree(nic->entries);
nic->mac_control.stats_info->sw_stat.mem_freed nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); += (nic->num_entries * sizeof(struct msix_entry));
kfree(nic->s2io_entries); kfree(nic->s2io_entries);
nic->mac_control.stats_info->sw_stat.mem_freed nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); += (nic->num_entries * sizeof(struct s2io_msix_entry));
nic->entries = NULL; nic->entries = NULL;
nic->s2io_entries = NULL; nic->s2io_entries = NULL;
nic->avail_msix_vectors = 0;
return -ENOMEM; return -ENOMEM;
} }
if (!nic->avail_msix_vectors)
nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
/* /*
* To enable MSI-X, MSI also needs to be enabled, due to a bug * To enable MSI-X, MSI also needs to be enabled, due to a bug
...@@ -3935,7 +3968,7 @@ static void remove_msix_isr(struct s2io_nic *sp) ...@@ -3935,7 +3968,7 @@ static void remove_msix_isr(struct s2io_nic *sp)
int i; int i;
u16 msi_control; u16 msi_control;
for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { for (i = 0; i < sp->num_entries; i++) {
if (sp->s2io_entries[i].in_use == if (sp->s2io_entries[i].in_use ==
MSIX_REGISTERED_SUCCESS) { MSIX_REGISTERED_SUCCESS) {
int vector = sp->entries[i].vector; int vector = sp->entries[i].vector;
...@@ -3991,29 +4024,6 @@ static int s2io_open(struct net_device *dev) ...@@ -3991,29 +4024,6 @@ static int s2io_open(struct net_device *dev)
netif_carrier_off(dev); netif_carrier_off(dev);
sp->last_link_state = 0; sp->last_link_state = 0;
if (sp->config.intr_type == MSI_X) {
int ret = s2io_enable_msi_x(sp);
if (!ret) {
ret = s2io_test_msi(sp);
/* rollback MSI-X, will re-enable during add_isr() */
remove_msix_isr(sp);
}
if (ret) {
DBG_PRINT(ERR_DBG,
"%s: MSI-X requested but failed to enable\n",
dev->name);
sp->config.intr_type = INTA;
}
}
/* NAPI doesn't work well with MSI(X) */
if (sp->config.intr_type != INTA) {
if(sp->config.napi)
sp->config.napi = 0;
}
/* Initialize H/W and enable interrupts */ /* Initialize H/W and enable interrupts */
err = s2io_card_up(sp); err = s2io_card_up(sp);
if (err) { if (err) {
...@@ -4036,12 +4046,12 @@ hw_init_failed: ...@@ -4036,12 +4046,12 @@ hw_init_failed:
if (sp->entries) { if (sp->entries) {
kfree(sp->entries); kfree(sp->entries);
sp->mac_control.stats_info->sw_stat.mem_freed sp->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); += (sp->num_entries * sizeof(struct msix_entry));
} }
if (sp->s2io_entries) { if (sp->s2io_entries) {
kfree(sp->s2io_entries); kfree(sp->s2io_entries);
sp->mac_control.stats_info->sw_stat.mem_freed sp->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); += (sp->num_entries * sizeof(struct s2io_msix_entry));
} }
} }
return err; return err;
...@@ -4343,25 +4353,29 @@ s2io_alarm_handle(unsigned long data) ...@@ -4343,25 +4353,29 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2); mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
} }
static int s2io_chk_rx_buffers(struct ring_info *ring)
{
if (fill_rx_buffers(ring) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
{ {
struct ring_info *ring = (struct ring_info *)dev_id; struct ring_info *ring = (struct ring_info *)dev_id;
struct s2io_nic *sp = ring->nic; struct s2io_nic *sp = ring->nic;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
struct net_device *dev = sp->dev;
if (!is_s2io_card_up(sp)) if (unlikely(!is_s2io_card_up(sp)))
return IRQ_HANDLED; return IRQ_HANDLED;
rx_intr_handler(ring); if (sp->config.napi) {
s2io_chk_rx_buffers(ring); u8 *addr = NULL, val8 = 0;
addr = (u8 *)&bar0->xmsi_mask_reg;
addr += (7 - ring->ring_no);
val8 = (ring->ring_no == 0) ? 0x7f : 0xff;
writeb(val8, addr);
val8 = readb(addr);
netif_rx_schedule(dev, &ring->napi);
} else {
rx_intr_handler(ring, 0);
s2io_chk_rx_buffers(ring);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -4798,14 +4812,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) ...@@ -4798,14 +4812,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
if (config->napi) { if (config->napi) {
if (reason & GEN_INTR_RXTRAFFIC) { if (reason & GEN_INTR_RXTRAFFIC) {
if (likely(netif_rx_schedule_prep(dev, netif_rx_schedule(dev, &sp->napi);
&sp->napi))) { writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
__netif_rx_schedule(dev, &sp->napi); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
writeq(S2IO_MINUS_ONE, readl(&bar0->rx_traffic_int);
&bar0->rx_traffic_mask);
} else
writeq(S2IO_MINUS_ONE,
&bar0->rx_traffic_int);
} }
} else { } else {
/* /*
...@@ -4817,7 +4827,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) ...@@ -4817,7 +4827,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++) for (i = 0; i < config->rx_ring_num; i++)
rx_intr_handler(&mac_control->rings[i]); rx_intr_handler(&mac_control->rings[i], 0);
} }
/* /*
...@@ -7022,8 +7032,9 @@ static int s2io_add_isr(struct s2io_nic * sp) ...@@ -7022,8 +7032,9 @@ static int s2io_add_isr(struct s2io_nic * sp)
if (sp->config.intr_type == MSI_X) { if (sp->config.intr_type == MSI_X) {
int i, msix_rx_cnt = 0; int i, msix_rx_cnt = 0;
for (i = 0; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { for (i = 0; i < sp->num_entries; i++) {
if (sp->s2io_entries[i].type == if (sp->s2io_entries[i].in_use == MSIX_FLG) {
if (sp->s2io_entries[i].type ==
MSIX_RING_TYPE) { MSIX_RING_TYPE) {
sprintf(sp->desc[i], "%s:MSI-X-%d-RX", sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
dev->name, i); dev->name, i);
...@@ -7068,7 +7079,7 @@ static int s2io_add_isr(struct s2io_nic * sp) ...@@ -7068,7 +7079,7 @@ static int s2io_add_isr(struct s2io_nic * sp)
} }
sp->s2io_entries[i].in_use = sp->s2io_entries[i].in_use =
MSIX_REGISTERED_SUCCESS; MSIX_REGISTERED_SUCCESS;
}
} }
if (!err) { if (!err) {
printk(KERN_INFO "MSI-X-RX %d entries enabled\n", printk(KERN_INFO "MSI-X-RX %d entries enabled\n",
...@@ -7115,8 +7126,15 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) ...@@ -7115,8 +7126,15 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
clear_bit(__S2IO_STATE_CARD_UP, &sp->state); clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
/* Disable napi */ /* Disable napi */
if (config->napi) if (sp->config.napi) {
napi_disable(&sp->napi); int off = 0;
if (config->intr_type == MSI_X) {
for (; off < sp->config.rx_ring_num; off++)
napi_disable(&sp->mac_control.rings[off].napi);
}
else
napi_disable(&sp->napi);
}
/* disable Tx and Rx traffic on the NIC */ /* disable Tx and Rx traffic on the NIC */
if (do_io) if (do_io)
...@@ -7208,8 +7226,15 @@ static int s2io_card_up(struct s2io_nic * sp) ...@@ -7208,8 +7226,15 @@ static int s2io_card_up(struct s2io_nic * sp)
} }
/* Initialise napi */ /* Initialise napi */
if (config->napi) if (config->napi) {
napi_enable(&sp->napi); int i;
if (config->intr_type == MSI_X) {
for (i = 0; i < sp->config.rx_ring_num; i++)
napi_enable(&sp->mac_control.rings[i].napi);
} else {
napi_enable(&sp->napi);
}
}
/* Maintain the state prior to the open */ /* Maintain the state prior to the open */
if (sp->promisc_flg) if (sp->promisc_flg)
...@@ -7650,9 +7675,6 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, ...@@ -7650,9 +7675,6 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
rx_ring_num = MAX_RX_RINGS; rx_ring_num = MAX_RX_RINGS;
} }
if (*dev_intr_type != INTA)
napi = 0;
if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) { if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. " DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
"Defaulting to INTA\n"); "Defaulting to INTA\n");
...@@ -7953,8 +7975,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -7953,8 +7975,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address * will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called * mac address will be set every time dev->open() is called
*/ */
netif_napi_add(dev, &sp->napi, s2io_poll, 32);
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll; dev->poll_controller = s2io_netpoll;
#endif #endif
...@@ -7998,6 +8018,32 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -7998,6 +8018,32 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
} }
} }
if (sp->config.intr_type == MSI_X) {
sp->num_entries = config->rx_ring_num + 1;
ret = s2io_enable_msi_x(sp);
if (!ret) {
ret = s2io_test_msi(sp);
/* rollback MSI-X, will re-enable during add_isr() */
remove_msix_isr(sp);
}
if (ret) {
DBG_PRINT(ERR_DBG,
"%s: MSI-X requested but failed to enable\n",
dev->name);
sp->config.intr_type = INTA;
}
}
if (config->intr_type == MSI_X) {
for (i = 0; i < config->rx_ring_num ; i++)
netif_napi_add(dev, &mac_control->rings[i].napi,
s2io_poll_msix, 64);
} else {
netif_napi_add(dev, &sp->napi, s2io_poll_inta, 64);
}
/* Not needed for Herc */ /* Not needed for Herc */
if (sp->device_type & XFRAME_I_DEVICE) { if (sp->device_type & XFRAME_I_DEVICE) {
/* /*
...@@ -8048,6 +8094,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -8048,6 +8094,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* store mac addresses from CAM to s2io_nic structure */ /* store mac addresses from CAM to s2io_nic structure */
do_s2io_store_unicast_mc(sp); do_s2io_store_unicast_mc(sp);
/* Configure MSIX vector for number of rings configured plus one */
if ((sp->device_type == XFRAME_II_DEVICE) &&
(config->intr_type == MSI_X))
sp->num_entries = config->rx_ring_num + 1;
/* Store the values of the MSIX table in the s2io_nic structure */ /* Store the values of the MSIX table in the s2io_nic structure */
store_xmsi_data(sp); store_xmsi_data(sp);
/* reset Nic and bring it to known state */ /* reset Nic and bring it to known state */
...@@ -8113,8 +8164,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ...@@ -8113,8 +8164,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
break; break;
} }
if (napi) switch (sp->config.napi) {
case 0:
DBG_PRINT(ERR_DBG, "%s: NAPI disabled\n", dev->name);
break;
case 1:
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
break;
}
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name, DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num); sp->config.tx_fifo_num);
......
...@@ -706,7 +706,7 @@ struct ring_info { ...@@ -706,7 +706,7 @@ struct ring_info {
/* per-ring buffer counter */ /* per-ring buffer counter */
u32 rx_bufs_left; u32 rx_bufs_left;
#define MAX_LRO_SESSIONS 32 #define MAX_LRO_SESSIONS 32
struct lro lro0_n[MAX_LRO_SESSIONS]; struct lro lro0_n[MAX_LRO_SESSIONS];
u8 lro; u8 lro;
...@@ -725,6 +725,11 @@ struct ring_info { ...@@ -725,6 +725,11 @@ struct ring_info {
/* copy of sp->pdev pointer */ /* copy of sp->pdev pointer */
struct pci_dev *pdev; struct pci_dev *pdev;
/* Per ring napi struct */
struct napi_struct napi;
unsigned long interrupt_count;
/* /*
* Place holders for the virtual and physical addresses of * Place holders for the virtual and physical addresses of
* all the Rx Blocks * all the Rx Blocks
...@@ -841,7 +846,7 @@ struct usr_addr { ...@@ -841,7 +846,7 @@ struct usr_addr {
* Structure to keep track of the MSI-X vectors and the corresponding * Structure to keep track of the MSI-X vectors and the corresponding
* argument registered against each vector * argument registered against each vector
*/ */
#define MAX_REQUESTED_MSI_X 17 #define MAX_REQUESTED_MSI_X 9
struct s2io_msix_entry struct s2io_msix_entry
{ {
u16 vector; u16 vector;
...@@ -877,7 +882,6 @@ struct s2io_nic { ...@@ -877,7 +882,6 @@ struct s2io_nic {
*/ */
int pkts_to_process; int pkts_to_process;
struct net_device *dev; struct net_device *dev;
struct napi_struct napi;
struct mac_info mac_control; struct mac_info mac_control;
struct config_param config; struct config_param config;
struct pci_dev *pdev; struct pci_dev *pdev;
...@@ -948,6 +952,7 @@ struct s2io_nic { ...@@ -948,6 +952,7 @@ struct s2io_nic {
*/ */
u8 other_fifo_idx; u8 other_fifo_idx;
struct napi_struct napi;
/* after blink, the adapter must be restored with original /* after blink, the adapter must be restored with original
* values. * values.
*/ */
...@@ -962,6 +967,7 @@ struct s2io_nic { ...@@ -962,6 +967,7 @@ struct s2io_nic {
unsigned long long start_time; unsigned long long start_time;
struct vlan_group *vlgrp; struct vlan_group *vlgrp;
#define MSIX_FLG 0xA5 #define MSIX_FLG 0xA5
int num_entries;
struct msix_entry *entries; struct msix_entry *entries;
int msi_detected; int msi_detected;
wait_queue_head_t msi_wait; wait_queue_head_t msi_wait;
...@@ -1104,7 +1110,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev); ...@@ -1104,7 +1110,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
static int init_shared_mem(struct s2io_nic *sp); static int init_shared_mem(struct s2io_nic *sp);
static void free_shared_mem(struct s2io_nic *sp); static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic); static int init_nic(struct s2io_nic *nic);
static void rx_intr_handler(struct ring_info *ring_data); static int rx_intr_handler(struct ring_info *ring_data, int budget);
static void tx_intr_handler(struct fifo_info *fifo_data); static void tx_intr_handler(struct fifo_info *fifo_data);
static void s2io_handle_errors(void * dev_id); static void s2io_handle_errors(void * dev_id);
...@@ -1115,7 +1121,8 @@ static void s2io_set_multicast(struct net_device *dev); ...@@ -1115,7 +1121,8 @@ static void s2io_set_multicast(struct net_device *dev);
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
static void s2io_link(struct s2io_nic * sp, int link); static void s2io_link(struct s2io_nic * sp, int link);
static void s2io_reset(struct s2io_nic * sp); static void s2io_reset(struct s2io_nic * sp);
static int s2io_poll(struct napi_struct *napi, int budget); static int s2io_poll_msix(struct napi_struct *napi, int budget);
static int s2io_poll_inta(struct napi_struct *napi, int budget);
static void s2io_init_pci(struct s2io_nic * sp); static void s2io_init_pci(struct s2io_nic * sp);
static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr); static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr);
static void s2io_alarm_handle(unsigned long data); static void s2io_alarm_handle(unsigned long data);
......
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