aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/s2io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r--drivers/net/s2io.c93
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 */
429S2IO_PARM_INT(rxsync_frequency, 3); 429S2IO_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) */
431S2IO_PARM_INT(intr_type, 0); 431S2IO_PARM_INT(intr_type, 2);
432/* Large receive offload feature */ 432/* Large receive offload feature */
433S2IO_PARM_INT(lro, 0); 433S2IO_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 */
3777static 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 */
3788static 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) {