alx: prepare resource allocation for multi queue support

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>
This commit is contained in:
Tobias Regnery 2016-11-15 12:43:13 +01:00 коммит произвёл David S. Miller
Родитель e0eac25460
Коммит a4076d347f
1 изменённых файлов: 95 добавлений и 50 удалений

Просмотреть файл

@ -429,28 +429,45 @@ static irqreturn_t alx_intr_legacy(int irq, void *data)
return alx_intr_handle(alx, intr); 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) static void alx_init_ring_ptrs(struct alx_priv *alx)
{ {
struct alx_hw *hw = &alx->hw; struct alx_hw *hw = &alx->hw;
u32 addr_hi = ((u64)alx->descmem.dma) >> 32; 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_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_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_RING_SZ, alx->rx_ringsz);
alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size); 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 */ /* load these pointers into the chip */
alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR); 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; struct alx_buffer *cur_buf;
u16 i; u16 i;
if (rxq == NULL) if (!rxq->bufs)
return; return;
for (i = 0; i < rxq->count; i++) { 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) static void alx_free_buffers(struct alx_priv *alx)
{ {
alx_free_txring_buf(alx->qnapi[0]->txq); int i;
alx_free_rxring_buf(alx->qnapi[0]->rxq);
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) 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) static int alx_alloc_rings(struct alx_priv *alx)
{ {
int offset = 0; int i, offset = 0;
/* physical tx/rx ring descriptors /* 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 * 4G boundary (hardware has a single register for high 32 bits
* of addresses only) * 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_rrd) * alx->rx_ringsz +
sizeof(struct alx_rfd) * alx->rx_ringsz; sizeof(struct alx_rfd) * alx->rx_ringsz;
alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev, 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_txd) % 8);
BUILD_BUG_ON(sizeof(struct alx_rrd) % 8); BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
offset = alx_alloc_tx_ring(alx, alx->qnapi[0]->txq, offset); for (i = 0; i < alx->num_txq; i++) {
if (offset < 0) { offset = alx_alloc_tx_ring(alx, alx->qnapi[i]->txq, offset);
netdev_err(alx->dev, "Allocation of tx buffer failed!\n"); if (offset < 0) {
return -ENOMEM; netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
return -ENOMEM;
}
} }
offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset); 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) static void alx_free_rings(struct alx_priv *alx)
{ {
int i;
alx_free_buffers(alx); alx_free_buffers(alx);
kfree(alx->qnapi[0]->txq->bufs); for (i = 0; i < alx->num_txq; i++)
kfree(alx->qnapi[0]->rxq->bufs); 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) if (!alx->descmem.virt)
dma_free_coherent(&alx->hw.pdev->dev, 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) static void alx_free_napis(struct alx_priv *alx)
{ {
struct alx_napi *np; struct alx_napi *np;
int i;
np = alx->qnapi[0]; for (i = 0; i < alx->num_napi; i++) {
if (!np) np = alx->qnapi[i];
return; if (!np)
continue;
netif_napi_del(&np->napi); netif_napi_del(&np->napi);
kfree(np->txq); kfree(np->txq);
kfree(np->rxq); kfree(np->rxq);
kfree(np); kfree(np);
alx->qnapi[0] = NULL; alx->qnapi[i] = NULL;
}
} }
static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1, 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_napi *np;
struct alx_rx_queue *rxq; struct alx_rx_queue *rxq;
struct alx_tx_queue *txq; struct alx_tx_queue *txq;
int i;
alx->int_mask &= ~ALX_ISR_ALL_QUEUES; alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
/* allocate alx_napi structures */ /* allocate alx_napi structures */
np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL); for (i = 0; i < alx->num_napi; i++) {
if (!np) np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
goto err_out; if (!np)
goto err_out;
np->alx = alx; np->alx = alx;
netif_napi_add(alx->dev, &np->napi, alx_poll, 64); netif_napi_add(alx->dev, &np->napi, alx_poll, 64);
alx->qnapi[0] = np; alx->qnapi[i] = np;
}
/* allocate tx queues */ /* allocate tx queues */
np = alx->qnapi[0]; for (i = 0; i < alx->num_txq; i++) {
txq = kzalloc(sizeof(*txq), GFP_KERNEL); np = alx->qnapi[i];
if (!txq) txq = kzalloc(sizeof(*txq), GFP_KERNEL);
goto err_out; if (!txq)
goto err_out;
np->txq = txq; np->txq = txq;
txq->queue_idx = 0; txq->queue_idx = i;
txq->count = alx->tx_ringsz; txq->count = alx->tx_ringsz;
txq->netdev = alx->dev; txq->netdev = alx->dev;
txq->dev = &alx->hw.pdev->dev; txq->dev = &alx->hw.pdev->dev;
np->vec_mask |= tx_vect_mask[0]; np->vec_mask |= tx_vect_mask[i];
alx->int_mask |= tx_vect_mask[0]; alx->int_mask |= tx_vect_mask[i];
}
/* allocate rx queues */ /* allocate rx queues */
np = alx->qnapi[0]; 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) static void alx_netif_stop(struct alx_priv *alx)
{ {
int i;
netif_trans_update(alx->dev); netif_trans_update(alx->dev);
if (netif_carrier_ok(alx->dev)) { if (netif_carrier_ok(alx->dev)) {
netif_carrier_off(alx->dev); netif_carrier_off(alx->dev);
netif_tx_disable(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) static void alx_netif_start(struct alx_priv *alx)
{ {
int i;
netif_tx_wake_all_queues(alx->dev); 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); netif_carrier_on(alx->dev);
} }