]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/amd/xgbe/xgbe-drv.c
amd-xgbe: Move ring allocation to device open
[karo-tx-linux.git] / drivers / net / ethernet / amd / xgbe / xgbe-drv.c
index 2349ea9702557b95de0860eb5921589104cd5c9d..07b00bdcd9f99f2f1fb2a2e3804028f4dd762a7d 100644 (file)
 static int xgbe_poll(struct napi_struct *, int);
 static void xgbe_set_rx_mode(struct net_device *);
 
+static int xgbe_alloc_channels(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel_mem, *channel;
+       struct xgbe_ring *tx_ring, *rx_ring;
+       unsigned int count, i;
+
+       count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count);
+
+       channel_mem = kcalloc(count, sizeof(struct xgbe_channel), GFP_KERNEL);
+       if (!channel_mem)
+               goto err_channel;
+
+       tx_ring = kcalloc(pdata->tx_ring_count, sizeof(struct xgbe_ring),
+                         GFP_KERNEL);
+       if (!tx_ring)
+               goto err_tx_ring;
+
+       rx_ring = kcalloc(pdata->rx_ring_count, sizeof(struct xgbe_ring),
+                         GFP_KERNEL);
+       if (!rx_ring)
+               goto err_rx_ring;
+
+       for (i = 0, channel = channel_mem; i < count; i++, channel++) {
+               snprintf(channel->name, sizeof(channel->name), "channel-%d", i);
+               channel->pdata = pdata;
+               channel->queue_index = i;
+               channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE +
+                                   (DMA_CH_INC * i);
+
+               if (i < pdata->tx_ring_count) {
+                       spin_lock_init(&tx_ring->lock);
+                       channel->tx_ring = tx_ring++;
+               }
+
+               if (i < pdata->rx_ring_count) {
+                       spin_lock_init(&rx_ring->lock);
+                       channel->rx_ring = rx_ring++;
+               }
+
+               DBGPR("  %s - queue_index=%u, dma_regs=%p, tx=%p, rx=%p\n",
+                     channel->name, channel->queue_index, channel->dma_regs,
+                     channel->tx_ring, channel->rx_ring);
+       }
+
+       pdata->channel = channel_mem;
+       pdata->channel_count = count;
+
+       return 0;
+
+err_rx_ring:
+       kfree(tx_ring);
+
+err_tx_ring:
+       kfree(channel_mem);
+
+err_channel:
+       netdev_err(pdata->netdev, "channel allocation failed\n");
+
+       return -ENOMEM;
+}
+
+static void xgbe_free_channels(struct xgbe_prv_data *pdata)
+{
+       if (!pdata->channel)
+               return;
+
+       kfree(pdata->channel->rx_ring);
+       kfree(pdata->channel->tx_ring);
+       kfree(pdata->channel);
+
+       pdata->channel = NULL;
+       pdata->channel_count = 0;
+}
+
 static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring)
 {
        return (ring->rdesc_count - (ring->cur - ring->dirty));
@@ -1119,10 +1193,15 @@ static int xgbe_open(struct net_device *netdev)
                goto err_ptpclk;
        pdata->rx_buf_size = ret;
 
+       /* Allocate the channel and ring structures */
+       ret = xgbe_alloc_channels(pdata);
+       if (ret)
+               goto err_ptpclk;
+
        /* Allocate the ring descriptors and buffers */
        ret = desc_if->alloc_ring_resources(pdata);
        if (ret)
-               goto err_ptpclk;
+               goto err_channels;
 
        /* Initialize the device restart and Tx timestamp work struct */
        INIT_WORK(&pdata->restart_work, xgbe_restart);
@@ -1134,7 +1213,7 @@ static int xgbe_open(struct net_device *netdev)
        if (ret) {
                netdev_alert(netdev, "error requesting irq %d\n",
                             pdata->irq_number);
-               goto err_irq;
+               goto err_rings;
        }
        pdata->irq_number = netdev->irq;
 
@@ -1152,9 +1231,12 @@ err_start:
        devm_free_irq(pdata->dev, pdata->irq_number, pdata);
        pdata->irq_number = 0;
 
-err_irq:
+err_rings:
        desc_if->free_ring_resources(pdata);
 
+err_channels:
+       xgbe_free_channels(pdata);
+
 err_ptpclk:
        clk_disable_unprepare(pdata->ptpclk);
 
@@ -1181,9 +1263,12 @@ static int xgbe_close(struct net_device *netdev)
        /* Issue software reset to device */
        hw_if->exit(pdata);
 
-       /* Free all the ring data */
+       /* Free the ring descriptors and buffers */
        desc_if->free_ring_resources(pdata);
 
+       /* Free the channel and ring structures */
+       xgbe_free_channels(pdata);
+
        /* Release the interrupt */
        if (pdata->irq_number != 0) {
                devm_free_irq(pdata->dev, pdata->irq_number, pdata);