From: Ananda Raju Date: Fri, 7 Jul 2006 06:58:23 +0000 (-0700) Subject: [PATCH] s2io driver irq fix X-Git-Tag: v2.6.18-rc2~101^2~12 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e6a8fee2098f29749e4e48321611f2d661b2eb71;p=linux-2.6 [PATCH] s2io driver irq fix Modification and bug fixes with respect to irq registration. - Enable interrupts after request_irq - Restored MSI data register value at driver unload time Signed-off-by: Ananda Raju Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index c6b77acb35..e1fe3a0a7b 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -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); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index c43f521797..217097bc22 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -829,8 +829,7 @@ struct s2io_nic { #define MSIX_FLG 0xA5 struct msix_entry *entries; struct s2io_msix_entry *s2io_entries; - char desc1[35]; - char desc2[35]; + char desc[MAX_REQUESTED_MSI_X][25]; int avail_msix_vectors; /* No. of MSI-X vectors granted by system */ @@ -1002,7 +1001,7 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static struct ethtool_ops netdev_ethtool_ops; static void s2io_set_link(unsigned long data); static int s2io_set_swapper(nic_t * sp); -static void s2io_card_down(nic_t *nic, int flag); +static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); static int get_xena_rev_id(struct pci_dev *pdev); static void restore_xmsi_data(nic_t *nic);