ibmveth_open() allocates the filter list and every RX queue inline. That's already ~160 lines and would get ugly once we loop over num_rx_queues, especially on error unwind. Pull the RX bits into helpers: ibmveth_alloc_filter_list() / ibmveth_free_filter_list() — shared multicast filter list (one per adapter, not per queue) ibmveth_alloc_rx_queues() / ibmveth_cleanup_rx_resources() — per-queue buffer lists and RX rings, looping [0, num_rx_queues) alloc_rx_queues() rolls back on failure so open() does not need nested goto chains for every queue index. This is the first of several helper-only patches (pools, IRQ, TX, PHYP registration, open/close wiring, buffer submit) that reshape bring-up ahead of MQ datapath commit later in the series. Signed-off-by: Mingming Cao Reviewed-by: Dave Marquardt --- drivers/net/ethernet/ibm/ibmveth.c | 168 +++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 8f9f927bff23..b8adc9935471 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -147,6 +147,174 @@ static unsigned int ibmveth_real_max_tx_queues(void) return min(n_cpu, IBMVETH_MAX_QUEUES); } +/** + * ibmveth_alloc_filter_list - Allocate and map filter list + * @adapter: ibmveth adapter structure + * + * Return: 0 on success, negative error code on failure + */ +static int __maybe_unused ibmveth_alloc_filter_list(struct ibmveth_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + struct net_device *netdev = adapter->netdev; + + adapter->filter_list_addr = (void *)get_zeroed_page(GFP_KERNEL); + if (!adapter->filter_list_addr) { + netdev_err(netdev, "unable to allocate filter pages\n"); + return -ENOMEM; + } + + adapter->filter_list_dma = dma_map_single(dev, + adapter->filter_list_addr, + 4096, DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, adapter->filter_list_dma)) { + netdev_err(netdev, "unable to map filter list pages\n"); + free_page((unsigned long)adapter->filter_list_addr); + adapter->filter_list_addr = NULL; + return -ENOMEM; + } + + netdev_dbg(netdev, "filter list @ 0x%p (DMA: 0x%llx)\n", + adapter->filter_list_addr, + (unsigned long long)adapter->filter_list_dma); + + return 0; +} + +/** + * ibmveth_free_filter_list - Free filter list resources + * @adapter: ibmveth adapter structure + */ +static void __maybe_unused ibmveth_free_filter_list(struct ibmveth_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + + if (adapter->filter_list_dma) { + dma_unmap_single(dev, adapter->filter_list_dma, 4096, + DMA_BIDIRECTIONAL); + adapter->filter_list_dma = 0; + } + + if (adapter->filter_list_addr) { + free_page((unsigned long)adapter->filter_list_addr); + adapter->filter_list_addr = NULL; + } +} + +/** + * ibmveth_alloc_rx_queues - Allocate per-queue RX resources + * @adapter: ibmveth adapter structure + * @rxq_entries: Number of entries per RX queue + * + * Return: 0 on success, negative error code on failure + */ +static int __maybe_unused +ibmveth_alloc_rx_queues(struct ibmveth_adapter *adapter, int rxq_entries) +{ + struct device *dev = &adapter->vdev->dev; + struct net_device *netdev = adapter->netdev; + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->buffer_list_addr[i] = (void *)get_zeroed_page(GFP_KERNEL); + if (!adapter->buffer_list_addr[i]) { + netdev_err(netdev, "unable to allocate buffer list for queue %d\n", i); + goto err_cleanup; + } + + adapter->rx_queue[i].queue_len = + sizeof(struct ibmveth_rx_q_entry) * rxq_entries; + adapter->rx_queue[i].queue_addr = + dma_alloc_coherent(dev, adapter->rx_queue[i].queue_len, + &adapter->rx_queue[i].queue_dma, + GFP_KERNEL); + if (!adapter->rx_queue[i].queue_addr) { + netdev_err(netdev, "unable to allocate RX queue for queue %d\n", i); + goto err_cleanup; + } + + adapter->buffer_list_dma[i] = dma_map_single(dev, + adapter->buffer_list_addr[i], + 4096, DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, adapter->buffer_list_dma[i])) { + netdev_err(netdev, "unable to map buffer list for queue %d\n", i); + adapter->buffer_list_dma[i] = 0; + goto err_cleanup; + } + + adapter->rx_queue[i].index = 0; + adapter->rx_queue[i].num_slots = rxq_entries; + adapter->rx_queue[i].toggle = 1; + + netdev_dbg(netdev, "queue %d: buffer_list @ 0x%p (DMA: 0x%llx), rx_queue @ 0x%p (DMA: 0x%llx), %llu entries\n", + i, adapter->buffer_list_addr[i], + (unsigned long long)adapter->buffer_list_dma[i], + adapter->rx_queue[i].queue_addr, + (unsigned long long)adapter->rx_queue[i].queue_dma, + (unsigned long long)rxq_entries); + } + + netdev_dbg(netdev, "allocated %d RX queue(s) with %d entries each\n", + adapter->num_rx_queues, rxq_entries); + + return 0; + +err_cleanup: + /* Clean up previously allocated queues */ + for (; i >= 0; i--) { + if (adapter->buffer_list_dma[i]) { + dma_unmap_single(dev, adapter->buffer_list_dma[i], + 4096, DMA_BIDIRECTIONAL); + adapter->buffer_list_dma[i] = 0; + } + if (adapter->rx_queue[i].queue_addr) { + dma_free_coherent(dev, adapter->rx_queue[i].queue_len, + adapter->rx_queue[i].queue_addr, + adapter->rx_queue[i].queue_dma); + adapter->rx_queue[i].queue_addr = NULL; + } + if (adapter->buffer_list_addr[i]) { + free_page((unsigned long)adapter->buffer_list_addr[i]); + adapter->buffer_list_addr[i] = NULL; + } + } + + return -ENOMEM; +} + +/** + * ibmveth_cleanup_rx_resources - Free all RX queue resources + * @adapter: ibmveth adapter structure + */ +static void __maybe_unused ibmveth_cleanup_rx_resources(struct ibmveth_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + int i; + + netdev_dbg(adapter->netdev, "cleaning up %d RX queue(s)\n", + adapter->num_rx_queues); + + for (i = 0; i < adapter->num_rx_queues; i++) { + if (adapter->buffer_list_dma[i]) { + dma_unmap_single(dev, adapter->buffer_list_dma[i], + 4096, DMA_BIDIRECTIONAL); + adapter->buffer_list_dma[i] = 0; + } + + if (adapter->rx_queue[i].queue_addr) { + dma_free_coherent(dev, adapter->rx_queue[i].queue_len, + adapter->rx_queue[i].queue_addr, + adapter->rx_queue[i].queue_dma); + adapter->rx_queue[i].queue_addr = NULL; + } + + if (adapter->buffer_list_addr[i]) { + free_page((unsigned long)adapter->buffer_list_addr[i]); + adapter->buffer_list_addr[i] = NULL; + } + } +} + /* setup the initial settings for a buffer pool */ static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, -- 2.39.3 (Apple Git-146)