Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be7fa326 authored by Rasesh Mody's avatar Rasesh Mody Committed by David S. Miller
Browse files

bna: TxRx and datapath fix



Change Details:
	- Check HW ready condition before accessing h/w register in data-path
	- Postpone clean-up of data buffers to the data-path restart path and
	wait in the cleanup routines for in-flight DMA to complete
	- Separate out Tx completion processing from Rx poll routine

Signed-off-by: default avatarDebashis Dutt <ddutt@brocade.com>
Signed-off-by: default avatarRasesh Mody <rmody@brocade.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e1928c86
Loading
Loading
Loading
Loading
+165 −188
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ do { \
	(sizeof(struct bnad_skb_unmap) * ((_depth) - 1));	\
} while (0)

#define BNAD_TXRX_SYNC_MDELAY	250	/* 250 msecs */

/*
 * Reinitialize completions in CQ, once Rx is taken down
 */
@@ -130,7 +132,9 @@ bnad_free_all_txbufs(struct bnad *bnad,
						PCI_DMA_TODEVICE);

		pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
		unmap_cons++;
		if (++unmap_cons >= unmap_q->q_depth)
			break;

		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
			pci_unmap_page(bnad->pcidev,
				       pci_unmap_addr(&unmap_array[unmap_cons],
@@ -139,7 +143,8 @@ bnad_free_all_txbufs(struct bnad *bnad,
				       PCI_DMA_TODEVICE);
			pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
					   0);
			unmap_cons++;
			if (++unmap_cons >= unmap_q->q_depth)
				break;
		}
		dev_kfree_skb_any(skb);
	}
@@ -167,11 +172,11 @@ bnad_free_txbufs(struct bnad *bnad,
	/*
	 * Just return if TX is stopped. This check is useful
	 * when bnad_free_txbufs() runs out of a tasklet scheduled
	 * before bnad_cb_tx_cleanup() cleared BNAD_RF_TX_STARTED bit
	 * before bnad_cb_tx_cleanup() cleared BNAD_TXQ_TX_STARTED bit
	 * but this routine runs actually after the cleanup has been
	 * executed.
	 */
	if (!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
	if (!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
		return 0;

	updated_hw_cons = *(tcb->hw_consumer_index);
@@ -252,6 +257,8 @@ bnad_tx_free_tasklet(unsigned long bnad_ptr)
				(!test_and_set_bit(BNAD_TXQ_FREE_SENT,
						  &tcb->flags))) {
				acked = bnad_free_txbufs(bnad, tcb);
				if (likely(test_bit(BNAD_TXQ_TX_STARTED,
					&tcb->flags)))
					bna_ib_ack(tcb->i_dbell, acked);
				smp_mb__before_clear_bit();
				clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
@@ -264,7 +271,7 @@ static u32
bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
{
	struct net_device *netdev = bnad->netdev;
	u32 sent;
	u32 sent = 0;

	if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
		return 0;
@@ -275,12 +282,15 @@ bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
		    netif_carrier_ok(netdev) &&
		    BNA_QE_FREE_CNT(tcb, tcb->q_depth) >=
				    BNAD_NETIF_WAKE_THRESHOLD) {
			if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) {
				netif_wake_queue(netdev);
				BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
			}
		}
	}

	if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
		bna_ib_ack(tcb->i_dbell, sent);
	} else
		bna_ib_ack(tcb->i_dbell, 0);

	smp_mb__before_clear_bit();
	clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
@@ -313,25 +323,26 @@ bnad_reset_rcb(struct bnad *bnad, struct bna_rcb *rcb)
}

static void
bnad_free_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
bnad_free_all_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
{
	struct bnad_unmap_q *unmap_q;
	struct sk_buff *skb;
	int unmap_cons;

	unmap_q = rcb->unmap_q;
	while (BNA_QE_IN_USE_CNT(unmap_q, unmap_q->q_depth)) {
		skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
		BUG_ON(!(skb));
		unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
	for (unmap_cons = 0; unmap_cons < unmap_q->q_depth; unmap_cons++) {
		skb = unmap_q->unmap_array[unmap_cons].skb;
		if (!skb)
			continue;
		BUG_ON(!(pci_unmap_addr(
			&unmap_q->unmap_array[unmap_cons], dma_addr)));
		unmap_q->unmap_array[unmap_cons].skb = NULL;
		pci_unmap_single(bnad->pcidev, pci_unmap_addr(&unmap_q->
					unmap_array[unmap_q->consumer_index],
					dma_addr), rcb->rxq->buffer_size +
					NET_IP_ALIGN, PCI_DMA_FROMDEVICE);
					unmap_array[unmap_cons],
					dma_addr), rcb->rxq->buffer_size,
					PCI_DMA_FROMDEVICE);
		dev_kfree_skb(skb);
		BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
		BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
	}

	bnad_reset_rcb(bnad, rcb);
}

@@ -385,43 +396,11 @@ bnad_alloc_n_post_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
		unmap_q->producer_index = unmap_prod;
		rcb->producer_index = unmap_prod;
		smp_mb();
		if (likely(test_bit(BNAD_RXQ_STARTED, &rcb->flags)))
			bna_rxq_prod_indx_doorbell(rcb);
	}
}

/*
 * Locking is required in the enable path
 * because it is called from a napi poll
 * context, where the bna_lock is not held
 * unlike the IRQ context.
 */
static void
bnad_enable_txrx_irqs(struct bnad *bnad)
{
	struct bna_tcb *tcb;
	struct bna_ccb *ccb;
	int i, j;
	unsigned long flags;

	spin_lock_irqsave(&bnad->bna_lock, flags);
	for (i = 0; i < bnad->num_tx; i++) {
		for (j = 0; j < bnad->num_txq_per_tx; j++) {
			tcb = bnad->tx_info[i].tcb[j];
			bna_ib_coalescing_timer_set(tcb->i_dbell,
				tcb->txq->ib->ib_config.coalescing_timeo);
			bna_ib_ack(tcb->i_dbell, 0);
		}
	}

	for (i = 0; i < bnad->num_rx; i++) {
		for (j = 0; j < bnad->num_rxp_per_rx; j++) {
			ccb = bnad->rx_info[i].rx_ctrl[j].ccb;
			bnad_enable_rx_irq_unsafe(ccb);
		}
	}
	spin_unlock_irqrestore(&bnad->bna_lock, flags);
}

static inline void
bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
{
@@ -448,6 +427,9 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
	u32 qid0 = ccb->rcb[0]->rxq->rxq_id;
	struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;

	if (!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))
		return 0;

	prefetch(bnad->netdev);
	BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
			    wi_range);
@@ -544,12 +526,15 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
	BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);

	if (likely(ccb)) {
		if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
			bna_ib_ack(ccb->i_dbell, packets);
		bnad_refill_rxq(bnad, ccb->rcb[0]);
		if (ccb->rcb[1])
			bnad_refill_rxq(bnad, ccb->rcb[1]);
	} else
	} else {
		if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
			bna_ib_ack(ccb->i_dbell, 0);
	}

	return packets;
}
@@ -557,6 +542,9 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
static void
bnad_disable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
{
	if (unlikely(!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
		return;

	bna_ib_coalescing_timer_set(ccb->i_dbell, 0);
	bna_ib_ack(ccb->i_dbell, 0);
}
@@ -575,9 +563,11 @@ static void
bnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb)
{
	struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
	if (likely(napi_schedule_prep((&rx_ctrl->napi)))) {
	struct napi_struct *napi = &rx_ctrl->napi;

	if (likely(napi_schedule_prep(napi))) {
		bnad_disable_rx_irq(bnad, ccb);
		__napi_schedule((&rx_ctrl->napi));
		__napi_schedule(napi);
	}
	BNAD_UPDATE_CTR(bnad, netif_rx_schedule);
}
@@ -602,12 +592,11 @@ bnad_msix_mbox_handler(int irq, void *data)
{
	u32 intr_status;
	unsigned long flags;
	struct net_device *netdev = data;
	struct bnad *bnad;
	struct bnad *bnad = (struct bnad *)data;

	bnad = netdev_priv(netdev);
	if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags)))
		return IRQ_HANDLED;

	/* BNA_ISR_GET(bnad); Inc Ref count */
	spin_lock_irqsave(&bnad->bna_lock, flags);

	bna_intr_status_get(&bnad->bna, intr_status);
@@ -617,7 +606,6 @@ bnad_msix_mbox_handler(int irq, void *data)

	spin_unlock_irqrestore(&bnad->bna_lock, flags);

	/* BNAD_ISR_PUT(bnad); Dec Ref count */
	return IRQ_HANDLED;
}

@@ -627,8 +615,7 @@ bnad_isr(int irq, void *data)
	int i, j;
	u32 intr_status;
	unsigned long flags;
	struct net_device *netdev = data;
	struct bnad *bnad = netdev_priv(netdev);
	struct bnad *bnad = (struct bnad *)data;
	struct bnad_rx_info *rx_info;
	struct bnad_rx_ctrl *rx_ctrl;

@@ -642,16 +629,21 @@ 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(intr_status))
		bna_mbox_handler(&bnad->bna, intr_status);
		if (!BNA_IS_INTX_DATA_INTR(intr_status)) {
			spin_unlock_irqrestore(&bnad->bna_lock, flags);
			goto done;
		}
	}

	spin_unlock_irqrestore(&bnad->bna_lock, flags);

	if (!BNA_IS_INTX_DATA_INTR(intr_status))
		return IRQ_HANDLED;

	/* 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]);
	}
	/* Rx processing */
	for (i = 0; i < bnad->num_rx; i++) {
		rx_info = &bnad->rx_info[i];
		if (!rx_info->rx)
@@ -663,7 +655,6 @@ bnad_isr(int irq, void *data)
							    rx_ctrl->ccb);
		}
	}
done:
	return IRQ_HANDLED;
}

@@ -674,11 +665,7 @@ bnad_isr(int irq, void *data)
static void
bnad_enable_mbox_irq(struct bnad *bnad)
{
	int irq = BNAD_GET_MBOX_IRQ(bnad);

	if (test_and_clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
		if (bnad->cfg_flags & BNAD_CF_MSIX)
			enable_irq(irq);
	clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);

	BNAD_UPDATE_CTR(bnad, mbox_intr_enabled);
}
@@ -690,14 +677,19 @@ bnad_enable_mbox_irq(struct bnad *bnad)
static void
bnad_disable_mbox_irq(struct bnad *bnad)
{
	int irq = BNAD_GET_MBOX_IRQ(bnad);
	set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);

	BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
}

	if (!test_and_set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
		if (bnad->cfg_flags & BNAD_CF_MSIX)
			disable_irq_nosync(irq);
static void
bnad_set_netdev_perm_addr(struct bnad *bnad)
{
	struct net_device *netdev = bnad->netdev;

	BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
	memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
	if (is_zero_ether_addr(netdev->dev_addr))
		memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
}

/* Control Path Handlers */
@@ -755,11 +747,14 @@ bnad_cb_port_link_status(struct bnad *bnad,

	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",
				bnad->netdev->name);
			netif_carrier_on(bnad->netdev);
			BNAD_UPDATE_CTR(bnad, link_toggle);
			if (test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags)) {
			if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) {
				/* Force an immediate Transmit Schedule */
				pr_info("bna: %s TX_STARTED\n",
					bnad->netdev->name);
@@ -807,6 +802,18 @@ bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb)
{
	struct bnad_tx_info *tx_info =
			(struct bnad_tx_info *)tcb->txq->tx->priv;
	struct bnad_unmap_q *unmap_q = tcb->unmap_q;

	while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
		cpu_relax();

	bnad_free_all_txbufs(bnad, tcb);

	unmap_q->producer_index = 0;
	unmap_q->consumer_index = 0;

	smp_mb__before_clear_bit();
	clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);

	tx_info->tcb[tcb->id] = NULL;
}
@@ -821,6 +828,12 @@ bnad_cb_rcb_setup(struct bnad *bnad, struct bna_rcb *rcb)
	unmap_q->q_depth = BNAD_RX_UNMAPQ_DEPTH;
}

static void
bnad_cb_rcb_destroy(struct bnad *bnad, struct bna_rcb *rcb)
{
	bnad_free_all_rxbufs(bnad, rcb);
}

static void
bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb)
{
@@ -849,7 +862,7 @@ bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
	if (tx_info != &bnad->tx_info[0])
		return;

	clear_bit(BNAD_RF_TX_STARTED, &bnad->run_flags);
	clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
	netif_stop_queue(bnad->netdev);
	pr_info("bna: %s TX_STOPPED\n", bnad->netdev->name);
}
@@ -857,30 +870,15 @@ bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
static void
bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb)
{
	if (test_and_set_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
		return;

	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)
{
	struct bnad_unmap_q *unmap_q;
	struct bnad_unmap_q *unmap_q = tcb->unmap_q;

	if (!tcb || (!tcb->unmap_q))
	if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
		return;

	unmap_q = tcb->unmap_q;
	if (!unmap_q->unmap_array)
		return;
	clear_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags);

	if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
		return;
	while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
		cpu_relax();

	bnad_free_all_txbufs(bnad, tcb);

@@ -889,21 +887,45 @@ bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)

	smp_mb__before_clear_bit();
	clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);

	/*
	 * Workaround for first device 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);
		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)
{
	/* 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);
}

static void
bnad_cb_rx_cleanup(struct bnad *bnad,
			struct bna_ccb *ccb)
{
	bnad_cq_cmpl_init(bnad, ccb);

	bnad_free_rxbufs(bnad, ccb->rcb[0]);
	clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);

	if (ccb->rcb[1]) {
		bnad_free_rxbufs(bnad, ccb->rcb[1]);
	if (ccb->rcb[1])
		clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
	}

	if (!test_and_set_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags))
		mdelay(BNAD_TXRX_SYNC_MDELAY);
}

static void
@@ -911,6 +933,13 @@ bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb)
{
	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);

	bnad_free_all_rxbufs(bnad, rcb);

	set_bit(BNAD_RXQ_STARTED, &rcb->flags);

	/* Now allocate & post buffers for this RCB */
@@ -1047,7 +1076,7 @@ bnad_mbox_irq_free(struct bnad *bnad,
	spin_unlock_irqrestore(&bnad->bna_lock, flags);

	irq = BNAD_GET_MBOX_IRQ(bnad);
	free_irq(irq, bnad->netdev);
	free_irq(irq, bnad);

	kfree(intr_info->idl);
}
@@ -1061,7 +1090,7 @@ static int
bnad_mbox_irq_alloc(struct bnad *bnad,
		    struct bna_intr_info *intr_info)
{
	int 		err;
	int 		err = 0;
	unsigned long 	flags;
	u32	irq;
	irq_handler_t 	irq_handler;
@@ -1096,22 +1125,17 @@ bnad_mbox_irq_alloc(struct bnad *bnad,
	 */
	set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);

	BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);

	err = request_irq(irq, irq_handler, flags,
			  bnad->mbox_irq_name, bnad->netdev);
			  bnad->mbox_irq_name, bnad);

	if (err) {
		kfree(intr_info->idl);
		intr_info->idl = NULL;
		return err;
	}

	spin_lock_irqsave(&bnad->bna_lock, flags);

	if (bnad->cfg_flags & BNAD_CF_MSIX)
		disable_irq_nosync(irq);

	spin_unlock_irqrestore(&bnad->bna_lock, flags);
	return 0;
	return err;
}

static void
@@ -1555,62 +1579,19 @@ bnad_napi_poll_rx(struct napi_struct *napi, int budget)
	return rcvd;
}

static int
bnad_napi_poll_txrx(struct napi_struct *napi, int budget)
{
	struct bnad_rx_ctrl *rx_ctrl =
		container_of(napi, struct bnad_rx_ctrl, napi);
	struct bna_ccb *ccb;
	struct bnad *bnad;
	int 			rcvd = 0;
	int			i, j;

	ccb = rx_ctrl->ccb;

	bnad = ccb->bnad;

	if (!netif_carrier_ok(bnad->netdev))
		goto poll_exit;

	/* Handle Tx Completions, if any */
	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]);
	}

	/* Handle Rx Completions */
	rcvd = bnad_poll_cq(bnad, ccb, budget);
	if (rcvd == budget)
		return rcvd;
poll_exit:
	napi_complete((napi));

	BNAD_UPDATE_CTR(bnad, netif_rx_complete);

	bnad_enable_txrx_irqs(bnad);
	return rcvd;
}

static void
bnad_napi_enable(struct bnad *bnad, u32 rx_id)
{
	int (*napi_poll) (struct napi_struct *, int);
	struct bnad_rx_ctrl *rx_ctrl;
	int i;
	unsigned long flags;

	spin_lock_irqsave(&bnad->bna_lock, flags);
	if (bnad->cfg_flags & BNAD_CF_MSIX)
		napi_poll = bnad_napi_poll_rx;
	else
		napi_poll = bnad_napi_poll_txrx;
	spin_unlock_irqrestore(&bnad->bna_lock, flags);

	/* Initialize & enable NAPI */
	for (i = 0; i <	bnad->num_rxp_per_rx; i++) {
		rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i];

		netif_napi_add(bnad->netdev, &rx_ctrl->napi,
			       napi_poll, 64);
			       bnad_napi_poll_rx, 64);

		napi_enable(&rx_ctrl->napi);
	}
}
@@ -1825,6 +1806,7 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)

	/* Initialize the Rx event handlers */
	rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup;
	rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy;
	rx_cbfn.rcb_destroy_cbfn = NULL;
	rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup;
	rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy;
@@ -2152,16 +2134,6 @@ bnad_q_num_adjust(struct bnad *bnad, int msix_vectors)
		bnad->num_rxp_per_rx = 1;
}

static void
bnad_set_netdev_perm_addr(struct bnad *bnad)
{
	struct net_device *netdev = bnad->netdev;

	memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
	if (is_zero_ether_addr(netdev->dev_addr))
		memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
}

/* Enable / disable device */
static void
bnad_device_disable(struct bnad *bnad)
@@ -2433,21 +2405,21 @@ 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.
	 */
	if (unlikely(!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))) {
	if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
		dev_kfree_skb(skb);
		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;

	vectors = 1 + skb_shinfo(skb)->nr_frags;
	if (vectors > BFI_TX_MAX_VECTORS_PER_PKT) {
		dev_kfree_skb(skb);
@@ -2462,6 +2434,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
		    tcb->consumer_index &&
		    !test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
			acked = bnad_free_txbufs(bnad, tcb);
			if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
				bna_ib_ack(tcb->i_dbell, acked);
			smp_mb__before_clear_bit();
			clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
@@ -2624,6 +2597,10 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
	tcb->producer_index = txq_prod;

	smp_mb();

	if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
		return NETDEV_TX_OK;

	bna_txq_prod_indx_doorbell(tcb);

	if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index)
+13 −9
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
 */
struct bnad_rx_ctrl {
	struct bna_ccb *ccb;
	unsigned long  flags;
	struct napi_struct	napi;
};

@@ -82,6 +83,7 @@ struct bnad_rx_ctrl {

/* Bit positions for tcb->flags */
#define BNAD_TXQ_FREE_SENT		0
#define BNAD_TXQ_TX_STARTED		1

/* Bit positions for rcb->flags */
#define BNAD_RXQ_REFILL			0
@@ -199,12 +201,12 @@ struct bnad_unmap_q {
/* Set, tested & cleared using xxx_bit() functions */
/* Values indicated bit positions */
#define	BNAD_RF_CEE_RUNNING		1
#define BNAD_RF_HW_ERROR 		2
#define BNAD_RF_MBOX_IRQ_DISABLED	3
#define BNAD_RF_TX_STARTED		4
#define BNAD_RF_RX_STARTED		5
#define BNAD_RF_DIM_TIMER_RUNNING	6
#define BNAD_RF_STATS_TIMER_RUNNING	7
#define BNAD_RF_MBOX_IRQ_DISABLED	2
#define BNAD_RF_RX_STARTED		3
#define BNAD_RF_DIM_TIMER_RUNNING	4
#define BNAD_RF_STATS_TIMER_RUNNING	5
#define BNAD_RF_TX_SHUTDOWN_DELAYED	6
#define BNAD_RF_RX_SHUTDOWN_DELAYED	7

struct bnad {
	struct net_device 	*netdev;
@@ -320,9 +322,11 @@ extern void bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64

#define bnad_enable_rx_irq_unsafe(_ccb)			\
{							\
	if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))) {\
		bna_ib_coalescing_timer_set((_ccb)->i_dbell,	\
			(_ccb)->rx_coalescing_timeo);		\
		bna_ib_ack((_ccb)->i_dbell, 0);			\
	}							\
}

#define bnad_dim_timer_running(_bnad)				\