alx: prepare resource allocation for multi queue support
authorTobias Regnery <tobias.regnery@gmail.com>
Tue, 15 Nov 2016 11:43:13 +0000 (12:43 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Nov 2016 03:46:30 +0000 (22:46 -0500)
Allocate, initialise and free alx_tx_queue structs based on the number of
alx_napi structures. Also increase the size of the descriptor memory based
on the number of tx queues in use.

Based on the downstream driver at github.com/qca/alx

Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/atheros/alx/main.c

index aeb42120910d7075d82df834feb561a1d36a5e9b..c5f09d2616a44e41d86ad8608f7f4ad2d538d9e4 100644 (file)
@@ -429,28 +429,45 @@ static irqreturn_t alx_intr_legacy(int irq, void *data)
        return alx_intr_handle(alx, intr);
 }
 
+static const u16 txring_header_reg[] = {ALX_TPD_PRI0_ADDR_LO,
+                                       ALX_TPD_PRI1_ADDR_LO,
+                                       ALX_TPD_PRI2_ADDR_LO,
+                                       ALX_TPD_PRI3_ADDR_LO};
+
 static void alx_init_ring_ptrs(struct alx_priv *alx)
 {
        struct alx_hw *hw = &alx->hw;
        u32 addr_hi = ((u64)alx->descmem.dma) >> 32;
-       struct alx_napi *np = alx->qnapi[0];
+       struct alx_napi *np;
+       int i;
+
+       for (i = 0; i < alx->num_napi; i++) {
+               np = alx->qnapi[i];
+               if (np->txq) {
+                       np->txq->read_idx = 0;
+                       np->txq->write_idx = 0;
+                       alx_write_mem32(hw,
+                                       txring_header_reg[np->txq->queue_idx],
+                                       np->txq->tpd_dma);
+               }
+
+               if (np->rxq) {
+                       np->rxq->read_idx = 0;
+                       np->rxq->write_idx = 0;
+                       np->rxq->rrd_read_idx = 0;
+                       alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma);
+                       alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma);
+               }
+       }
+
+       alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
+       alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
 
-       np->rxq->read_idx = 0;
-       np->rxq->write_idx = 0;
-       np->rxq->rrd_read_idx = 0;
        alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi);
-       alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma);
        alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz);
-       alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma);
        alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz);
        alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size);
 
-       np->txq->read_idx = 0;
-       np->txq->write_idx = 0;
-       alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
-       alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, np->txq->tpd_dma);
-       alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
-
        /* load these pointers into the chip */
        alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR);
 }
@@ -478,7 +495,7 @@ static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
        struct alx_buffer *cur_buf;
        u16 i;
 
-       if (rxq == NULL)
+       if (!rxq->bufs)
                return;
 
        for (i = 0; i < rxq->count; i++) {
@@ -502,8 +519,14 @@ static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
 
 static void alx_free_buffers(struct alx_priv *alx)
 {
-       alx_free_txring_buf(alx->qnapi[0]->txq);
-       alx_free_rxring_buf(alx->qnapi[0]->rxq);
+       int i;
+
+       for (i = 0; i < alx->num_txq; i++)
+               if (alx->qnapi[i] && alx->qnapi[i]->txq)
+                       alx_free_txring_buf(alx->qnapi[i]->txq);
+
+       if (alx->qnapi[0] && alx->qnapi[0]->rxq)
+               alx_free_rxring_buf(alx->qnapi[0]->rxq);
 }
 
 static int alx_reinit_rings(struct alx_priv *alx)
@@ -611,7 +634,7 @@ static int alx_alloc_rx_ring(struct alx_priv *alx, struct alx_rx_queue *rxq,
 
 static int alx_alloc_rings(struct alx_priv *alx)
 {
-       int offset = 0;
+       int i, offset = 0;
 
        /* physical tx/rx ring descriptors
         *
@@ -619,7 +642,8 @@ static int alx_alloc_rings(struct alx_priv *alx)
         * 4G boundary (hardware has a single register for high 32 bits
         * of addresses only)
         */
-       alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz +
+       alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz *
+                           alx->num_txq +
                            sizeof(struct alx_rrd) * alx->rx_ringsz +
                            sizeof(struct alx_rfd) * alx->rx_ringsz;
        alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev,
@@ -633,10 +657,12 @@ static int alx_alloc_rings(struct alx_priv *alx)
        BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
        BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
 
-       offset = alx_alloc_tx_ring(alx, alx->qnapi[0]->txq, offset);
-       if (offset < 0) {
-               netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
-               return -ENOMEM;
+       for (i = 0; i < alx->num_txq; i++) {
+               offset = alx_alloc_tx_ring(alx, alx->qnapi[i]->txq, offset);
+               if (offset < 0) {
+                       netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
+                       return -ENOMEM;
+               }
        }
 
        offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset);
@@ -652,11 +678,16 @@ static int alx_alloc_rings(struct alx_priv *alx)
 
 static void alx_free_rings(struct alx_priv *alx)
 {
+       int i;
 
        alx_free_buffers(alx);
 
-       kfree(alx->qnapi[0]->txq->bufs);
-       kfree(alx->qnapi[0]->rxq->bufs);
+       for (i = 0; i < alx->num_txq; i++)
+               if (alx->qnapi[i] && alx->qnapi[i]->txq)
+                       kfree(alx->qnapi[i]->txq->bufs);
+
+       if (alx->qnapi[0] && alx->qnapi[0]->rxq)
+               kfree(alx->qnapi[0]->rxq->bufs);
 
        if (!alx->descmem.virt)
                dma_free_coherent(&alx->hw.pdev->dev,
@@ -668,16 +699,19 @@ static void alx_free_rings(struct alx_priv *alx)
 static void alx_free_napis(struct alx_priv *alx)
 {
        struct alx_napi *np;
+       int i;
 
-       np = alx->qnapi[0];
-       if (!np)
-               return;
-
-       netif_napi_del(&np->napi);
-       kfree(np->txq);
-       kfree(np->rxq);
-       kfree(np);
-       alx->qnapi[0] = NULL;
+       for (i = 0; i < alx->num_napi; i++) {
+               np = alx->qnapi[i];
+               if (!np)
+                       continue;
+
+               netif_napi_del(&np->napi);
+               kfree(np->txq);
+               kfree(np->rxq);
+               kfree(np);
+               alx->qnapi[i] = NULL;
+       }
 }
 
 static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1,
@@ -692,31 +726,36 @@ static int alx_alloc_napis(struct alx_priv *alx)
        struct alx_napi *np;
        struct alx_rx_queue *rxq;
        struct alx_tx_queue *txq;
+       int i;
 
        alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
 
        /* allocate alx_napi structures */
-       np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
-       if (!np)
-               goto err_out;
+       for (i = 0; i < alx->num_napi; i++) {
+               np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
+               if (!np)
+                       goto err_out;
 
-       np->alx = alx;
-       netif_napi_add(alx->dev, &np->napi, alx_poll, 64);
-       alx->qnapi[0] = np;
+               np->alx = alx;
+               netif_napi_add(alx->dev, &np->napi, alx_poll, 64);
+               alx->qnapi[i] = np;
+       }
 
        /* allocate tx queues */
-       np = alx->qnapi[0];
-       txq = kzalloc(sizeof(*txq), GFP_KERNEL);
-       if (!txq)
-               goto err_out;
-
-       np->txq = txq;
-       txq->queue_idx = 0;
-       txq->count = alx->tx_ringsz;
-       txq->netdev = alx->dev;
-       txq->dev = &alx->hw.pdev->dev;
-       np->vec_mask |= tx_vect_mask[0];
-       alx->int_mask |= tx_vect_mask[0];
+       for (i = 0; i < alx->num_txq; i++) {
+               np = alx->qnapi[i];
+               txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+               if (!txq)
+                       goto err_out;
+
+               np->txq = txq;
+               txq->queue_idx = i;
+               txq->count = alx->tx_ringsz;
+               txq->netdev = alx->dev;
+               txq->dev = &alx->hw.pdev->dev;
+               np->vec_mask |= tx_vect_mask[i];
+               alx->int_mask |= tx_vect_mask[i];
+       }
 
        /* allocate rx queues */
        np = alx->qnapi[0];
@@ -1075,11 +1114,14 @@ static netdev_features_t alx_fix_features(struct net_device *netdev,
 
 static void alx_netif_stop(struct alx_priv *alx)
 {
+       int i;
+
        netif_trans_update(alx->dev);
        if (netif_carrier_ok(alx->dev)) {
                netif_carrier_off(alx->dev);
                netif_tx_disable(alx->dev);
-               napi_disable(&alx->qnapi[0]->napi);
+               for (i = 0; i < alx->num_napi; i++)
+                       napi_disable(&alx->qnapi[i]->napi);
        }
 }
 
@@ -1148,8 +1190,11 @@ static int alx_change_mtu(struct net_device *netdev, int mtu)
 
 static void alx_netif_start(struct alx_priv *alx)
 {
+       int i;
+
        netif_tx_wake_all_queues(alx->dev);
-       napi_enable(&alx->qnapi[0]->napi);
+       for (i = 0; i < alx->num_napi; i++)
+               napi_enable(&alx->qnapi[i]->napi);
        netif_carrier_on(alx->dev);
 }