diff options
author | Ravinandan Arakali <ravinandan.arakali@neterion.com> | 2005-10-04 06:41:24 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-04 06:41:24 -0400 |
commit | cc6e7c44f4b8ab13acf5521cd4b312848122179f (patch) | |
tree | 9a95e57befa59f6a50e5eb8ef4c9f8ae26816b87 | |
parent | d9e34325fd62310b7b49243d02b774f3ef2452db (diff) |
[PATCH] S2io: MSI/MSI-X support (runtime configurable)
This patch adds support for MSI/MSI-X feature to the driver. It is
a runtime parameter(for now, loadable parameter). Default is INTA.
Patch has been tested on IA64 platform with Xframe II adapter,
both of which support MSI-X feature. An improvement of about 7%
in throughput(both Tx and Rx) was observed and a reduction by 7%
in CPU utilization during Tx test.
Signed-off-by: Ravinandan Arakali <ravinandan.arakali@neterion.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/net/s2io.c | 543 | ||||
-rw-r--r-- | drivers/net/s2io.h | 50 |
2 files changed, 556 insertions, 37 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd451e099a4c..4b9f1828845e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -67,7 +67,7 @@ | |||
67 | 67 | ||
68 | /* S2io Driver name & version. */ | 68 | /* S2io Driver name & version. */ |
69 | static char s2io_driver_name[] = "Neterion"; | 69 | static char s2io_driver_name[] = "Neterion"; |
70 | static char s2io_driver_version[] = "Version 2.0.8.1"; | 70 | static char s2io_driver_version[] = "Version 2.0.9.1"; |
71 | 71 | ||
72 | static inline int RXD_IS_UP2DT(RxD_t *rxdp) | 72 | static inline int RXD_IS_UP2DT(RxD_t *rxdp) |
73 | { | 73 | { |
@@ -307,6 +307,8 @@ static unsigned int indicate_max_pkts; | |||
307 | #endif | 307 | #endif |
308 | /* Frequency of Rx desc syncs expressed as power of 2 */ | 308 | /* Frequency of Rx desc syncs expressed as power of 2 */ |
309 | static unsigned int rxsync_frequency = 3; | 309 | static unsigned int rxsync_frequency = 3; |
310 | /* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ | ||
311 | static unsigned int intr_type = 0; | ||
310 | 312 | ||
311 | /* | 313 | /* |
312 | * S2IO device table. | 314 | * S2IO device table. |
@@ -1396,8 +1398,13 @@ static int init_nic(struct s2io_nic *nic) | |||
1396 | writeq(val64, &bar0->rti_data1_mem); | 1398 | writeq(val64, &bar0->rti_data1_mem); |
1397 | 1399 | ||
1398 | val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | | 1400 | val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | |
1399 | RTI_DATA2_MEM_RX_UFC_B(0x2) | | 1401 | RTI_DATA2_MEM_RX_UFC_B(0x2) ; |
1400 | RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); | 1402 | if (nic->intr_type == MSI_X) |
1403 | val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ | ||
1404 | RTI_DATA2_MEM_RX_UFC_D(0x40)); | ||
1405 | else | ||
1406 | val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ | ||
1407 | RTI_DATA2_MEM_RX_UFC_D(0x80)); | ||
1401 | writeq(val64, &bar0->rti_data2_mem); | 1408 | writeq(val64, &bar0->rti_data2_mem); |
1402 | 1409 | ||
1403 | for (i = 0; i < config->rx_ring_num; i++) { | 1410 | for (i = 0; i < config->rx_ring_num; i++) { |
@@ -1507,17 +1514,15 @@ static int init_nic(struct s2io_nic *nic) | |||
1507 | #define LINK_UP_DOWN_INTERRUPT 1 | 1514 | #define LINK_UP_DOWN_INTERRUPT 1 |
1508 | #define MAC_RMAC_ERR_TIMER 2 | 1515 | #define MAC_RMAC_ERR_TIMER 2 |
1509 | 1516 | ||
1510 | #if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE) | ||
1511 | #define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER | ||
1512 | #else | ||
1513 | int s2io_link_fault_indication(nic_t *nic) | 1517 | int s2io_link_fault_indication(nic_t *nic) |
1514 | { | 1518 | { |
1519 | if (nic->intr_type != INTA) | ||
1520 | return MAC_RMAC_ERR_TIMER; | ||
1515 | if (nic->device_type == XFRAME_II_DEVICE) | 1521 | if (nic->device_type == XFRAME_II_DEVICE) |
1516 | return LINK_UP_DOWN_INTERRUPT; | 1522 | return LINK_UP_DOWN_INTERRUPT; |
1517 | else | 1523 | else |
1518 | return MAC_RMAC_ERR_TIMER; | 1524 | return MAC_RMAC_ERR_TIMER; |
1519 | } | 1525 | } |
1520 | #endif | ||
1521 | 1526 | ||
1522 | /** | 1527 | /** |
1523 | * en_dis_able_nic_intrs - Enable or Disable the interrupts | 1528 | * en_dis_able_nic_intrs - Enable or Disable the interrupts |
@@ -1941,11 +1946,14 @@ static int start_nic(struct s2io_nic *nic) | |||
1941 | } | 1946 | } |
1942 | 1947 | ||
1943 | /* Enable select interrupts */ | 1948 | /* Enable select interrupts */ |
1944 | interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; | 1949 | if (nic->intr_type != INTA) |
1945 | interruptible |= TX_PIC_INTR | RX_PIC_INTR; | 1950 | en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS); |
1946 | interruptible |= TX_MAC_INTR | RX_MAC_INTR; | 1951 | else { |
1947 | 1952 | interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; | |
1948 | en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); | 1953 | interruptible |= TX_PIC_INTR | RX_PIC_INTR; |
1954 | interruptible |= TX_MAC_INTR | RX_MAC_INTR; | ||
1955 | en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); | ||
1956 | } | ||
1949 | 1957 | ||
1950 | /* | 1958 | /* |
1951 | * With some switches, link might be already up at this point. | 1959 | * With some switches, link might be already up at this point. |
@@ -2633,11 +2641,11 @@ static void tx_intr_handler(fifo_info_t *fifo_data) | |||
2633 | err = txdlp->Control_1 & TXD_T_CODE; | 2641 | err = txdlp->Control_1 & TXD_T_CODE; |
2634 | if ((err >> 48) == 0xA) { | 2642 | if ((err >> 48) == 0xA) { |
2635 | DBG_PRINT(TX_DBG, "TxD returned due \ | 2643 | DBG_PRINT(TX_DBG, "TxD returned due \ |
2636 | to loss of link\n"); | 2644 | to loss of link\n"); |
2637 | } | 2645 | } |
2638 | else { | 2646 | else { |
2639 | DBG_PRINT(ERR_DBG, "***TxD error \ | 2647 | DBG_PRINT(ERR_DBG, "***TxD error \ |
2640 | %llx\n", err); | 2648 | %llx\n", err); |
2641 | } | 2649 | } |
2642 | } | 2650 | } |
2643 | 2651 | ||
@@ -2854,6 +2862,9 @@ void s2io_reset(nic_t * sp) | |||
2854 | /* Set swapper to enable I/O register access */ | 2862 | /* Set swapper to enable I/O register access */ |
2855 | s2io_set_swapper(sp); | 2863 | s2io_set_swapper(sp); |
2856 | 2864 | ||
2865 | /* Restore the MSIX table entries from local variables */ | ||
2866 | restore_xmsi_data(sp); | ||
2867 | |||
2857 | /* Clear certain PCI/PCI-X fields after reset */ | 2868 | /* Clear certain PCI/PCI-X fields after reset */ |
2858 | if (sp->device_type == XFRAME_II_DEVICE) { | 2869 | if (sp->device_type == XFRAME_II_DEVICE) { |
2859 | /* Clear parity err detect bit */ | 2870 | /* Clear parity err detect bit */ |
@@ -2983,8 +2994,9 @@ int s2io_set_swapper(nic_t * sp) | |||
2983 | SWAPPER_CTRL_RXD_W_FE | | 2994 | SWAPPER_CTRL_RXD_W_FE | |
2984 | SWAPPER_CTRL_RXF_W_FE | | 2995 | SWAPPER_CTRL_RXF_W_FE | |
2985 | SWAPPER_CTRL_XMSI_FE | | 2996 | SWAPPER_CTRL_XMSI_FE | |
2986 | SWAPPER_CTRL_XMSI_SE | | ||
2987 | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); | 2997 | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); |
2998 | if (nic->intr_type == INTA) | ||
2999 | val64 |= SWAPPER_CTRL_XMSI_SE; | ||
2988 | writeq(val64, &bar0->swapper_ctrl); | 3000 | writeq(val64, &bar0->swapper_ctrl); |
2989 | #else | 3001 | #else |
2990 | /* | 3002 | /* |
@@ -3005,8 +3017,9 @@ int s2io_set_swapper(nic_t * sp) | |||
3005 | SWAPPER_CTRL_RXD_W_SE | | 3017 | SWAPPER_CTRL_RXD_W_SE | |
3006 | SWAPPER_CTRL_RXF_W_FE | | 3018 | SWAPPER_CTRL_RXF_W_FE | |
3007 | SWAPPER_CTRL_XMSI_FE | | 3019 | SWAPPER_CTRL_XMSI_FE | |
3008 | SWAPPER_CTRL_XMSI_SE | | ||
3009 | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); | 3020 | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); |
3021 | if (sp->intr_type == INTA) | ||
3022 | val64 |= SWAPPER_CTRL_XMSI_SE; | ||
3010 | writeq(val64, &bar0->swapper_ctrl); | 3023 | writeq(val64, &bar0->swapper_ctrl); |
3011 | #endif | 3024 | #endif |
3012 | val64 = readq(&bar0->swapper_ctrl); | 3025 | val64 = readq(&bar0->swapper_ctrl); |
@@ -3028,6 +3041,201 @@ int s2io_set_swapper(nic_t * sp) | |||
3028 | return SUCCESS; | 3041 | return SUCCESS; |
3029 | } | 3042 | } |
3030 | 3043 | ||
3044 | int wait_for_msix_trans(nic_t *nic, int i) | ||
3045 | { | ||
3046 | XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; | ||
3047 | u64 val64; | ||
3048 | int ret = 0, cnt = 0; | ||
3049 | |||
3050 | do { | ||
3051 | val64 = readq(&bar0->xmsi_access); | ||
3052 | if (!(val64 & BIT(15))) | ||
3053 | break; | ||
3054 | mdelay(1); | ||
3055 | cnt++; | ||
3056 | } while(cnt < 5); | ||
3057 | if (cnt == 5) { | ||
3058 | DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); | ||
3059 | ret = 1; | ||
3060 | } | ||
3061 | |||
3062 | return ret; | ||
3063 | } | ||
3064 | |||
3065 | void restore_xmsi_data(nic_t *nic) | ||
3066 | { | ||
3067 | XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; | ||
3068 | u64 val64; | ||
3069 | int i; | ||
3070 | |||
3071 | for (i=0; i< MAX_REQUESTED_MSI_X; i++) { | ||
3072 | writeq(nic->msix_info[i].addr, &bar0->xmsi_address); | ||
3073 | writeq(nic->msix_info[i].data, &bar0->xmsi_data); | ||
3074 | val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6)); | ||
3075 | writeq(val64, &bar0->xmsi_access); | ||
3076 | if (wait_for_msix_trans(nic, i)) { | ||
3077 | DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); | ||
3078 | continue; | ||
3079 | } | ||
3080 | } | ||
3081 | } | ||
3082 | |||
3083 | void store_xmsi_data(nic_t *nic) | ||
3084 | { | ||
3085 | XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; | ||
3086 | u64 val64, addr, data; | ||
3087 | int i; | ||
3088 | |||
3089 | /* Store and display */ | ||
3090 | for (i=0; i< MAX_REQUESTED_MSI_X; i++) { | ||
3091 | val64 = (BIT(15) | vBIT(i, 26, 6)); | ||
3092 | writeq(val64, &bar0->xmsi_access); | ||
3093 | if (wait_for_msix_trans(nic, i)) { | ||
3094 | DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); | ||
3095 | continue; | ||
3096 | } | ||
3097 | addr = readq(&bar0->xmsi_address); | ||
3098 | data = readq(&bar0->xmsi_data); | ||
3099 | if (addr && data) { | ||
3100 | nic->msix_info[i].addr = addr; | ||
3101 | nic->msix_info[i].data = data; | ||
3102 | } | ||
3103 | } | ||
3104 | } | ||
3105 | |||
3106 | int s2io_enable_msi(nic_t *nic) | ||
3107 | { | ||
3108 | XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; | ||
3109 | u16 msi_ctrl, msg_val; | ||
3110 | struct config_param *config = &nic->config; | ||
3111 | struct net_device *dev = nic->dev; | ||
3112 | u64 val64, tx_mat, rx_mat; | ||
3113 | int i, err; | ||
3114 | |||
3115 | val64 = readq(&bar0->pic_control); | ||
3116 | val64 &= ~BIT(1); | ||
3117 | writeq(val64, &bar0->pic_control); | ||
3118 | |||
3119 | err = pci_enable_msi(nic->pdev); | ||
3120 | if (err) { | ||
3121 | DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n", | ||
3122 | nic->dev->name); | ||
3123 | return err; | ||
3124 | } | ||
3125 | |||
3126 | /* | ||
3127 | * Enable MSI and use MSI-1 in stead of the standard MSI-0 | ||
3128 | * for interrupt handling. | ||
3129 | */ | ||
3130 | pci_read_config_word(nic->pdev, 0x4c, &msg_val); | ||
3131 | msg_val ^= 0x1; | ||
3132 | pci_write_config_word(nic->pdev, 0x4c, msg_val); | ||
3133 | pci_read_config_word(nic->pdev, 0x4c, &msg_val); | ||
3134 | |||
3135 | pci_read_config_word(nic->pdev, 0x42, &msi_ctrl); | ||
3136 | msi_ctrl |= 0x10; | ||
3137 | pci_write_config_word(nic->pdev, 0x42, msi_ctrl); | ||
3138 | |||
3139 | /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */ | ||
3140 | tx_mat = readq(&bar0->tx_mat0_n[0]); | ||
3141 | for (i=0; i<config->tx_fifo_num; i++) { | ||
3142 | tx_mat |= TX_MAT_SET(i, 1); | ||
3143 | } | ||
3144 | writeq(tx_mat, &bar0->tx_mat0_n[0]); | ||
3145 | |||
3146 | rx_mat = readq(&bar0->rx_mat); | ||
3147 | for (i=0; i<config->rx_ring_num; i++) { | ||
3148 | rx_mat |= RX_MAT_SET(i, 1); | ||
3149 | } | ||
3150 | writeq(rx_mat, &bar0->rx_mat); | ||
3151 | |||
3152 | dev->irq = nic->pdev->irq; | ||
3153 | return 0; | ||
3154 | } | ||
3155 | |||
3156 | int s2io_enable_msi_x(nic_t *nic) | ||
3157 | { | ||
3158 | XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; | ||
3159 | u64 tx_mat, rx_mat; | ||
3160 | u16 msi_control; /* Temp variable */ | ||
3161 | int ret, i, j, msix_indx = 1; | ||
3162 | |||
3163 | nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), | ||
3164 | GFP_KERNEL); | ||
3165 | if (nic->entries == NULL) { | ||
3166 | DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); | ||
3167 | return -ENOMEM; | ||
3168 | } | ||
3169 | memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); | ||
3170 | |||
3171 | nic->s2io_entries = | ||
3172 | kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), | ||
3173 | GFP_KERNEL); | ||
3174 | if (nic->s2io_entries == NULL) { | ||
3175 | DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); | ||
3176 | kfree(nic->entries); | ||
3177 | return -ENOMEM; | ||
3178 | } | ||
3179 | memset(nic->s2io_entries, 0, | ||
3180 | MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); | ||
3181 | |||
3182 | for (i=0; i< MAX_REQUESTED_MSI_X; i++) { | ||
3183 | nic->entries[i].entry = i; | ||
3184 | nic->s2io_entries[i].entry = i; | ||
3185 | nic->s2io_entries[i].arg = NULL; | ||
3186 | nic->s2io_entries[i].in_use = 0; | ||
3187 | } | ||
3188 | |||
3189 | tx_mat = readq(&bar0->tx_mat0_n[0]); | ||
3190 | for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) { | ||
3191 | tx_mat |= TX_MAT_SET(i, msix_indx); | ||
3192 | nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i]; | ||
3193 | nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE; | ||
3194 | nic->s2io_entries[msix_indx].in_use = MSIX_FLG; | ||
3195 | } | ||
3196 | writeq(tx_mat, &bar0->tx_mat0_n[0]); | ||
3197 | |||
3198 | if (!nic->config.bimodal) { | ||
3199 | rx_mat = readq(&bar0->rx_mat); | ||
3200 | for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) { | ||
3201 | rx_mat |= RX_MAT_SET(j, msix_indx); | ||
3202 | nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; | ||
3203 | nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; | ||
3204 | nic->s2io_entries[msix_indx].in_use = MSIX_FLG; | ||
3205 | } | ||
3206 | writeq(rx_mat, &bar0->rx_mat); | ||
3207 | } else { | ||
3208 | tx_mat = readq(&bar0->tx_mat0_n[7]); | ||
3209 | for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) { | ||
3210 | tx_mat |= TX_MAT_SET(i, msix_indx); | ||
3211 | nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; | ||
3212 | nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; | ||
3213 | nic->s2io_entries[msix_indx].in_use = MSIX_FLG; | ||
3214 | } | ||
3215 | writeq(tx_mat, &bar0->tx_mat0_n[7]); | ||
3216 | } | ||
3217 | |||
3218 | ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X); | ||
3219 | if (ret) { | ||
3220 | DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); | ||
3221 | kfree(nic->entries); | ||
3222 | kfree(nic->s2io_entries); | ||
3223 | nic->entries = NULL; | ||
3224 | nic->s2io_entries = NULL; | ||
3225 | return -ENOMEM; | ||
3226 | } | ||
3227 | |||
3228 | /* | ||
3229 | * To enable MSI-X, MSI also needs to be enabled, due to a bug | ||
3230 | * in the herc NIC. (Temp change, needs to be removed later) | ||
3231 | */ | ||
3232 | pci_read_config_word(nic->pdev, 0x42, &msi_control); | ||
3233 | msi_control |= 0x1; /* Enable MSI */ | ||
3234 | pci_write_config_word(nic->pdev, 0x42, msi_control); | ||
3235 | |||
3236 | return 0; | ||
3237 | } | ||
3238 | |||
3031 | /* ********************************************************* * | 3239 | /* ********************************************************* * |
3032 | * Functions defined below concern the OS part of the driver * | 3240 | * Functions defined below concern the OS part of the driver * |
3033 | * ********************************************************* */ | 3241 | * ********************************************************* */ |
@@ -3048,6 +3256,8 @@ int s2io_open(struct net_device *dev) | |||
3048 | { | 3256 | { |
3049 | nic_t *sp = dev->priv; | 3257 | nic_t *sp = dev->priv; |
3050 | int err = 0; | 3258 | int err = 0; |
3259 | int i; | ||
3260 | u16 msi_control; /* Temp variable */ | ||
3051 | 3261 | ||
3052 | /* | 3262 | /* |
3053 | * Make sure you have link off by default every time | 3263 | * Make sure you have link off by default every time |
@@ -3064,13 +3274,55 @@ int s2io_open(struct net_device *dev) | |||
3064 | goto hw_init_failed; | 3274 | goto hw_init_failed; |
3065 | } | 3275 | } |
3066 | 3276 | ||
3277 | /* Store the values of the MSIX table in the nic_t structure */ | ||
3278 | store_xmsi_data(sp); | ||
3279 | |||
3067 | /* After proper initialization of H/W, register ISR */ | 3280 | /* After proper initialization of H/W, register ISR */ |
3068 | err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, | 3281 | if (sp->intr_type == MSI) { |
3069 | sp->name, dev); | 3282 | err = request_irq((int) sp->pdev->irq, s2io_msi_handle, |
3070 | if (err) { | 3283 | SA_SHIRQ, sp->name, dev); |
3071 | DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", | 3284 | if (err) { |
3072 | dev->name); | 3285 | DBG_PRINT(ERR_DBG, "%s: MSI registration \ |
3073 | goto isr_registration_failed; | 3286 | failed\n", dev->name); |
3287 | goto isr_registration_failed; | ||
3288 | } | ||
3289 | } | ||
3290 | if (sp->intr_type == MSI_X) { | ||
3291 | for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { | ||
3292 | if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) { | ||
3293 | sprintf(sp->desc1, "%s:MSI-X-%d-TX", | ||
3294 | dev->name, i); | ||
3295 | err = request_irq(sp->entries[i].vector, | ||
3296 | s2io_msix_fifo_handle, 0, sp->desc1, | ||
3297 | sp->s2io_entries[i].arg); | ||
3298 | DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1, | ||
3299 | sp->msix_info[i].addr); | ||
3300 | } else { | ||
3301 | sprintf(sp->desc2, "%s:MSI-X-%d-RX", | ||
3302 | dev->name, i); | ||
3303 | err = request_irq(sp->entries[i].vector, | ||
3304 | s2io_msix_ring_handle, 0, sp->desc2, | ||
3305 | sp->s2io_entries[i].arg); | ||
3306 | DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2, | ||
3307 | sp->msix_info[i].addr); | ||
3308 | } | ||
3309 | if (err) { | ||
3310 | DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \ | ||
3311 | failed\n", dev->name, i); | ||
3312 | DBG_PRINT(ERR_DBG, "Returned: %d\n", err); | ||
3313 | goto isr_registration_failed; | ||
3314 | } | ||
3315 | sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS; | ||
3316 | } | ||
3317 | } | ||
3318 | if (sp->intr_type == INTA) { | ||
3319 | err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, | ||
3320 | sp->name, dev); | ||
3321 | if (err) { | ||
3322 | DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", | ||
3323 | dev->name); | ||
3324 | goto isr_registration_failed; | ||
3325 | } | ||
3074 | } | 3326 | } |
3075 | 3327 | ||
3076 | if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { | 3328 | if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { |
@@ -3083,11 +3335,37 @@ int s2io_open(struct net_device *dev) | |||
3083 | return 0; | 3335 | return 0; |
3084 | 3336 | ||
3085 | setting_mac_address_failed: | 3337 | setting_mac_address_failed: |
3086 | free_irq(sp->pdev->irq, dev); | 3338 | if (sp->intr_type != MSI_X) |
3339 | free_irq(sp->pdev->irq, dev); | ||
3087 | isr_registration_failed: | 3340 | isr_registration_failed: |
3088 | del_timer_sync(&sp->alarm_timer); | 3341 | del_timer_sync(&sp->alarm_timer); |
3342 | if (sp->intr_type == MSI_X) { | ||
3343 | if (sp->device_type == XFRAME_II_DEVICE) { | ||
3344 | for (i=1; (sp->s2io_entries[i].in_use == | ||
3345 | MSIX_REGISTERED_SUCCESS); i++) { | ||
3346 | int vector = sp->entries[i].vector; | ||
3347 | void *arg = sp->s2io_entries[i].arg; | ||
3348 | |||
3349 | free_irq(vector, arg); | ||
3350 | } | ||
3351 | pci_disable_msix(sp->pdev); | ||
3352 | |||
3353 | /* Temp */ | ||
3354 | pci_read_config_word(sp->pdev, 0x42, &msi_control); | ||
3355 | msi_control &= 0xFFFE; /* Disable MSI */ | ||
3356 | pci_write_config_word(sp->pdev, 0x42, msi_control); | ||
3357 | } | ||
3358 | } | ||
3359 | else if (sp->intr_type == MSI) | ||
3360 | pci_disable_msi(sp->pdev); | ||
3089 | s2io_reset(sp); | 3361 | s2io_reset(sp); |
3090 | hw_init_failed: | 3362 | hw_init_failed: |
3363 | if (sp->intr_type == MSI_X) { | ||
3364 | if (sp->entries) | ||
3365 | kfree(sp->entries); | ||
3366 | if (sp->s2io_entries) | ||
3367 | kfree(sp->s2io_entries); | ||
3368 | } | ||
3091 | return err; | 3369 | return err; |
3092 | } | 3370 | } |
3093 | 3371 | ||
@@ -3107,12 +3385,35 @@ hw_init_failed: | |||
3107 | int s2io_close(struct net_device *dev) | 3385 | int s2io_close(struct net_device *dev) |
3108 | { | 3386 | { |
3109 | nic_t *sp = dev->priv; | 3387 | nic_t *sp = dev->priv; |
3388 | int i; | ||
3389 | u16 msi_control; | ||
3390 | |||
3110 | flush_scheduled_work(); | 3391 | flush_scheduled_work(); |
3111 | netif_stop_queue(dev); | 3392 | netif_stop_queue(dev); |
3112 | /* Reset card, kill tasklet and free Tx and Rx buffers. */ | 3393 | /* Reset card, kill tasklet and free Tx and Rx buffers. */ |
3113 | s2io_card_down(sp); | 3394 | s2io_card_down(sp); |
3114 | 3395 | ||
3115 | free_irq(sp->pdev->irq, dev); | 3396 | if (sp->intr_type == MSI_X) { |
3397 | if (sp->device_type == XFRAME_II_DEVICE) { | ||
3398 | for (i=1; (sp->s2io_entries[i].in_use == | ||
3399 | MSIX_REGISTERED_SUCCESS); i++) { | ||
3400 | int vector = sp->entries[i].vector; | ||
3401 | void *arg = sp->s2io_entries[i].arg; | ||
3402 | |||
3403 | free_irq(vector, arg); | ||
3404 | } | ||
3405 | pci_read_config_word(sp->pdev, 0x42, &msi_control); | ||
3406 | msi_control &= 0xFFFE; /* Disable MSI */ | ||
3407 | pci_write_config_word(sp->pdev, 0x42, msi_control); | ||
3408 | |||
3409 | pci_disable_msix(sp->pdev); | ||
3410 | } | ||
3411 | } | ||
3412 | else { | ||
3413 | free_irq(sp->pdev->irq, dev); | ||
3414 | if (sp->intr_type == MSI) | ||
3415 | pci_disable_msi(sp->pdev); | ||
3416 | } | ||
3116 | sp->device_close_flag = TRUE; /* Device is shut down. */ | 3417 | sp->device_close_flag = TRUE; /* Device is shut down. */ |
3117 | return 0; | 3418 | return 0; |
3118 | } | 3419 | } |
@@ -3278,6 +3579,104 @@ s2io_alarm_handle(unsigned long data) | |||
3278 | mod_timer(&sp->alarm_timer, jiffies + HZ / 2); | 3579 | mod_timer(&sp->alarm_timer, jiffies + HZ / 2); |
3279 | } | 3580 | } |
3280 | 3581 | ||
3582 | static irqreturn_t | ||
3583 | s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) | ||
3584 | { | ||
3585 | struct net_device *dev = (struct net_device *) dev_id; | ||
3586 | nic_t *sp = dev->priv; | ||
3587 | int i; | ||
3588 | int ret; | ||
3589 | mac_info_t *mac_control; | ||
3590 | struct config_param *config; | ||
3591 | |||
3592 | atomic_inc(&sp->isr_cnt); | ||
3593 | mac_control = &sp->mac_control; | ||
3594 | config = &sp->config; | ||
3595 | DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__); | ||
3596 | |||
3597 | /* If Intr is because of Rx Traffic */ | ||
3598 | for (i = 0; i < config->rx_ring_num; i++) | ||
3599 | rx_intr_handler(&mac_control->rings[i]); | ||
3600 | |||
3601 | /* If Intr is because of Tx Traffic */ | ||
3602 | for (i = 0; i < config->tx_fifo_num; i++) | ||
3603 | tx_intr_handler(&mac_control->fifos[i]); | ||
3604 | |||
3605 | /* | ||
3606 | * If the Rx buffer count is below the panic threshold then | ||
3607 | * reallocate the buffers from the interrupt handler itself, | ||
3608 | * else schedule a tasklet to reallocate the buffers. | ||
3609 | */ | ||
3610 | for (i = 0; i < config->rx_ring_num; i++) { | ||
3611 | int rxb_size = atomic_read(&sp->rx_bufs_left[i]); | ||
3612 | int level = rx_buffer_level(sp, rxb_size, i); | ||
3613 | |||
3614 | if ((level == PANIC) && (!TASKLET_IN_USE)) { | ||
3615 | DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); | ||
3616 | DBG_PRINT(INTR_DBG, "PANIC levels\n"); | ||
3617 | if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { | ||
3618 | DBG_PRINT(ERR_DBG, "%s:Out of memory", | ||
3619 | dev->name); | ||
3620 | DBG_PRINT(ERR_DBG, " in ISR!!\n"); | ||
3621 | clear_bit(0, (&sp->tasklet_status)); | ||
3622 | atomic_dec(&sp->isr_cnt); | ||
3623 | return IRQ_HANDLED; | ||
3624 | } | ||
3625 | clear_bit(0, (&sp->tasklet_status)); | ||
3626 | } else if (level == LOW) { | ||
3627 | tasklet_schedule(&sp->task); | ||
3628 | } | ||
3629 | } | ||
3630 | |||
3631 | atomic_dec(&sp->isr_cnt); | ||
3632 | return IRQ_HANDLED; | ||
3633 | } | ||
3634 | |||
3635 | static irqreturn_t | ||
3636 | s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) | ||
3637 | { | ||
3638 | ring_info_t *ring = (ring_info_t *)dev_id; | ||
3639 | nic_t *sp = ring->nic; | ||
3640 | int rxb_size, level, rng_n; | ||
3641 | |||
3642 | atomic_inc(&sp->isr_cnt); | ||
3643 | rx_intr_handler(ring); | ||
3644 | |||
3645 | rng_n = ring->ring_no; | ||
3646 | rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); | ||
3647 | level = rx_buffer_level(sp, rxb_size, rng_n); | ||
3648 | |||
3649 | if ((level == PANIC) && (!TASKLET_IN_USE)) { | ||
3650 | int ret; | ||
3651 | DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); | ||
3652 | DBG_PRINT(INTR_DBG, "PANIC levels\n"); | ||
3653 | if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { | ||
3654 | DBG_PRINT(ERR_DBG, "Out of memory in %s", | ||
3655 | __FUNCTION__); | ||
3656 | clear_bit(0, (&sp->tasklet_status)); | ||
3657 | return IRQ_HANDLED; | ||
3658 | } | ||
3659 | clear_bit(0, (&sp->tasklet_status)); | ||
3660 | } else if (level == LOW) { | ||
3661 | tasklet_schedule(&sp->task); | ||
3662 | } | ||
3663 | atomic_dec(&sp->isr_cnt); | ||
3664 | |||
3665 | return IRQ_HANDLED; | ||
3666 | } | ||
3667 | |||
3668 | static irqreturn_t | ||
3669 | s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs) | ||
3670 | { | ||
3671 | fifo_info_t *fifo = (fifo_info_t *)dev_id; | ||
3672 | nic_t *sp = fifo->nic; | ||
3673 | |||
3674 | atomic_inc(&sp->isr_cnt); | ||
3675 | tx_intr_handler(fifo); | ||
3676 | atomic_dec(&sp->isr_cnt); | ||
3677 | return IRQ_HANDLED; | ||
3678 | } | ||
3679 | |||
3281 | static void s2io_txpic_intr_handle(nic_t *sp) | 3680 | static void s2io_txpic_intr_handle(nic_t *sp) |
3282 | { | 3681 | { |
3283 | XENA_dev_config_t __iomem *bar0 = sp->bar0; | 3682 | XENA_dev_config_t __iomem *bar0 = sp->bar0; |
@@ -4932,7 +5331,7 @@ static void s2io_card_down(nic_t * sp) | |||
4932 | 5331 | ||
4933 | static int s2io_card_up(nic_t * sp) | 5332 | static int s2io_card_up(nic_t * sp) |
4934 | { | 5333 | { |
4935 | int i, ret; | 5334 | int i, ret = 0; |
4936 | mac_info_t *mac_control; | 5335 | mac_info_t *mac_control; |
4937 | struct config_param *config; | 5336 | struct config_param *config; |
4938 | struct net_device *dev = (struct net_device *) sp->dev; | 5337 | struct net_device *dev = (struct net_device *) sp->dev; |
@@ -4944,6 +5343,15 @@ static int s2io_card_up(nic_t * sp) | |||
4944 | return -ENODEV; | 5343 | return -ENODEV; |
4945 | } | 5344 | } |
4946 | 5345 | ||
5346 | if (sp->intr_type == MSI) | ||
5347 | ret = s2io_enable_msi(sp); | ||
5348 | else if (sp->intr_type == MSI_X) | ||
5349 | ret = s2io_enable_msi_x(sp); | ||
5350 | if (ret) { | ||
5351 | DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); | ||
5352 | sp->intr_type = INTA; | ||
5353 | } | ||
5354 | |||
4947 | /* | 5355 | /* |
4948 | * Initializing the Rx buffers. For now we are considering only 1 | 5356 | * Initializing the Rx buffers. For now we are considering only 1 |
4949 | * Rx ring and initializing buffers into 30 Rx blocks | 5357 | * Rx ring and initializing buffers into 30 Rx blocks |
@@ -5245,6 +5653,7 @@ module_param(bimodal, bool, 0); | |||
5245 | module_param(indicate_max_pkts, int, 0); | 5653 | module_param(indicate_max_pkts, int, 0); |
5246 | #endif | 5654 | #endif |
5247 | module_param(rxsync_frequency, int, 0); | 5655 | module_param(rxsync_frequency, int, 0); |
5656 | module_param(intr_type, int, 0); | ||
5248 | 5657 | ||
5249 | /** | 5658 | /** |
5250 | * s2io_init_nic - Initialization of the adapter . | 5659 | * s2io_init_nic - Initialization of the adapter . |
@@ -5274,9 +5683,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5274 | mac_info_t *mac_control; | 5683 | mac_info_t *mac_control; |
5275 | struct config_param *config; | 5684 | struct config_param *config; |
5276 | int mode; | 5685 | int mode; |
5686 | u8 dev_intr_type = intr_type; | ||
5277 | 5687 | ||
5278 | #ifdef CONFIG_S2IO_NAPI | 5688 | #ifdef CONFIG_S2IO_NAPI |
5279 | DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); | 5689 | if (dev_intr_type != INTA) { |
5690 | DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \ | ||
5691 | is enabled. Defaulting to INTA\n"); | ||
5692 | dev_intr_type = INTA; | ||
5693 | } | ||
5694 | else | ||
5695 | DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); | ||
5280 | #endif | 5696 | #endif |
5281 | 5697 | ||
5282 | if ((ret = pci_enable_device(pdev))) { | 5698 | if ((ret = pci_enable_device(pdev))) { |
@@ -5303,10 +5719,35 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5303 | return -ENOMEM; | 5719 | return -ENOMEM; |
5304 | } | 5720 | } |
5305 | 5721 | ||
5306 | if (pci_request_regions(pdev, s2io_driver_name)) { | 5722 | if ((dev_intr_type == MSI_X) && |
5307 | DBG_PRINT(ERR_DBG, "Request Regions failed\n"), | 5723 | ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && |
5308 | pci_disable_device(pdev); | 5724 | (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { |
5309 | return -ENODEV; | 5725 | DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \ |
5726 | Defaulting to INTA\n"); | ||
5727 | dev_intr_type = INTA; | ||
5728 | } | ||
5729 | if (dev_intr_type != MSI_X) { | ||
5730 | if (pci_request_regions(pdev, s2io_driver_name)) { | ||
5731 | DBG_PRINT(ERR_DBG, "Request Regions failed\n"), | ||
5732 | pci_disable_device(pdev); | ||
5733 | return -ENODEV; | ||
5734 | } | ||
5735 | } | ||
5736 | else { | ||
5737 | if (!(request_mem_region(pci_resource_start(pdev, 0), | ||
5738 | pci_resource_len(pdev, 0), s2io_driver_name))) { | ||
5739 | DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n"); | ||
5740 | pci_disable_device(pdev); | ||
5741 | return -ENODEV; | ||
5742 | } | ||
5743 | if (!(request_mem_region(pci_resource_start(pdev, 2), | ||
5744 | pci_resource_len(pdev, 2), s2io_driver_name))) { | ||
5745 | DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n"); | ||
5746 | release_mem_region(pci_resource_start(pdev, 0), | ||
5747 | pci_resource_len(pdev, 0)); | ||
5748 | pci_disable_device(pdev); | ||
5749 | return -ENODEV; | ||
5750 | } | ||
5310 | } | 5751 | } |
5311 | 5752 | ||
5312 | dev = alloc_etherdev(sizeof(nic_t)); | 5753 | dev = alloc_etherdev(sizeof(nic_t)); |
@@ -5329,6 +5770,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5329 | sp->pdev = pdev; | 5770 | sp->pdev = pdev; |
5330 | sp->high_dma_flag = dma_flag; | 5771 | sp->high_dma_flag = dma_flag; |
5331 | sp->device_enabled_once = FALSE; | 5772 | sp->device_enabled_once = FALSE; |
5773 | sp->intr_type = dev_intr_type; | ||
5332 | 5774 | ||
5333 | if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || | 5775 | if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || |
5334 | (pdev->device == PCI_DEVICE_ID_HERC_UNI)) | 5776 | (pdev->device == PCI_DEVICE_ID_HERC_UNI)) |
@@ -5336,6 +5778,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5336 | else | 5778 | else |
5337 | sp->device_type = XFRAME_I_DEVICE; | 5779 | sp->device_type = XFRAME_I_DEVICE; |
5338 | 5780 | ||
5781 | |||
5339 | /* Initialize some PCI/PCI-X fields of the NIC. */ | 5782 | /* Initialize some PCI/PCI-X fields of the NIC. */ |
5340 | s2io_init_pci(sp); | 5783 | s2io_init_pci(sp); |
5341 | 5784 | ||
@@ -5577,6 +6020,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5577 | #ifdef CONFIG_2BUFF_MODE | 6020 | #ifdef CONFIG_2BUFF_MODE |
5578 | DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); | 6021 | DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); |
5579 | #endif | 6022 | #endif |
6023 | switch(sp->intr_type) { | ||
6024 | case INTA: | ||
6025 | DBG_PRINT(ERR_DBG, ", Intr type INTA"); | ||
6026 | break; | ||
6027 | case MSI: | ||
6028 | DBG_PRINT(ERR_DBG, ", Intr type MSI"); | ||
6029 | break; | ||
6030 | case MSI_X: | ||
6031 | DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); | ||
6032 | break; | ||
6033 | } | ||
5580 | 6034 | ||
5581 | DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); | 6035 | DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); |
5582 | DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", | 6036 | DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", |
@@ -5601,6 +6055,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5601 | #ifdef CONFIG_2BUFF_MODE | 6055 | #ifdef CONFIG_2BUFF_MODE |
5602 | DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); | 6056 | DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); |
5603 | #endif | 6057 | #endif |
6058 | switch(sp->intr_type) { | ||
6059 | case INTA: | ||
6060 | DBG_PRINT(ERR_DBG, ", Intr type INTA"); | ||
6061 | break; | ||
6062 | case MSI: | ||
6063 | DBG_PRINT(ERR_DBG, ", Intr type MSI"); | ||
6064 | break; | ||
6065 | case MSI_X: | ||
6066 | DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); | ||
6067 | break; | ||
6068 | } | ||
5604 | DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); | 6069 | DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); |
5605 | DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", | 6070 | DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", |
5606 | sp->def_mac_addr[0].mac_addr[0], | 6071 | sp->def_mac_addr[0].mac_addr[0], |
@@ -5644,7 +6109,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
5644 | mem_alloc_failed: | 6109 | mem_alloc_failed: |
5645 | free_shared_mem(sp); | 6110 | free_shared_mem(sp); |
5646 | pci_disable_device(pdev); | 6111 | pci_disable_device(pdev); |
5647 | pci_release_regions(pdev); | 6112 | if (dev_intr_type != MSI_X) |
6113 | pci_release_regions(pdev); | ||
6114 | else { | ||
6115 | release_mem_region(pci_resource_start(pdev, 0), | ||
6116 | pci_resource_len(pdev, 0)); | ||
6117 | release_mem_region(pci_resource_start(pdev, 2), | ||
6118 | pci_resource_len(pdev, 2)); | ||
6119 | } | ||
5648 | pci_set_drvdata(pdev, NULL); | 6120 | pci_set_drvdata(pdev, NULL); |
5649 | free_netdev(dev); | 6121 | free_netdev(dev); |
5650 | 6122 | ||
@@ -5678,7 +6150,14 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) | |||
5678 | iounmap(sp->bar0); | 6150 | iounmap(sp->bar0); |
5679 | iounmap(sp->bar1); | 6151 | iounmap(sp->bar1); |
5680 | pci_disable_device(pdev); | 6152 | pci_disable_device(pdev); |
5681 | pci_release_regions(pdev); | 6153 | if (sp->intr_type != MSI_X) |
6154 | pci_release_regions(pdev); | ||
6155 | else { | ||
6156 | release_mem_region(pci_resource_start(pdev, 0), | ||
6157 | pci_resource_len(pdev, 0)); | ||
6158 | release_mem_region(pci_resource_start(pdev, 2), | ||
6159 | pci_resource_len(pdev, 2)); | ||
6160 | } | ||
5682 | pci_set_drvdata(pdev, NULL); | 6161 | pci_set_drvdata(pdev, NULL); |
5683 | free_netdev(dev); | 6162 | free_netdev(dev); |
5684 | } | 6163 | } |
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 89151cb52181..1cc24b56760e 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h | |||
@@ -652,6 +652,30 @@ typedef struct { | |||
652 | #define SMALL_BLK_CNT 30 | 652 | #define SMALL_BLK_CNT 30 |
653 | #define LARGE_BLK_CNT 100 | 653 | #define LARGE_BLK_CNT 100 |
654 | 654 | ||
655 | /* | ||
656 | * Structure to keep track of the MSI-X vectors and the corresponding | ||
657 | * argument registered against each vector | ||
658 | */ | ||
659 | #define MAX_REQUESTED_MSI_X 17 | ||
660 | struct s2io_msix_entry | ||
661 | { | ||
662 | u16 vector; | ||
663 | u16 entry; | ||
664 | void *arg; | ||
665 | |||
666 | u8 type; | ||
667 | #define MSIX_FIFO_TYPE 1 | ||
668 | #define MSIX_RING_TYPE 2 | ||
669 | |||
670 | u8 in_use; | ||
671 | #define MSIX_REGISTERED_SUCCESS 0xAA | ||
672 | }; | ||
673 | |||
674 | struct msix_info_st { | ||
675 | u64 addr; | ||
676 | u64 data; | ||
677 | }; | ||
678 | |||
655 | /* Structure representing one instance of the NIC */ | 679 | /* Structure representing one instance of the NIC */ |
656 | struct s2io_nic { | 680 | struct s2io_nic { |
657 | #ifdef CONFIG_S2IO_NAPI | 681 | #ifdef CONFIG_S2IO_NAPI |
@@ -719,13 +743,8 @@ struct s2io_nic { | |||
719 | * a schedule task that will set the correct Link state once the | 743 | * a schedule task that will set the correct Link state once the |
720 | * NIC's PHY has stabilized after a state change. | 744 | * NIC's PHY has stabilized after a state change. |
721 | */ | 745 | */ |
722 | #ifdef INIT_TQUEUE | ||
723 | struct tq_struct rst_timer_task; | ||
724 | struct tq_struct set_link_task; | ||
725 | #else | ||
726 | struct work_struct rst_timer_task; | 746 | struct work_struct rst_timer_task; |
727 | struct work_struct set_link_task; | 747 | struct work_struct set_link_task; |
728 | #endif | ||
729 | 748 | ||
730 | /* Flag that can be used to turn on or turn off the Rx checksum | 749 | /* Flag that can be used to turn on or turn off the Rx checksum |
731 | * offload feature. | 750 | * offload feature. |
@@ -748,10 +767,23 @@ struct s2io_nic { | |||
748 | atomic_t card_state; | 767 | atomic_t card_state; |
749 | volatile unsigned long link_state; | 768 | volatile unsigned long link_state; |
750 | struct vlan_group *vlgrp; | 769 | struct vlan_group *vlgrp; |
770 | #define MSIX_FLG 0xA5 | ||
771 | struct msix_entry *entries; | ||
772 | struct s2io_msix_entry *s2io_entries; | ||
773 | char desc1[35]; | ||
774 | char desc2[35]; | ||
775 | |||
776 | struct msix_info_st msix_info[0x3f]; | ||
777 | |||
751 | #define XFRAME_I_DEVICE 1 | 778 | #define XFRAME_I_DEVICE 1 |
752 | #define XFRAME_II_DEVICE 2 | 779 | #define XFRAME_II_DEVICE 2 |
753 | u8 device_type; | 780 | u8 device_type; |
754 | 781 | ||
782 | #define INTA 0 | ||
783 | #define MSI 1 | ||
784 | #define MSI_X 2 | ||
785 | u8 intr_type; | ||
786 | |||
755 | spinlock_t rx_lock; | 787 | spinlock_t rx_lock; |
756 | atomic_t isr_cnt; | 788 | atomic_t isr_cnt; |
757 | }; | 789 | }; |
@@ -886,6 +918,13 @@ static int s2io_poll(struct net_device *dev, int *budget); | |||
886 | static void s2io_init_pci(nic_t * sp); | 918 | static void s2io_init_pci(nic_t * sp); |
887 | int s2io_set_mac_addr(struct net_device *dev, u8 * addr); | 919 | int s2io_set_mac_addr(struct net_device *dev, u8 * addr); |
888 | static void s2io_alarm_handle(unsigned long data); | 920 | static void s2io_alarm_handle(unsigned long data); |
921 | static int s2io_enable_msi(nic_t *nic); | ||
922 | static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs); | ||
923 | static irqreturn_t | ||
924 | s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs); | ||
925 | static irqreturn_t | ||
926 | s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs); | ||
927 | int s2io_enable_msi_x(nic_t *nic); | ||
889 | static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); | 928 | static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); |
890 | static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); | 929 | static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); |
891 | static struct ethtool_ops netdev_ethtool_ops; | 930 | static struct ethtool_ops netdev_ethtool_ops; |
@@ -894,4 +933,5 @@ int s2io_set_swapper(nic_t * sp); | |||
894 | static void s2io_card_down(nic_t *nic); | 933 | static void s2io_card_down(nic_t *nic); |
895 | static int s2io_card_up(nic_t *nic); | 934 | static int s2io_card_up(nic_t *nic); |
896 | int get_xena_rev_id(struct pci_dev *pdev); | 935 | int get_xena_rev_id(struct pci_dev *pdev); |
936 | void restore_xmsi_data(nic_t *nic); | ||
897 | #endif /* _S2IO_H */ | 937 | #endif /* _S2IO_H */ |