diff options
author | Rasesh Mody <rmody@brocade.com> | 2011-08-08 16:21:39 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-08-11 07:30:13 -0700 |
commit | 078086f3c17fae8af6c077153773c4a10392ffbf (patch) | |
tree | 009c110c4f735f15eb149b49c8290e1d9e5c424a /drivers/net/ethernet/brocade/bna/bnad.c | |
parent | 6849c6b30772bb08ed52c3ec00e8245e70e25a2b (diff) | |
download | lwn-078086f3c17fae8af6c077153773c4a10392ffbf.tar.gz lwn-078086f3c17fae8af6c077153773c4a10392ffbf.zip |
bna: ENET and Tx Rx Redesign Enablement
Change details:
This patch contains additional structure and function definition changes
that are required to enable the new msgq/enet/txrx redesign introduced
by the previous 4 patches.
- structure and function definition changes to header files as a result
of Ethport, Enet, IOCEth, Tx, Rx redesign.
- ethtool changes to use new enet function and definitions
- Set number of Tx and Rx queues bassed on underlying hardware. Define
separate macros for maximum and supported numbers of Tx and Rx queues
based on underlying hardware. Take VLAN header into account for MTU
calculation. Default to INTx mode when pci_enable_msix() fails. Set a
bit in Rx poll routine, check and wait for that bit to be cleared in
the cleanup routine before proceeding.
- The TX and Rx coalesce settings are programmed in steps of 5 us. The value
that are not divisible by 5 are rounded to the next lower number. This was
causing the value os 1 to 4 to be rounded to 0, which is an invalid setting.
When creating Rx and Tx object, we are currently assigning the default
values of Rx and Tx coalescing_timeo. If these values are changed in the
driver to a different value, the change is lost during such operations as
MTU change. In order to avoid that, pass the configured value of
coalescing_timeo before Rx and Tx object creation. Fix
bnad_tx_coalescing_timeo_set() so it applies to all the Tx objects.
- Reorg uninitialization path in case of pci_probe failure.
- Hardware clock setup changes to pass asic generation, port modes and
asic mode as part firmware boot parameters to firmware.
- FW mailbox interface changes to defined asic specific mailbox interfaces.
h/w mailbox interfaces take 8-bit FIDs and 2-bit port id for owner. Cleaned
up mailbox definitions and usage for new and old HW. Eliminated usage of
ASIC ID. MSI-X vector assignment and programming done by firmware. Fixed
host offsets for CPE/RME queue registers.
- Implement polling mechanism for FW ready to have poll mechanism replaces
the current interrupt based FW READY method. The timer based poll routine
in IOC will query the ioc_fwstate register to see if there is a state
change in FW, and sends the READY event. Removed infrastructure needed to
support mbox READY event from fw as well as IOC code.
- Move FW init to HW init. Handle the case where PCI mapping goes away when
IOCPF state machine is waiting for semaphore.
- Add IOC mbox call back to client indicating that the command is sent.
Signed-off-by: Rasesh Mody <rmody@brocade.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/brocade/bna/bnad.c')
-rw-r--r-- | drivers/net/ethernet/brocade/bna/bnad.c | 643 |
1 files changed, 388 insertions, 255 deletions
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 8e35b2596f93..5ad07eab7bec 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -441,11 +441,15 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) struct bnad_skb_unmap *unmap_array; struct sk_buff *skb; u32 flags, unmap_cons; - u32 qid0 = ccb->rcb[0]->rxq->rxq_id; struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate; + struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl); + + set_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags); - if (!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)) + if (!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)) { + clear_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags); return 0; + } prefetch(bnad->netdev); BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl, @@ -455,10 +459,10 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) packets++; BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length)); - if (qid0 == cmpl->rxq_id) - rcb = ccb->rcb[0]; - else + if (bna_is_small_rxq(cmpl->rxq_id)) rcb = ccb->rcb[1]; + else + rcb = ccb->rcb[0]; unmap_q = rcb->unmap_q; unmap_array = unmap_q->unmap_array; @@ -518,12 +522,9 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) if (flags & BNA_CQ_EF_VLAN) __vlan_hwaccel_put_tag(skb, ntohs(cmpl->vlan_tag)); - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - struct bnad_rx_ctrl *rx_ctrl; - - rx_ctrl = (struct bnad_rx_ctrl *) ccb->ctrl; + if (skb->ip_summed == CHECKSUM_UNNECESSARY) napi_gro_receive(&rx_ctrl->napi, skb); - } else { + else { netif_receive_skb(skb); } @@ -545,6 +546,8 @@ next: bna_ib_ack(ccb->i_dbell, 0); } + clear_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags); + return packets; } @@ -611,7 +614,7 @@ bnad_msix_mbox_handler(int irq, void *data) bna_intr_status_get(&bnad->bna, intr_status); - if (BNA_IS_MBOX_ERR_INTR(intr_status)) + if (BNA_IS_MBOX_ERR_INTR(&bnad->bna, intr_status)) bna_mbox_handler(&bnad->bna, intr_status); spin_unlock_irqrestore(&bnad->bna_lock, flags); @@ -628,6 +631,7 @@ bnad_isr(int irq, void *data) struct bnad *bnad = (struct bnad *)data; struct bnad_rx_info *rx_info; struct bnad_rx_ctrl *rx_ctrl; + struct bna_tcb *tcb = NULL; if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))) return IRQ_NONE; @@ -639,7 +643,7 @@ bnad_isr(int irq, void *data) spin_lock_irqsave(&bnad->bna_lock, flags); - if (BNA_IS_MBOX_ERR_INTR(intr_status)) + if (BNA_IS_MBOX_ERR_INTR(&bnad->bna, intr_status)) bna_mbox_handler(&bnad->bna, intr_status); spin_unlock_irqrestore(&bnad->bna_lock, flags); @@ -650,8 +654,11 @@ bnad_isr(int irq, void *data) /* Process data interrupts */ /* Tx processing */ for (i = 0; i < bnad->num_tx; i++) { - for (j = 0; j < bnad->num_txq_per_tx; j++) - bnad_tx(bnad, bnad->tx_info[i].tcb[j]); + for (j = 0; j < bnad->num_txq_per_tx; j++) { + tcb = bnad->tx_info[i].tcb[j]; + if (tcb && test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) + bnad_tx(bnad, bnad->tx_info[i].tcb[j]); + } } /* Rx processing */ for (i = 0; i < bnad->num_rx; i++) { @@ -706,43 +713,49 @@ bnad_set_netdev_perm_addr(struct bnad *bnad) /* Callbacks */ void -bnad_cb_device_enable_mbox_intr(struct bnad *bnad) +bnad_cb_mbox_intr_enable(struct bnad *bnad) { bnad_enable_mbox_irq(bnad); } void -bnad_cb_device_disable_mbox_intr(struct bnad *bnad) +bnad_cb_mbox_intr_disable(struct bnad *bnad) { bnad_disable_mbox_irq(bnad); } void -bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status) +bnad_cb_ioceth_ready(struct bnad *bnad) +{ + bnad->bnad_completions.ioc_comp_status = BNA_CB_SUCCESS; + complete(&bnad->bnad_completions.ioc_comp); +} + +void +bnad_cb_ioceth_failed(struct bnad *bnad) { + bnad->bnad_completions.ioc_comp_status = BNA_CB_FAIL; complete(&bnad->bnad_completions.ioc_comp); - bnad->bnad_completions.ioc_comp_status = status; } void -bnad_cb_device_disabled(struct bnad *bnad, enum bna_cb_status status) +bnad_cb_ioceth_disabled(struct bnad *bnad) { + bnad->bnad_completions.ioc_comp_status = BNA_CB_SUCCESS; complete(&bnad->bnad_completions.ioc_comp); - bnad->bnad_completions.ioc_comp_status = status; } static void -bnad_cb_port_disabled(void *arg, enum bna_cb_status status) +bnad_cb_enet_disabled(void *arg) { struct bnad *bnad = (struct bnad *)arg; - complete(&bnad->bnad_completions.port_comp); - netif_carrier_off(bnad->netdev); + complete(&bnad->bnad_completions.enet_comp); } void -bnad_cb_port_link_status(struct bnad *bnad, +bnad_cb_ethport_link_status(struct bnad *bnad, enum bna_link_status link_status) { bool link_up = 0; @@ -750,34 +763,60 @@ bnad_cb_port_link_status(struct bnad *bnad, link_up = (link_status == BNA_LINK_UP) || (link_status == BNA_CEE_UP); if (link_status == BNA_CEE_UP) { + if (!test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) + BNAD_UPDATE_CTR(bnad, cee_toggle); set_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags); - BNAD_UPDATE_CTR(bnad, cee_up); - } else + } else { + if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) + BNAD_UPDATE_CTR(bnad, cee_toggle); clear_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags); + } if (link_up) { if (!netif_carrier_ok(bnad->netdev)) { - struct bna_tcb *tcb = bnad->tx_info[0].tcb[0]; - if (!tcb) - return; - pr_warn("bna: %s link up\n", + uint tx_id, tcb_id; + printk(KERN_WARNING "bna: %s link up\n", bnad->netdev->name); netif_carrier_on(bnad->netdev); BNAD_UPDATE_CTR(bnad, link_toggle); - if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) { - /* Force an immediate Transmit Schedule */ - pr_info("bna: %s TX_STARTED\n", - bnad->netdev->name); - netif_wake_queue(bnad->netdev); - BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); - } else { - netif_stop_queue(bnad->netdev); - BNAD_UPDATE_CTR(bnad, netif_queue_stop); + for (tx_id = 0; tx_id < bnad->num_tx; tx_id++) { + for (tcb_id = 0; tcb_id < bnad->num_txq_per_tx; + tcb_id++) { + struct bna_tcb *tcb = + bnad->tx_info[tx_id].tcb[tcb_id]; + u32 txq_id; + if (!tcb) + continue; + + txq_id = tcb->id; + + if (test_bit(BNAD_TXQ_TX_STARTED, + &tcb->flags)) { + /* + * Force an immediate + * Transmit Schedule */ + printk(KERN_INFO "bna: %s %d " + "TXQ_STARTED\n", + bnad->netdev->name, + txq_id); + netif_wake_subqueue( + bnad->netdev, + txq_id); + BNAD_UPDATE_CTR(bnad, + netif_queue_wakeup); + } else { + netif_stop_subqueue( + bnad->netdev, + txq_id); + BNAD_UPDATE_CTR(bnad, + netif_queue_stop); + } + } } } } else { if (netif_carrier_ok(bnad->netdev)) { - pr_warn("bna: %s link down\n", + printk(KERN_WARNING "bna: %s link down\n", bnad->netdev->name); netif_carrier_off(bnad->netdev); BNAD_UPDATE_CTR(bnad, link_toggle); @@ -786,8 +825,7 @@ bnad_cb_port_link_status(struct bnad *bnad, } static void -bnad_cb_tx_disabled(void *arg, struct bna_tx *tx, - enum bna_cb_status status) +bnad_cb_tx_disabled(void *arg, struct bna_tx *tx) { struct bnad *bnad = (struct bnad *)arg; @@ -864,108 +902,166 @@ bnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb) } static void -bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb) +bnad_cb_tx_stall(struct bnad *bnad, struct bna_tx *tx) { struct bnad_tx_info *tx_info = - (struct bnad_tx_info *)tcb->txq->tx->priv; - - if (tx_info != &bnad->tx_info[0]) - return; + (struct bnad_tx_info *)tx->priv; + struct bna_tcb *tcb; + u32 txq_id; + int i; - clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); - netif_stop_queue(bnad->netdev); - pr_info("bna: %s TX_STOPPED\n", bnad->netdev->name); + for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { + tcb = tx_info->tcb[i]; + if (!tcb) + continue; + txq_id = tcb->id; + clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); + netif_stop_subqueue(bnad->netdev, txq_id); + printk(KERN_INFO "bna: %s %d TXQ_STOPPED\n", + bnad->netdev->name, txq_id); + } } static void -bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb) +bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx) { - struct bnad_unmap_q *unmap_q = tcb->unmap_q; + struct bnad_tx_info *tx_info = (struct bnad_tx_info *)tx->priv; + struct bna_tcb *tcb; + struct bnad_unmap_q *unmap_q; + u32 txq_id; + int i; - if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) - return; + for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { + tcb = tx_info->tcb[i]; + if (!tcb) + continue; + txq_id = tcb->id; - clear_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags); + unmap_q = tcb->unmap_q; - while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) - cpu_relax(); + if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) + continue; - bnad_free_all_txbufs(bnad, tcb); + while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) + cpu_relax(); - unmap_q->producer_index = 0; - unmap_q->consumer_index = 0; + bnad_free_all_txbufs(bnad, tcb); - smp_mb__before_clear_bit(); - clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); + unmap_q->producer_index = 0; + unmap_q->consumer_index = 0; + + smp_mb__before_clear_bit(); + clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); + + set_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); + + if (netif_carrier_ok(bnad->netdev)) { + printk(KERN_INFO "bna: %s %d TXQ_STARTED\n", + bnad->netdev->name, txq_id); + netif_wake_subqueue(bnad->netdev, txq_id); + BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); + } + } /* - * Workaround for first device enable failure & we + * Workaround for first ioceth enable failure & we * get a 0 MAC address. We try to get the MAC address * again here. */ if (is_zero_ether_addr(&bnad->perm_addr.mac[0])) { - bna_port_mac_get(&bnad->bna.port, &bnad->perm_addr); + bna_enet_perm_mac_get(&bnad->bna.enet, &bnad->perm_addr); bnad_set_netdev_perm_addr(bnad); } - - set_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); - - if (netif_carrier_ok(bnad->netdev)) { - pr_info("bna: %s TX_STARTED\n", bnad->netdev->name); - netif_wake_queue(bnad->netdev); - BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); - } } static void -bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb) +bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx) { - /* Delay only once for the whole Tx Path Shutdown */ - if (!test_and_set_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags)) - mdelay(BNAD_TXRX_SYNC_MDELAY); + struct bnad_tx_info *tx_info = (struct bnad_tx_info *)tx->priv; + struct bna_tcb *tcb; + int i; + + for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { + tcb = tx_info->tcb[i]; + if (!tcb) + continue; + } + + mdelay(BNAD_TXRX_SYNC_MDELAY); + bna_tx_cleanup_complete(tx); } static void -bnad_cb_rx_cleanup(struct bnad *bnad, - struct bna_ccb *ccb) +bnad_cb_rx_cleanup(struct bnad *bnad, struct bna_rx *rx) { - clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags); + struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv; + struct bna_ccb *ccb; + struct bnad_rx_ctrl *rx_ctrl; + int i; + + mdelay(BNAD_TXRX_SYNC_MDELAY); + + for (i = 0; i < BNAD_MAX_RXPS_PER_RX; i++) { + rx_ctrl = &rx_info->rx_ctrl[i]; + ccb = rx_ctrl->ccb; + if (!ccb) + continue; + + clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags); + + if (ccb->rcb[1]) + clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags); - if (ccb->rcb[1]) - clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags); + while (test_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags)) + cpu_relax(); + } - if (!test_and_set_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags)) - mdelay(BNAD_TXRX_SYNC_MDELAY); + bna_rx_cleanup_complete(rx); } static void -bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb) +bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx) { - struct bnad_unmap_q *unmap_q = rcb->unmap_q; - - clear_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags); - - if (rcb == rcb->cq->ccb->rcb[0]) - bnad_cq_cmpl_init(bnad, rcb->cq->ccb); + struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv; + struct bna_ccb *ccb; + struct bna_rcb *rcb; + struct bnad_rx_ctrl *rx_ctrl; + struct bnad_unmap_q *unmap_q; + int i; + int j; - bnad_free_all_rxbufs(bnad, rcb); + for (i = 0; i < BNAD_MAX_RXPS_PER_RX; i++) { + rx_ctrl = &rx_info->rx_ctrl[i]; + ccb = rx_ctrl->ccb; + if (!ccb) + continue; - set_bit(BNAD_RXQ_STARTED, &rcb->flags); + bnad_cq_cmpl_init(bnad, ccb); - /* Now allocate & post buffers for this RCB */ - /* !!Allocation in callback context */ - if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) { - if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth) - >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT) - bnad_alloc_n_post_rxbufs(bnad, rcb); - smp_mb__before_clear_bit(); - clear_bit(BNAD_RXQ_REFILL, &rcb->flags); + for (j = 0; j < BNAD_MAX_RXQ_PER_RXP; j++) { + rcb = ccb->rcb[j]; + if (!rcb) + continue; + bnad_free_all_rxbufs(bnad, rcb); + + set_bit(BNAD_RXQ_STARTED, &rcb->flags); + unmap_q = rcb->unmap_q; + + /* Now allocate & post buffers for this RCB */ + /* !!Allocation in callback context */ + if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) { + if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth) + >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT) + bnad_alloc_n_post_rxbufs(bnad, rcb); + smp_mb__before_clear_bit(); + clear_bit(BNAD_RXQ_REFILL, &rcb->flags); + } + } } } static void -bnad_cb_rx_disabled(void *arg, struct bna_rx *rx, - enum bna_cb_status status) +bnad_cb_rx_disabled(void *arg, struct bna_rx *rx) { struct bnad *bnad = (struct bnad *)arg; @@ -973,10 +1069,9 @@ bnad_cb_rx_disabled(void *arg, struct bna_rx *rx, } static void -bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx, - enum bna_cb_status status) +bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx) { - bnad->bnad_completions.mcast_comp_status = status; + bnad->bnad_completions.mcast_comp_status = BNA_CB_SUCCESS; complete(&bnad->bnad_completions.mcast_comp); } @@ -995,6 +1090,13 @@ bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status, jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ)); } +static void +bnad_cb_enet_mtu_set(struct bnad *bnad) +{ + bnad->bnad_completions.mtu_comp_status = BNA_CB_SUCCESS; + complete(&bnad->bnad_completions.mtu_comp); +} + /* Resource allocation, free functions */ static void @@ -1073,23 +1175,17 @@ err_return: /* Free IRQ for Mailbox */ static void -bnad_mbox_irq_free(struct bnad *bnad, - struct bna_intr_info *intr_info) +bnad_mbox_irq_free(struct bnad *bnad) { int irq; unsigned long flags; - if (intr_info->idl == NULL) - return; - spin_lock_irqsave(&bnad->bna_lock, flags); bnad_disable_mbox_irq(bnad); spin_unlock_irqrestore(&bnad->bna_lock, flags); irq = BNAD_GET_MBOX_IRQ(bnad); free_irq(irq, bnad); - - kfree(intr_info->idl); } /* @@ -1098,32 +1194,22 @@ bnad_mbox_irq_free(struct bnad *bnad, * from bna */ static int -bnad_mbox_irq_alloc(struct bnad *bnad, - struct bna_intr_info *intr_info) +bnad_mbox_irq_alloc(struct bnad *bnad) { int err = 0; unsigned long irq_flags, flags; u32 irq; irq_handler_t irq_handler; - /* Mbox should use only 1 vector */ - - intr_info->idl = kzalloc(sizeof(*(intr_info->idl)), GFP_KERNEL); - if (!intr_info->idl) - return -ENOMEM; - spin_lock_irqsave(&bnad->bna_lock, flags); if (bnad->cfg_flags & BNAD_CF_MSIX) { irq_handler = (irq_handler_t)bnad_msix_mbox_handler; irq = bnad->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector; irq_flags = 0; - intr_info->intr_type = BNA_INTR_T_MSIX; - intr_info->idl[0].vector = BNAD_MAILBOX_MSIX_INDEX; } else { irq_handler = (irq_handler_t)bnad_isr; irq = bnad->pcidev->irq; irq_flags = IRQF_SHARED; - intr_info->intr_type = BNA_INTR_T_INTX; } spin_unlock_irqrestore(&bnad->bna_lock, flags); @@ -1140,11 +1226,6 @@ bnad_mbox_irq_alloc(struct bnad *bnad, err = request_irq(irq, irq_handler, irq_flags, bnad->mbox_irq_name, bnad); - if (err) { - kfree(intr_info->idl); - intr_info->idl = NULL; - } - return err; } @@ -1158,7 +1239,7 @@ bnad_txrx_irq_free(struct bnad *bnad, struct bna_intr_info *intr_info) /* Allocates Interrupt Descriptor List for MSIX/INT-X vectors */ static int bnad_txrx_irq_alloc(struct bnad *bnad, enum bnad_intr_source src, - uint txrx_id, struct bna_intr_info *intr_info) + u32 txrx_id, struct bna_intr_info *intr_info) { int i, vector_start = 0; u32 cfg_flags; @@ -1241,7 +1322,7 @@ bnad_tx_msix_unregister(struct bnad *bnad, struct bnad_tx_info *tx_info, */ static int bnad_tx_msix_register(struct bnad *bnad, struct bnad_tx_info *tx_info, - uint tx_id, int num_txqs) + u32 tx_id, int num_txqs) { int i; int err; @@ -1294,7 +1375,7 @@ bnad_rx_msix_unregister(struct bnad *bnad, struct bnad_rx_info *rx_info, */ static int bnad_rx_msix_register(struct bnad *bnad, struct bnad_rx_info *rx_info, - uint rx_id, int num_rxps) + u32 rx_id, int num_rxps) { int i; int err; @@ -1338,7 +1419,7 @@ bnad_tx_res_free(struct bnad *bnad, struct bna_res_info *res_info) /* Allocates memory and interrupt resources for Tx object */ static int bnad_tx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info, - uint tx_id) + u32 tx_id) { int i, err = 0; @@ -1407,7 +1488,7 @@ bnad_ioc_timeout(unsigned long data) unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_ioc_timeout((void *) &bnad->bna.device.ioc); + bfa_nw_ioc_timeout((void *) &bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1418,7 +1499,7 @@ bnad_ioc_hb_check(unsigned long data) unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_ioc_hb_check((void *) &bnad->bna.device.ioc); + bfa_nw_ioc_hb_check((void *) &bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1429,7 +1510,7 @@ bnad_iocpf_timeout(unsigned long data) unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_iocpf_timeout((void *) &bnad->bna.device.ioc); + bfa_nw_iocpf_timeout((void *) &bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1440,7 +1521,7 @@ bnad_iocpf_sem_timeout(unsigned long data) unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.device.ioc); + bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1499,7 +1580,7 @@ bnad_stats_timeout(unsigned long data) return; spin_lock_irqsave(&bnad->bna_lock, flags); - bna_stats_get(&bnad->bna); + bna_hw_stats_get(&bnad->bna); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1632,7 +1713,7 @@ bnad_napi_disable(struct bnad *bnad, u32 rx_id) /* Should be held with conf_lock held */ void -bnad_cleanup_tx(struct bnad *bnad, uint tx_id) +bnad_cleanup_tx(struct bnad *bnad, u32 tx_id) { struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id]; struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0]; @@ -1656,6 +1737,7 @@ bnad_cleanup_tx(struct bnad *bnad, uint tx_id) spin_unlock_irqrestore(&bnad->bna_lock, flags); tx_info->tx = NULL; + tx_info->tx_id = 0; if (0 == tx_id) tasklet_kill(&bnad->tx_free_tasklet); @@ -1665,7 +1747,7 @@ bnad_cleanup_tx(struct bnad *bnad, uint tx_id) /* Should be held with conf_lock held */ int -bnad_setup_tx(struct bnad *bnad, uint tx_id) +bnad_setup_tx(struct bnad *bnad, u32 tx_id) { int err; struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id]; @@ -1677,10 +1759,13 @@ bnad_setup_tx(struct bnad *bnad, uint tx_id) struct bna_tx *tx; unsigned long flags; + tx_info->tx_id = tx_id; + /* Initialize the Tx object configuration */ tx_config->num_txq = bnad->num_txq_per_tx; tx_config->txq_depth = bnad->txq_depth; tx_config->tx_type = BNA_TX_T_REGULAR; + tx_config->coalescing_timeo = bnad->tx_coalescing_timeo; /* Initialize the tx event handlers */ tx_cbfn.tcb_setup_cbfn = bnad_cb_tcb_setup; @@ -1741,14 +1826,15 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config) { rx_config->rx_type = BNA_RX_T_REGULAR; rx_config->num_paths = bnad->num_rxp_per_rx; + rx_config->coalescing_timeo = bnad->rx_coalescing_timeo; if (bnad->num_rxp_per_rx > 1) { rx_config->rss_status = BNA_STATUS_T_ENABLED; rx_config->rss_config.hash_type = - (BFI_RSS_T_V4_TCP | - BFI_RSS_T_V6_TCP | - BFI_RSS_T_V4_IP | - BFI_RSS_T_V6_IP); + (BFI_ENET_RSS_IPV6 | + BFI_ENET_RSS_IPV6_TCP | + BFI_ENET_RSS_IPV4 | + BFI_ENET_RSS_IPV4_TCP); rx_config->rss_config.hash_mask = bnad->num_rxp_per_rx - 1; get_random_bytes(rx_config->rss_config.toeplitz_hash_key, @@ -1768,7 +1854,7 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config) /* Called with mutex_lock(&bnad->conf_mutex) held */ void -bnad_cleanup_rx(struct bnad *bnad, uint rx_id) +bnad_cleanup_rx(struct bnad *bnad, u32 rx_id) { struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id]; struct bna_rx_config *rx_config = &bnad->rx_config[rx_id]; @@ -1811,7 +1897,7 @@ bnad_cleanup_rx(struct bnad *bnad, uint rx_id) /* Called with mutex_lock(&bnad->conf_mutex) held */ int -bnad_setup_rx(struct bnad *bnad, uint rx_id) +bnad_setup_rx(struct bnad *bnad, u32 rx_id) { int err; struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id]; @@ -1823,6 +1909,8 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id) struct bna_rx *rx; unsigned long flags; + rx_info->rx_id = rx_id; + /* Initialize the Rx object configuration */ bnad_init_rx_config(bnad, rx_config); @@ -1978,7 +2066,7 @@ bnad_restore_vlans(struct bnad *bnad, u32 rx_id) u16 vid; unsigned long flags; - BUG_ON(!(VLAN_N_VID == (BFI_MAX_VLAN + 1))); + BUG_ON(!(VLAN_N_VID == BFI_ENET_VLAN_ID_MAX)); for_each_set_bit(vid, bnad->active_vlans, VLAN_N_VID) { spin_lock_irqsave(&bnad->bna_lock, flags); @@ -2031,11 +2119,11 @@ bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats) void bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats) { - struct bfi_ll_stats_mac *mac_stats; - u64 bmap; + struct bfi_enet_stats_mac *mac_stats; + u32 bmap; int i; - mac_stats = &bnad->stats.bna_stats->hw_stats->mac_stats; + mac_stats = &bnad->stats.bna_stats->hw_stats.mac_stats; stats->rx_errors = mac_stats->rx_fcs_error + mac_stats->rx_alignment_error + mac_stats->rx_frame_length_error + mac_stats->rx_code_error + @@ -2054,13 +2142,12 @@ bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats) stats->rx_crc_errors = mac_stats->rx_fcs_error; stats->rx_frame_errors = mac_stats->rx_alignment_error; /* recv'r fifo overrun */ - bmap = (u64)bnad->stats.bna_stats->rxf_bmap[0] | - ((u64)bnad->stats.bna_stats->rxf_bmap[1] << 32); - for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) { + bmap = bna_rx_rid_mask(&bnad->bna); + for (i = 0; bmap; i++) { if (bmap & 1) { stats->rx_fifo_errors += bnad->stats.bna_stats-> - hw_stats->rxf_stats[i].frame_drops; + hw_stats.rxf_stats[i].frame_drops; break; } bmap >>= 1; @@ -2158,7 +2245,7 @@ bnad_q_num_init(struct bnad *bnad) * Called with bnad->bna_lock held b'cos of cfg_flags access */ static void -bnad_q_num_adjust(struct bnad *bnad, int msix_vectors) +bnad_q_num_adjust(struct bnad *bnad, int msix_vectors, int temp) { bnad->num_txq_per_tx = 1; if ((msix_vectors >= (bnad->num_tx * bnad->num_txq_per_tx) + @@ -2171,76 +2258,72 @@ bnad_q_num_adjust(struct bnad *bnad, int msix_vectors) bnad->num_rxp_per_rx = 1; } -/* Enable / disable device */ -static void -bnad_device_disable(struct bnad *bnad) +/* Enable / disable ioceth */ +static int +bnad_ioceth_disable(struct bnad *bnad) { unsigned long flags; - - init_completion(&bnad->bnad_completions.ioc_comp); + int err = 0; spin_lock_irqsave(&bnad->bna_lock, flags); - bna_device_disable(&bnad->bna.device, BNA_HARD_CLEANUP); + init_completion(&bnad->bnad_completions.ioc_comp); + bna_ioceth_disable(&bnad->bna.ioceth, BNA_HARD_CLEANUP); spin_unlock_irqrestore(&bnad->bna_lock, flags); - wait_for_completion(&bnad->bnad_completions.ioc_comp); + wait_for_completion_timeout(&bnad->bnad_completions.ioc_comp, + msecs_to_jiffies(BNAD_IOCETH_TIMEOUT)); + + err = bnad->bnad_completions.ioc_comp_status; + return err; } static int -bnad_device_enable(struct bnad *bnad) +bnad_ioceth_enable(struct bnad *bnad) { int err = 0; unsigned long flags; - init_completion(&bnad->bnad_completions.ioc_comp); - spin_lock_irqsave(&bnad->bna_lock, flags); - bna_device_enable(&bnad->bna.device); + init_completion(&bnad->bnad_completions.ioc_comp); + bnad->bnad_completions.ioc_comp_status = BNA_CB_WAITING; + bna_ioceth_enable(&bnad->bna.ioceth); spin_unlock_irqrestore(&bnad->bna_lock, flags); - wait_for_completion(&bnad->bnad_completions.ioc_comp); + wait_for_completion_timeout(&bnad->bnad_completions.ioc_comp, + msecs_to_jiffies(BNAD_IOCETH_TIMEOUT)); - if (bnad->bnad_completions.ioc_comp_status) - err = bnad->bnad_completions.ioc_comp_status; + err = bnad->bnad_completions.ioc_comp_status; return err; } /* Free BNA resources */ static void -bnad_res_free(struct bnad *bnad) +bnad_res_free(struct bnad *bnad, struct bna_res_info *res_info, + u32 res_val_max) { int i; - struct bna_res_info *res_info = &bnad->res_info[0]; - for (i = 0; i < BNA_RES_T_MAX; i++) { - if (res_info[i].res_type == BNA_RES_T_MEM) - bnad_mem_free(bnad, &res_info[i].res_u.mem_info); - else - bnad_mbox_irq_free(bnad, &res_info[i].res_u.intr_info); - } + for (i = 0; i < res_val_max; i++) + bnad_mem_free(bnad, &res_info[i].res_u.mem_info); } /* Allocates memory and interrupt resources for BNA */ static int -bnad_res_alloc(struct bnad *bnad) +bnad_res_alloc(struct bnad *bnad, struct bna_res_info *res_info, + u32 res_val_max) { int i, err; - struct bna_res_info *res_info = &bnad->res_info[0]; - for (i = 0; i < BNA_RES_T_MAX; i++) { - if (res_info[i].res_type == BNA_RES_T_MEM) - err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info); - else - err = bnad_mbox_irq_alloc(bnad, - &res_info[i].res_u.intr_info); + for (i = 0; i < res_val_max; i++) { + err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info); if (err) goto err_return; } return 0; err_return: - bnad_res_free(bnad); + bnad_res_free(bnad, res_info, res_val_max); return err; } @@ -2276,7 +2359,7 @@ bnad_enable_msix(struct bnad *bnad) spin_lock_irqsave(&bnad->bna_lock, flags); /* ret = #of vectors that we got */ - bnad_q_num_adjust(bnad, ret); + bnad_q_num_adjust(bnad, ret, 0); spin_unlock_irqrestore(&bnad->bna_lock, flags); bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx) @@ -2284,6 +2367,9 @@ bnad_enable_msix(struct bnad *bnad) * bnad->num_rxp_per_rx) + BNAD_MAILBOX_MSIX_VECTORS; + if (bnad->msix_num > ret) + goto intx_mode; + /* Try once more with adjusted numbers */ /* If this fails, fall back to INTx */ ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, @@ -2293,6 +2379,9 @@ bnad_enable_msix(struct bnad *bnad) } else if (ret < 0) goto intx_mode; + + pci_intx(bnad->pcidev, 0); + return; intx_mode: @@ -2351,12 +2440,12 @@ bnad_open(struct net_device *netdev) pause_config.tx_pause = 0; pause_config.rx_pause = 0; - mtu = ETH_HLEN + bnad->netdev->mtu + ETH_FCS_LEN; + mtu = ETH_HLEN + VLAN_HLEN + bnad->netdev->mtu + ETH_FCS_LEN; spin_lock_irqsave(&bnad->bna_lock, flags); - bna_port_mtu_set(&bnad->bna.port, mtu, NULL); - bna_port_pause_config(&bnad->bna.port, &pause_config, NULL); - bna_port_enable(&bnad->bna.port); + bna_enet_mtu_set(&bnad->bna.enet, mtu, NULL); + bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL); + bna_enet_enable(&bnad->bna.enet); spin_unlock_irqrestore(&bnad->bna_lock, flags); /* Enable broadcast */ @@ -2396,14 +2485,14 @@ bnad_stop(struct net_device *netdev) /* Stop the stats timer */ bnad_stats_timer_stop(bnad); - init_completion(&bnad->bnad_completions.port_comp); + init_completion(&bnad->bnad_completions.enet_comp); spin_lock_irqsave(&bnad->bna_lock, flags); - bna_port_disable(&bnad->bna.port, BNA_HARD_CLEANUP, - bnad_cb_port_disabled); + bna_enet_disable(&bnad->bna.enet, BNA_HARD_CLEANUP, + bnad_cb_enet_disabled); spin_unlock_irqrestore(&bnad->bna_lock, flags); - wait_for_completion(&bnad->bnad_completions.port_comp); + wait_for_completion(&bnad->bnad_completions.enet_comp); bnad_cleanup_tx(bnad, 0); bnad_cleanup_rx(bnad, 0); @@ -2425,19 +2514,18 @@ static netdev_tx_t bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct bnad *bnad = netdev_priv(netdev); + u32 txq_id = 0; + struct bna_tcb *tcb = bnad->tx_info[0].tcb[txq_id]; u16 txq_prod, vlan_tag = 0; u32 unmap_prod, wis, wis_used, wi_range; u32 vectors, vect_id, i, acked; - u32 tx_id; int err; - struct bnad_tx_info *tx_info; - struct bna_tcb *tcb; - struct bnad_unmap_q *unmap_q; + struct bnad_unmap_q *unmap_q = tcb->unmap_q; dma_addr_t dma_addr; struct bna_txq_entry *txqent; - bna_txq_wi_ctrl_flag_t flags; + u16 flags; if (unlikely (skb->len <= ETH_HLEN || skb->len > BFI_TX_MAX_DATA_PER_PKT)) { @@ -2445,15 +2533,9 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } - tx_id = 0; - - tx_info = &bnad->tx_info[tx_id]; - tcb = tx_info->tcb[tx_id]; - unmap_q = tcb->unmap_q; - /* * Takes care of the Tx that is scheduled between clearing the flag - * and the netif_stop_queue() call. + * and the netif_stop_all_queue() call. */ if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) { dev_kfree_skb(skb); @@ -2467,9 +2549,8 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) } wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */ acked = 0; - if (unlikely - (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) || - vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) { + if (unlikely(wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) || + vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) { if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index && !test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) { @@ -2602,7 +2683,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - u32 size = frag->size; + u16 size = frag->size; if (++vect_id == BFI_TX_MAX_VECTORS_PER_WI) { vect_id = 0; @@ -2760,11 +2841,25 @@ bnad_set_mac_address(struct net_device *netdev, void *mac_addr) } static int -bnad_change_mtu(struct net_device *netdev, int new_mtu) +bnad_mtu_set(struct bnad *bnad, int mtu) { - int mtu, err = 0; unsigned long flags; + init_completion(&bnad->bnad_completions.mtu_comp); + + spin_lock_irqsave(&bnad->bna_lock, flags); + bna_enet_mtu_set(&bnad->bna.enet, mtu, bnad_cb_enet_mtu_set); + spin_unlock_irqrestore(&bnad->bna_lock, flags); + + wait_for_completion(&bnad->bnad_completions.mtu_comp); + + return bnad->bnad_completions.mtu_comp_status; +} + +static int +bnad_change_mtu(struct net_device *netdev, int new_mtu) +{ + int err, mtu = netdev->mtu; struct bnad *bnad = netdev_priv(netdev); if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU) @@ -2774,11 +2869,10 @@ bnad_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; - mtu = ETH_HLEN + new_mtu + ETH_FCS_LEN; - - spin_lock_irqsave(&bnad->bna_lock, flags); - bna_port_mtu_set(&bnad->bna.port, mtu, NULL); - spin_unlock_irqrestore(&bnad->bna_lock, flags); + mtu = ETH_HLEN + VLAN_HLEN + new_mtu + ETH_FCS_LEN; + err = bnad_mtu_set(bnad, mtu); + if (err) + err = -EBUSY; mutex_unlock(&bnad->conf_mutex); return err; @@ -2968,7 +3062,7 @@ bnad_uninit(struct bnad *bnad) /* * Initialize locks - a) Per device mutes used for serializing configuration + a) Per ioceth mutes used for serializing configuration changes from OS interface b) spin lock used to protect bna state machine */ @@ -3058,12 +3152,15 @@ bnad_pci_probe(struct pci_dev *pdev, */ netdev = alloc_etherdev(sizeof(struct bnad)); if (!netdev) { - dev_err(&pdev->dev, "alloc_etherdev failed\n"); + dev_err(&pdev->dev, "netdev allocation failed\n"); err = -ENOMEM; return err; } bnad = netdev_priv(netdev); + bnad_lock_init(bnad); + + mutex_lock(&bnad->conf_mutex); /* * PCI initialization * Output : using_dac = 1 for 64 bit DMA @@ -3073,7 +3170,6 @@ bnad_pci_probe(struct pci_dev *pdev, if (err) goto free_netdev; - bnad_lock_init(bnad); /* * Initialize bnad structure * Setup relation between pci_dev & netdev @@ -3082,21 +3178,22 @@ bnad_pci_probe(struct pci_dev *pdev, err = bnad_init(bnad, pdev, netdev); if (err) goto pci_uninit; + /* Initialize netdev structure, set up ethtool ops */ bnad_netdev_init(bnad, using_dac); /* Set link to down state */ netif_carrier_off(netdev); - bnad_enable_msix(bnad); - /* Get resource requirement form bna */ + spin_lock_irqsave(&bnad->bna_lock, flags); bna_res_req(&bnad->res_info[0]); + spin_unlock_irqrestore(&bnad->bna_lock, flags); /* Allocate resources from bna */ - err = bnad_res_alloc(bnad); + err = bnad_res_alloc(bnad, &bnad->res_info[0], BNA_RES_T_MAX); if (err) - goto free_netdev; + goto drv_uninit; bna = &bnad->bna; @@ -3106,69 +3203,102 @@ bnad_pci_probe(struct pci_dev *pdev, pcidev_info.device_id = bnad->pcidev->device; pcidev_info.pci_bar_kva = bnad->bar0; - mutex_lock(&bnad->conf_mutex); - spin_lock_irqsave(&bnad->bna_lock, flags); bna_init(bna, bnad, &pcidev_info, &bnad->res_info[0]); spin_unlock_irqrestore(&bnad->bna_lock, flags); bnad->stats.bna_stats = &bna->stats; + bnad_enable_msix(bnad); + err = bnad_mbox_irq_alloc(bnad); + if (err) + goto res_free; + + /* Set up timers */ - setup_timer(&bnad->bna.device.ioc.ioc_timer, bnad_ioc_timeout, + setup_timer(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout, ((unsigned long)bnad)); - setup_timer(&bnad->bna.device.ioc.hb_timer, bnad_ioc_hb_check, + setup_timer(&bnad->bna.ioceth.ioc.hb_timer, bnad_ioc_hb_check, ((unsigned long)bnad)); - setup_timer(&bnad->bna.device.ioc.iocpf_timer, bnad_iocpf_timeout, + setup_timer(&bnad->bna.ioceth.ioc.iocpf_timer, bnad_iocpf_timeout, ((unsigned long)bnad)); - setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_iocpf_sem_timeout, + setup_timer(&bnad->bna.ioceth.ioc.sem_timer, bnad_iocpf_sem_timeout, ((unsigned long)bnad)); /* Now start the timer before calling IOC */ - mod_timer(&bnad->bna.device.ioc.iocpf_timer, + mod_timer(&bnad->bna.ioceth.ioc.iocpf_timer, jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ)); /* * Start the chip - * Don't care even if err != 0, bna state machine will - * deal with it + * If the call back comes with error, we bail out. + * This is a catastrophic error. */ - err = bnad_device_enable(bnad); + err = bnad_ioceth_enable(bnad); + if (err) { + pr_err("BNA: Initialization failed err=%d\n", + err); + goto probe_success; + } + + spin_lock_irqsave(&bnad->bna_lock, flags); + if (bna_num_txq_set(bna, BNAD_NUM_TXQ + 1) || + bna_num_rxp_set(bna, BNAD_NUM_RXP + 1)) { + bnad_q_num_adjust(bnad, bna_attr(bna)->num_txq - 1, + bna_attr(bna)->num_rxp - 1); + if (bna_num_txq_set(bna, BNAD_NUM_TXQ + 1) || + bna_num_rxp_set(bna, BNAD_NUM_RXP + 1)) + err = -EIO; + } + bna_mod_res_req(&bnad->bna, &bnad->mod_res_info[0]); + spin_unlock_irqrestore(&bnad->bna_lock, flags); + + err = bnad_res_alloc(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX); + if (err) + goto disable_ioceth; + + spin_lock_irqsave(&bnad->bna_lock, flags); + bna_mod_init(&bnad->bna, &bnad->mod_res_info[0]); + spin_unlock_irqrestore(&bnad->bna_lock, flags); /* Get the burnt-in mac */ spin_lock_irqsave(&bnad->bna_lock, flags); - bna_port_mac_get(&bna->port, &bnad->perm_addr); + bna_enet_perm_mac_get(&bna->enet, &bnad->perm_addr); bnad_set_netdev_perm_addr(bnad); spin_unlock_irqrestore(&bnad->bna_lock, flags); - mutex_unlock(&bnad->conf_mutex); - /* Finally, reguister with net_device layer */ err = register_netdev(netdev); if (err) { pr_err("BNA : Registering with netdev failed\n"); - goto disable_device; + goto probe_uninit; } + set_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags); +probe_success: + mutex_unlock(&bnad->conf_mutex); return 0; -disable_device: - mutex_lock(&bnad->conf_mutex); - bnad_device_disable(bnad); - del_timer_sync(&bnad->bna.device.ioc.ioc_timer); - del_timer_sync(&bnad->bna.device.ioc.sem_timer); - del_timer_sync(&bnad->bna.device.ioc.hb_timer); +probe_uninit: + bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX); +disable_ioceth: + bnad_ioceth_disable(bnad); + del_timer_sync(&bnad->bna.ioceth.ioc.ioc_timer); + del_timer_sync(&bnad->bna.ioceth.ioc.sem_timer); + del_timer_sync(&bnad->bna.ioceth.ioc.hb_timer); spin_lock_irqsave(&bnad->bna_lock, flags); bna_uninit(bna); spin_unlock_irqrestore(&bnad->bna_lock, flags); - mutex_unlock(&bnad->conf_mutex); - - bnad_res_free(bnad); + bnad_mbox_irq_free(bnad); bnad_disable_msix(bnad); +res_free: + bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX); +drv_uninit: + bnad_uninit(bnad); pci_uninit: bnad_pci_uninit(pdev); + mutex_unlock(&bnad->conf_mutex); bnad_lock_uninit(bnad); - bnad_uninit(bnad); free_netdev: free_netdev(netdev); return err; @@ -3189,21 +3319,24 @@ bnad_pci_remove(struct pci_dev *pdev) bnad = netdev_priv(netdev); bna = &bnad->bna; - unregister_netdev(netdev); + if (test_and_clear_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags)) + unregister_netdev(netdev); mutex_lock(&bnad->conf_mutex); - bnad_device_disable(bnad); - del_timer_sync(&bnad->bna.device.ioc.ioc_timer); - del_timer_sync(&bnad->bna.device.ioc.sem_timer); - del_timer_sync(&bnad->bna.device.ioc.hb_timer); + bnad_ioceth_disable(bnad); + del_timer_sync(&bnad->bna.ioceth.ioc.ioc_timer); + del_timer_sync(&bnad->bna.ioceth.ioc.sem_timer); + del_timer_sync(&bnad->bna.ioceth.ioc.hb_timer); spin_lock_irqsave(&bnad->bna_lock, flags); bna_uninit(bna); spin_unlock_irqrestore(&bnad->bna_lock, flags); - mutex_unlock(&bnad->conf_mutex); - bnad_res_free(bnad); + bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX); + bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX); + bnad_mbox_irq_free(bnad); bnad_disable_msix(bnad); bnad_pci_uninit(pdev); + mutex_unlock(&bnad->conf_mutex); bnad_lock_uninit(bnad); bnad_uninit(bnad); free_netdev(netdev); |