diff options
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r-- | drivers/net/s2io.c | 93 |
1 files changed, 91 insertions, 2 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd012322cdbe..588938204e20 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -37,7 +37,7 @@ | |||
37 | * tx_fifo_len: This too is an array of 8. Each element defines the number of | 37 | * tx_fifo_len: This too is an array of 8. Each element defines the number of |
38 | * Tx descriptors that can be associated with each corresponding FIFO. | 38 | * Tx descriptors that can be associated with each corresponding FIFO. |
39 | * intr_type: This defines the type of interrupt. The values can be 0(INTA), | 39 | * intr_type: This defines the type of interrupt. The values can be 0(INTA), |
40 | * 2(MSI_X). Default value is '0(INTA)' | 40 | * 2(MSI_X). Default value is '2(MSI_X)' |
41 | * lro: Specifies whether to enable Large Receive Offload (LRO) or not. | 41 | * lro: Specifies whether to enable Large Receive Offload (LRO) or not. |
42 | * Possible values '1' for enable '0' for disable. Default is '0' | 42 | * Possible values '1' for enable '0' for disable. Default is '0' |
43 | * lro_max_pkts: This parameter defines maximum number of packets can be | 43 | * lro_max_pkts: This parameter defines maximum number of packets can be |
@@ -428,7 +428,7 @@ S2IO_PARM_INT(l3l4hdr_size, 128); | |||
428 | /* Frequency of Rx desc syncs expressed as power of 2 */ | 428 | /* Frequency of Rx desc syncs expressed as power of 2 */ |
429 | S2IO_PARM_INT(rxsync_frequency, 3); | 429 | S2IO_PARM_INT(rxsync_frequency, 3); |
430 | /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ | 430 | /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ |
431 | S2IO_PARM_INT(intr_type, 0); | 431 | S2IO_PARM_INT(intr_type, 2); |
432 | /* Large receive offload feature */ | 432 | /* Large receive offload feature */ |
433 | S2IO_PARM_INT(lro, 0); | 433 | S2IO_PARM_INT(lro, 0); |
434 | /* Max pkts to be aggregated by LRO at one time. If not specified, | 434 | /* Max pkts to be aggregated by LRO at one time. If not specified, |
@@ -3773,6 +3773,59 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) | |||
3773 | return 0; | 3773 | return 0; |
3774 | } | 3774 | } |
3775 | 3775 | ||
3776 | /* Handle software interrupt used during MSI(X) test */ | ||
3777 | static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id) | ||
3778 | { | ||
3779 | struct s2io_nic *sp = dev_id; | ||
3780 | |||
3781 | sp->msi_detected = 1; | ||
3782 | wake_up(&sp->msi_wait); | ||
3783 | |||
3784 | return IRQ_HANDLED; | ||
3785 | } | ||
3786 | |||
3787 | /* Test interrupt path by forcing a a software IRQ */ | ||
3788 | static int __devinit s2io_test_msi(struct s2io_nic *sp) | ||
3789 | { | ||
3790 | struct pci_dev *pdev = sp->pdev; | ||
3791 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | ||
3792 | int err; | ||
3793 | u64 val64, saved64; | ||
3794 | |||
3795 | err = request_irq(sp->entries[1].vector, s2io_test_intr, 0, | ||
3796 | sp->name, sp); | ||
3797 | if (err) { | ||
3798 | DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n", | ||
3799 | sp->dev->name, pci_name(pdev), pdev->irq); | ||
3800 | return err; | ||
3801 | } | ||
3802 | |||
3803 | init_waitqueue_head (&sp->msi_wait); | ||
3804 | sp->msi_detected = 0; | ||
3805 | |||
3806 | saved64 = val64 = readq(&bar0->scheduled_int_ctrl); | ||
3807 | val64 |= SCHED_INT_CTRL_ONE_SHOT; | ||
3808 | val64 |= SCHED_INT_CTRL_TIMER_EN; | ||
3809 | val64 |= SCHED_INT_CTRL_INT2MSI(1); | ||
3810 | writeq(val64, &bar0->scheduled_int_ctrl); | ||
3811 | |||
3812 | wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10); | ||
3813 | |||
3814 | if (!sp->msi_detected) { | ||
3815 | /* MSI(X) test failed, go back to INTx mode */ | ||
3816 | DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated" | ||
3817 | "using MSI(X) during test\n", sp->dev->name, | ||
3818 | pci_name(pdev)); | ||
3819 | |||
3820 | err = -EOPNOTSUPP; | ||
3821 | } | ||
3822 | |||
3823 | free_irq(sp->entries[1].vector, sp); | ||
3824 | |||
3825 | writeq(saved64, &bar0->scheduled_int_ctrl); | ||
3826 | |||
3827 | return err; | ||
3828 | } | ||
3776 | /* ********************************************************* * | 3829 | /* ********************************************************* * |
3777 | * Functions defined below concern the OS part of the driver * | 3830 | * Functions defined below concern the OS part of the driver * |
3778 | * ********************************************************* */ | 3831 | * ********************************************************* */ |
@@ -3803,6 +3856,42 @@ static int s2io_open(struct net_device *dev) | |||
3803 | 3856 | ||
3804 | napi_enable(&sp->napi); | 3857 | napi_enable(&sp->napi); |
3805 | 3858 | ||
3859 | if (sp->intr_type == MSI_X) { | ||
3860 | int ret = s2io_enable_msi_x(sp); | ||
3861 | |||
3862 | if (!ret) { | ||
3863 | u16 msi_control; | ||
3864 | |||
3865 | ret = s2io_test_msi(sp); | ||
3866 | |||
3867 | /* rollback MSI-X, will re-enable during add_isr() */ | ||
3868 | kfree(sp->entries); | ||
3869 | sp->mac_control.stats_info->sw_stat.mem_freed += | ||
3870 | (MAX_REQUESTED_MSI_X * | ||
3871 | sizeof(struct msix_entry)); | ||
3872 | kfree(sp->s2io_entries); | ||
3873 | sp->mac_control.stats_info->sw_stat.mem_freed += | ||
3874 | (MAX_REQUESTED_MSI_X * | ||
3875 | sizeof(struct s2io_msix_entry)); | ||
3876 | sp->entries = NULL; | ||
3877 | sp->s2io_entries = NULL; | ||
3878 | |||
3879 | pci_read_config_word(sp->pdev, 0x42, &msi_control); | ||
3880 | msi_control &= 0xFFFE; /* Disable MSI */ | ||
3881 | pci_write_config_word(sp->pdev, 0x42, msi_control); | ||
3882 | |||
3883 | pci_disable_msix(sp->pdev); | ||
3884 | |||
3885 | } | ||
3886 | if (ret) { | ||
3887 | |||
3888 | DBG_PRINT(ERR_DBG, | ||
3889 | "%s: MSI-X requested but failed to enable\n", | ||
3890 | dev->name); | ||
3891 | sp->intr_type = INTA; | ||
3892 | } | ||
3893 | } | ||
3894 | |||
3806 | /* Initialize H/W and enable interrupts */ | 3895 | /* Initialize H/W and enable interrupts */ |
3807 | err = s2io_card_up(sp); | 3896 | err = s2io_card_up(sp); |
3808 | if (err) { | 3897 | if (err) { |