|
@@ -129,6 +129,80 @@
|
|
|
static int xgbe_poll(struct napi_struct *, int);
|
|
static int xgbe_poll(struct napi_struct *, int);
|
|
|
static void xgbe_set_rx_mode(struct net_device *);
|
|
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)
|
|
static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring)
|
|
|
{
|
|
{
|
|
|
return (ring->rdesc_count - (ring->cur - ring->dirty));
|
|
return (ring->rdesc_count - (ring->cur - ring->dirty));
|
|
@@ -1119,10 +1193,15 @@ static int xgbe_open(struct net_device *netdev)
|
|
|
goto err_ptpclk;
|
|
goto err_ptpclk;
|
|
|
pdata->rx_buf_size = ret;
|
|
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 */
|
|
/* Allocate the ring descriptors and buffers */
|
|
|
ret = desc_if->alloc_ring_resources(pdata);
|
|
ret = desc_if->alloc_ring_resources(pdata);
|
|
|
if (ret)
|
|
if (ret)
|
|
|
- goto err_ptpclk;
|
|
|
|
|
|
|
+ goto err_channels;
|
|
|
|
|
|
|
|
/* Initialize the device restart and Tx timestamp work struct */
|
|
/* Initialize the device restart and Tx timestamp work struct */
|
|
|
INIT_WORK(&pdata->restart_work, xgbe_restart);
|
|
INIT_WORK(&pdata->restart_work, xgbe_restart);
|
|
@@ -1134,7 +1213,7 @@ static int xgbe_open(struct net_device *netdev)
|
|
|
if (ret) {
|
|
if (ret) {
|
|
|
netdev_alert(netdev, "error requesting irq %d\n",
|
|
netdev_alert(netdev, "error requesting irq %d\n",
|
|
|
pdata->irq_number);
|
|
pdata->irq_number);
|
|
|
- goto err_irq;
|
|
|
|
|
|
|
+ goto err_rings;
|
|
|
}
|
|
}
|
|
|
pdata->irq_number = netdev->irq;
|
|
pdata->irq_number = netdev->irq;
|
|
|
|
|
|
|
@@ -1152,9 +1231,12 @@ err_start:
|
|
|
devm_free_irq(pdata->dev, pdata->irq_number, pdata);
|
|
devm_free_irq(pdata->dev, pdata->irq_number, pdata);
|
|
|
pdata->irq_number = 0;
|
|
pdata->irq_number = 0;
|
|
|
|
|
|
|
|
-err_irq:
|
|
|
|
|
|
|
+err_rings:
|
|
|
desc_if->free_ring_resources(pdata);
|
|
desc_if->free_ring_resources(pdata);
|
|
|
|
|
|
|
|
|
|
+err_channels:
|
|
|
|
|
+ xgbe_free_channels(pdata);
|
|
|
|
|
+
|
|
|
err_ptpclk:
|
|
err_ptpclk:
|
|
|
clk_disable_unprepare(pdata->ptpclk);
|
|
clk_disable_unprepare(pdata->ptpclk);
|
|
|
|
|
|
|
@@ -1181,9 +1263,12 @@ static int xgbe_close(struct net_device *netdev)
|
|
|
/* Issue software reset to device */
|
|
/* Issue software reset to device */
|
|
|
hw_if->exit(pdata);
|
|
hw_if->exit(pdata);
|
|
|
|
|
|
|
|
- /* Free all the ring data */
|
|
|
|
|
|
|
+ /* Free the ring descriptors and buffers */
|
|
|
desc_if->free_ring_resources(pdata);
|
|
desc_if->free_ring_resources(pdata);
|
|
|
|
|
|
|
|
|
|
+ /* Free the channel and ring structures */
|
|
|
|
|
+ xgbe_free_channels(pdata);
|
|
|
|
|
+
|
|
|
/* Release the interrupt */
|
|
/* Release the interrupt */
|
|
|
if (pdata->irq_number != 0) {
|
|
if (pdata->irq_number != 0) {
|
|
|
devm_free_irq(pdata->dev, pdata->irq_number, pdata);
|
|
devm_free_irq(pdata->dev, pdata->irq_number, pdata);
|