diff options
author | Sivakumar Subramani <sivakumar.subramani@neterion.com> | 2007-09-15 16:11:34 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:50:24 -0400 |
commit | 8abc4d5b84f23edccf405aa591aae7d9b967e8d2 (patch) | |
tree | eed27797f8e5d0ee41f4aa56df5a57705262d2ce | |
parent | 28006c65a74403a8c4a1846aa7f08981e0d0b44a (diff) |
[S2IO]: Making MSIX as default intr_type
- Making MSIX as default intr_type
- Driver will test MSI-X by issuing test MSI-X vector and if fails it will
fallback to INTA
Signed-off-by: Sivakumar Subramani <sivakumar.subramani@neterion.com>
Signed-off-by: Ramkrishna Vepa <ram.vepa@neterion.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/s2io-regs.h | 2 | ||||
-rw-r--r-- | drivers/net/s2io.c | 93 | ||||
-rw-r--r-- | drivers/net/s2io.h | 6 |
3 files changed, 98 insertions, 3 deletions
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index cfa267914476..83e3e47a9e3d 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h | |||
@@ -220,7 +220,7 @@ struct XENA_dev_config { | |||
220 | u64 scheduled_int_ctrl; | 220 | u64 scheduled_int_ctrl; |
221 | #define SCHED_INT_CTRL_TIMER_EN BIT(0) | 221 | #define SCHED_INT_CTRL_TIMER_EN BIT(0) |
222 | #define SCHED_INT_CTRL_ONE_SHOT BIT(1) | 222 | #define SCHED_INT_CTRL_ONE_SHOT BIT(1) |
223 | #define SCHED_INT_CTRL_INT2MSI TBD | 223 | #define SCHED_INT_CTRL_INT2MSI(val) vBIT(val,10,6) |
224 | #define SCHED_INT_PERIOD TBD | 224 | #define SCHED_INT_PERIOD TBD |
225 | 225 | ||
226 | u64 txreqtimeout; | 226 | u64 txreqtimeout; |
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) { |
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 420fefb99188..62398fab2e96 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h | |||
@@ -412,6 +412,10 @@ struct config_param { | |||
412 | struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ | 412 | struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ |
413 | u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ | 413 | u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ |
414 | u64 tx_intr_type; | 414 | u64 tx_intr_type; |
415 | #define INTA 0 | ||
416 | #define MSI_X 2 | ||
417 | u8 intr_type; | ||
418 | |||
415 | /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ | 419 | /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ |
416 | 420 | ||
417 | /* Rx Side */ | 421 | /* Rx Side */ |
@@ -862,6 +866,8 @@ struct s2io_nic { | |||
862 | struct vlan_group *vlgrp; | 866 | struct vlan_group *vlgrp; |
863 | #define MSIX_FLG 0xA5 | 867 | #define MSIX_FLG 0xA5 |
864 | struct msix_entry *entries; | 868 | struct msix_entry *entries; |
869 | int msi_detected; | ||
870 | wait_queue_head_t msi_wait; | ||
865 | struct s2io_msix_entry *s2io_entries; | 871 | struct s2io_msix_entry *s2io_entries; |
866 | char desc[MAX_REQUESTED_MSI_X][25]; | 872 | char desc[MAX_REQUESTED_MSI_X][25]; |
867 | 873 | ||