|
@@ -1976,7 +1976,6 @@ static int start_nic(struct s2io_nic *nic)
|
|
|
XENA_dev_config_t __iomem *bar0 = nic->bar0;
|
|
|
struct net_device *dev = nic->dev;
|
|
|
register u64 val64 = 0;
|
|
|
- u16 interruptible;
|
|
|
u16 subid, i;
|
|
|
mac_info_t *mac_control;
|
|
|
struct config_param *config;
|
|
@@ -2047,16 +2046,6 @@ static int start_nic(struct s2io_nic *nic)
|
|
|
return FAILURE;
|
|
|
}
|
|
|
|
|
|
- /* Enable select interrupts */
|
|
|
- if (nic->intr_type != INTA)
|
|
|
- en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
|
|
|
- else {
|
|
|
- interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
|
|
|
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
|
|
|
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
|
|
|
- en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
* With some switches, link might be already up at this point.
|
|
|
* Because of this weird behavior, when we enable laser,
|
|
@@ -3749,101 +3738,19 @@ static int s2io_open(struct net_device *dev)
|
|
|
if (err) {
|
|
|
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
|
|
|
dev->name);
|
|
|
- if (err == -ENODEV)
|
|
|
- goto hw_init_failed;
|
|
|
- else
|
|
|
- goto hw_enable_failed;
|
|
|
- }
|
|
|
-
|
|
|
- /* Store the values of the MSIX table in the nic_t structure */
|
|
|
- store_xmsi_data(sp);
|
|
|
-
|
|
|
- /* After proper initialization of H/W, register ISR */
|
|
|
- if (sp->intr_type == MSI) {
|
|
|
- err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
|
|
|
- IRQF_SHARED, sp->name, dev);
|
|
|
- if (err) {
|
|
|
- DBG_PRINT(ERR_DBG, "%s: MSI registration \
|
|
|
-failed\n", dev->name);
|
|
|
- goto isr_registration_failed;
|
|
|
- }
|
|
|
- }
|
|
|
- if (sp->intr_type == MSI_X) {
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
|
|
|
- if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
|
|
|
- sprintf(sp->desc1, "%s:MSI-X-%d-TX",
|
|
|
- dev->name, i);
|
|
|
- err = request_irq(sp->entries[i].vector,
|
|
|
- s2io_msix_fifo_handle, 0, sp->desc1,
|
|
|
- sp->s2io_entries[i].arg);
|
|
|
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
|
|
|
- (unsigned long long)sp->msix_info[i].addr);
|
|
|
- } else {
|
|
|
- sprintf(sp->desc2, "%s:MSI-X-%d-RX",
|
|
|
- dev->name, i);
|
|
|
- err = request_irq(sp->entries[i].vector,
|
|
|
- s2io_msix_ring_handle, 0, sp->desc2,
|
|
|
- sp->s2io_entries[i].arg);
|
|
|
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
|
|
|
- (unsigned long long)sp->msix_info[i].addr);
|
|
|
- }
|
|
|
- if (err) {
|
|
|
- DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
|
|
|
-failed\n", dev->name, i);
|
|
|
- DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
|
|
|
- goto isr_registration_failed;
|
|
|
- }
|
|
|
- sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
|
|
|
- }
|
|
|
- }
|
|
|
- if (sp->intr_type == INTA) {
|
|
|
- err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
|
|
|
- sp->name, dev);
|
|
|
- if (err) {
|
|
|
- DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
|
|
|
- dev->name);
|
|
|
- goto isr_registration_failed;
|
|
|
- }
|
|
|
+ goto hw_init_failed;
|
|
|
}
|
|
|
|
|
|
if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
|
|
|
DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
|
|
|
+ s2io_card_down(sp);
|
|
|
err = -ENODEV;
|
|
|
- goto setting_mac_address_failed;
|
|
|
+ goto hw_init_failed;
|
|
|
}
|
|
|
|
|
|
netif_start_queue(dev);
|
|
|
return 0;
|
|
|
|
|
|
-setting_mac_address_failed:
|
|
|
- if (sp->intr_type != MSI_X)
|
|
|
- free_irq(sp->pdev->irq, dev);
|
|
|
-isr_registration_failed:
|
|
|
- del_timer_sync(&sp->alarm_timer);
|
|
|
- if (sp->intr_type == MSI_X) {
|
|
|
- int i;
|
|
|
- u16 msi_control; /* Temp variable */
|
|
|
-
|
|
|
- for (i=1; (sp->s2io_entries[i].in_use ==
|
|
|
- MSIX_REGISTERED_SUCCESS); i++) {
|
|
|
- int vector = sp->entries[i].vector;
|
|
|
- void *arg = sp->s2io_entries[i].arg;
|
|
|
-
|
|
|
- free_irq(vector, arg);
|
|
|
- }
|
|
|
- pci_disable_msix(sp->pdev);
|
|
|
-
|
|
|
- /* Temp */
|
|
|
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
|
|
|
- msi_control &= 0xFFFE; /* Disable MSI */
|
|
|
- pci_write_config_word(sp->pdev, 0x42, msi_control);
|
|
|
- }
|
|
|
- else if (sp->intr_type == MSI)
|
|
|
- pci_disable_msi(sp->pdev);
|
|
|
-hw_enable_failed:
|
|
|
- s2io_reset(sp);
|
|
|
hw_init_failed:
|
|
|
if (sp->intr_type == MSI_X) {
|
|
|
if (sp->entries)
|
|
@@ -3874,7 +3781,7 @@ static int s2io_close(struct net_device *dev)
|
|
|
flush_scheduled_work();
|
|
|
netif_stop_queue(dev);
|
|
|
/* Reset card, kill tasklet and free Tx and Rx buffers. */
|
|
|
- s2io_card_down(sp, 1);
|
|
|
+ s2io_card_down(sp);
|
|
|
|
|
|
sp->device_close_flag = TRUE; /* Device is shut down. */
|
|
|
return 0;
|
|
@@ -5919,7 +5826,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
|
|
|
|
|
|
dev->mtu = new_mtu;
|
|
|
if (netif_running(dev)) {
|
|
|
- s2io_card_down(sp, 0);
|
|
|
+ s2io_card_down(sp);
|
|
|
netif_stop_queue(dev);
|
|
|
if (s2io_card_up(sp)) {
|
|
|
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
|
|
@@ -6216,43 +6123,106 @@ static int rxd_owner_bit_reset(nic_t *sp)
|
|
|
|
|
|
}
|
|
|
|
|
|
-static void s2io_card_down(nic_t * sp, int flag)
|
|
|
+static int s2io_add_isr(nic_t * sp)
|
|
|
{
|
|
|
- int cnt = 0;
|
|
|
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
|
|
|
- unsigned long flags;
|
|
|
- register u64 val64 = 0;
|
|
|
+ int ret = 0;
|
|
|
struct net_device *dev = sp->dev;
|
|
|
+ int err = 0;
|
|
|
|
|
|
- del_timer_sync(&sp->alarm_timer);
|
|
|
- /* If s2io_set_link task is executing, wait till it completes. */
|
|
|
- while (test_and_set_bit(0, &(sp->link_state))) {
|
|
|
- msleep(50);
|
|
|
+ if (sp->intr_type == MSI)
|
|
|
+ ret = s2io_enable_msi(sp);
|
|
|
+ else if (sp->intr_type == MSI_X)
|
|
|
+ ret = s2io_enable_msi_x(sp);
|
|
|
+ if (ret) {
|
|
|
+ DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
|
|
|
+ sp->intr_type = INTA;
|
|
|
}
|
|
|
- atomic_set(&sp->card_state, CARD_DOWN);
|
|
|
|
|
|
- /* disable Tx and Rx traffic on the NIC */
|
|
|
- stop_nic(sp);
|
|
|
- if (flag) {
|
|
|
- if (sp->intr_type == MSI_X) {
|
|
|
- int i;
|
|
|
- u16 msi_control;
|
|
|
+ /* Store the values of the MSIX table in the nic_t structure */
|
|
|
+ store_xmsi_data(sp);
|
|
|
|
|
|
- for (i=1; (sp->s2io_entries[i].in_use ==
|
|
|
- MSIX_REGISTERED_SUCCESS); i++) {
|
|
|
- int vector = sp->entries[i].vector;
|
|
|
- void *arg = sp->s2io_entries[i].arg;
|
|
|
+ /* After proper initialization of H/W, register ISR */
|
|
|
+ if (sp->intr_type == MSI) {
|
|
|
+ err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
|
|
|
+ IRQF_SHARED, sp->name, dev);
|
|
|
+ if (err) {
|
|
|
+ pci_disable_msi(sp->pdev);
|
|
|
+ DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
|
|
|
+ dev->name);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (sp->intr_type == MSI_X) {
|
|
|
+ int i;
|
|
|
|
|
|
- free_irq(vector, arg);
|
|
|
+ for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
|
|
|
+ if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
|
|
|
+ sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
|
|
|
+ dev->name, i);
|
|
|
+ err = request_irq(sp->entries[i].vector,
|
|
|
+ s2io_msix_fifo_handle, 0, sp->desc[i],
|
|
|
+ sp->s2io_entries[i].arg);
|
|
|
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
|
|
|
+ (unsigned long long)sp->msix_info[i].addr);
|
|
|
+ } else {
|
|
|
+ sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
|
|
|
+ dev->name, i);
|
|
|
+ err = request_irq(sp->entries[i].vector,
|
|
|
+ s2io_msix_ring_handle, 0, sp->desc[i],
|
|
|
+ sp->s2io_entries[i].arg);
|
|
|
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
|
|
|
+ (unsigned long long)sp->msix_info[i].addr);
|
|
|
}
|
|
|
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
|
|
|
- msi_control &= 0xFFFE; /* Disable MSI */
|
|
|
- pci_write_config_word(sp->pdev, 0x42, msi_control);
|
|
|
- pci_disable_msix(sp->pdev);
|
|
|
- } else {
|
|
|
- free_irq(sp->pdev->irq, dev);
|
|
|
- if (sp->intr_type == MSI)
|
|
|
- pci_disable_msi(sp->pdev);
|
|
|
+ if (err) {
|
|
|
+ DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
|
|
|
+ "failed\n", dev->name, i);
|
|
|
+ DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (sp->intr_type == INTA) {
|
|
|
+ err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
|
|
|
+ sp->name, dev);
|
|
|
+ if (err) {
|
|
|
+ DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
|
|
|
+ dev->name);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+static void s2io_rem_isr(nic_t * sp)
|
|
|
+{
|
|
|
+ int cnt = 0;
|
|
|
+ struct net_device *dev = sp->dev;
|
|
|
+
|
|
|
+ if (sp->intr_type == MSI_X) {
|
|
|
+ int i;
|
|
|
+ u16 msi_control;
|
|
|
+
|
|
|
+ for (i=1; (sp->s2io_entries[i].in_use ==
|
|
|
+ MSIX_REGISTERED_SUCCESS); i++) {
|
|
|
+ int vector = sp->entries[i].vector;
|
|
|
+ void *arg = sp->s2io_entries[i].arg;
|
|
|
+
|
|
|
+ free_irq(vector, arg);
|
|
|
+ }
|
|
|
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
|
|
|
+ msi_control &= 0xFFFE; /* Disable MSI */
|
|
|
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
|
|
|
+
|
|
|
+ pci_disable_msix(sp->pdev);
|
|
|
+ } else {
|
|
|
+ free_irq(sp->pdev->irq, dev);
|
|
|
+ if (sp->intr_type == MSI) {
|
|
|
+ u16 val;
|
|
|
+
|
|
|
+ pci_disable_msi(sp->pdev);
|
|
|
+ pci_read_config_word(sp->pdev, 0x4c, &val);
|
|
|
+ val ^= 0x1;
|
|
|
+ pci_write_config_word(sp->pdev, 0x4c, val);
|
|
|
}
|
|
|
}
|
|
|
/* Waiting till all Interrupt handlers are complete */
|
|
@@ -6263,6 +6233,26 @@ static void s2io_card_down(nic_t * sp, int flag)
|
|
|
break;
|
|
|
cnt++;
|
|
|
} while(cnt < 5);
|
|
|
+}
|
|
|
+
|
|
|
+static void s2io_card_down(nic_t * sp)
|
|
|
+{
|
|
|
+ int cnt = 0;
|
|
|
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
|
|
|
+ unsigned long flags;
|
|
|
+ register u64 val64 = 0;
|
|
|
+
|
|
|
+ del_timer_sync(&sp->alarm_timer);
|
|
|
+ /* If s2io_set_link task is executing, wait till it completes. */
|
|
|
+ while (test_and_set_bit(0, &(sp->link_state))) {
|
|
|
+ msleep(50);
|
|
|
+ }
|
|
|
+ atomic_set(&sp->card_state, CARD_DOWN);
|
|
|
+
|
|
|
+ /* disable Tx and Rx traffic on the NIC */
|
|
|
+ stop_nic(sp);
|
|
|
+
|
|
|
+ s2io_rem_isr(sp);
|
|
|
|
|
|
/* Kill tasklet. */
|
|
|
tasklet_kill(&sp->task);
|
|
@@ -6314,23 +6304,16 @@ static int s2io_card_up(nic_t * sp)
|
|
|
mac_info_t *mac_control;
|
|
|
struct config_param *config;
|
|
|
struct net_device *dev = (struct net_device *) sp->dev;
|
|
|
+ u16 interruptible;
|
|
|
|
|
|
/* Initialize the H/W I/O registers */
|
|
|
if (init_nic(sp) != 0) {
|
|
|
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
|
|
|
dev->name);
|
|
|
+ s2io_reset(sp);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
- if (sp->intr_type == MSI)
|
|
|
- ret = s2io_enable_msi(sp);
|
|
|
- else if (sp->intr_type == MSI_X)
|
|
|
- ret = s2io_enable_msi_x(sp);
|
|
|
- if (ret) {
|
|
|
- DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
|
|
|
- sp->intr_type = INTA;
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
* Initializing the Rx buffers. For now we are considering only 1
|
|
|
* Rx ring and initializing buffers into 30 Rx blocks
|
|
@@ -6361,21 +6344,39 @@ static int s2io_card_up(nic_t * sp)
|
|
|
sp->lro_max_aggr_per_sess = lro_max_pkts;
|
|
|
}
|
|
|
|
|
|
- /* Enable tasklet for the device */
|
|
|
- tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
|
|
|
-
|
|
|
/* Enable Rx Traffic and interrupts on the NIC */
|
|
|
if (start_nic(sp)) {
|
|
|
DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
|
|
|
- tasklet_kill(&sp->task);
|
|
|
s2io_reset(sp);
|
|
|
- free_irq(dev->irq, dev);
|
|
|
+ free_rx_buffers(sp);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add interrupt service routine */
|
|
|
+ if (s2io_add_isr(sp) != 0) {
|
|
|
+ if (sp->intr_type == MSI_X)
|
|
|
+ s2io_rem_isr(sp);
|
|
|
+ s2io_reset(sp);
|
|
|
free_rx_buffers(sp);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
|
|
|
|
|
|
+ /* Enable tasklet for the device */
|
|
|
+ tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
|
|
|
+
|
|
|
+ /* Enable select interrupts */
|
|
|
+ if (sp->intr_type != INTA)
|
|
|
+ en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
|
|
|
+ else {
|
|
|
+ interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
|
|
|
+ interruptible |= TX_PIC_INTR | RX_PIC_INTR;
|
|
|
+ interruptible |= TX_MAC_INTR | RX_MAC_INTR;
|
|
|
+ en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
atomic_set(&sp->card_state, CARD_UP);
|
|
|
return 0;
|
|
|
}
|
|
@@ -6395,7 +6396,7 @@ static void s2io_restart_nic(unsigned long data)
|
|
|
struct net_device *dev = (struct net_device *) data;
|
|
|
nic_t *sp = dev->priv;
|
|
|
|
|
|
- s2io_card_down(sp, 0);
|
|
|
+ s2io_card_down(sp);
|
|
|
if (s2io_card_up(sp)) {
|
|
|
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
|
|
|
dev->name);
|