Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-restore-the-structure-of-driver-facing-qcfg-api'

Jakub Kicinski says:

====================
net: restore the structure of driver-facing qcfg API

The goal of qcfg objects is to let us seamlessly support new use cases
without modifying all the drivers. We want to pull all the logic of
combining configuration supplied via different interfaces into the core
and present the drivers with a flat queue-by-queue configuration.
Additionally we want to separate the current effective configuration
from the user intent (default vs user setting vs memory provider setting).

Restructure the recently added code to re-introduce the pieces that
are missing compared to the old RFC:
https://lore.kernel.org/20250421222827.283737-1-kuba@kernel.org
Namely:
- the netdev_queue_config() helper
- queue config validation callback

I hopefully removed all the more "out there" parts of the RFC.
====================

Link: https://patch.msgid.link/20260122005113.2476634-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+152 -49
+14 -9
drivers/net/ethernet/broadcom/bnxt/bnxt.c
··· 4326 4326 4327 4327 for (i = 0; i < bp->cp_nr_rings; i++) { 4328 4328 struct bnxt_napi *bnapi = bp->bnapi[i]; 4329 + struct netdev_queue_config qcfg; 4329 4330 struct bnxt_ring_mem_info *rmem; 4330 4331 struct bnxt_cp_ring_info *cpr; 4331 4332 struct bnxt_rx_ring_info *rxr; 4332 4333 struct bnxt_tx_ring_info *txr; 4333 4334 struct bnxt_ring_struct *ring; 4334 - struct netdev_rx_queue *rxq; 4335 4335 4336 4336 if (!bnapi) 4337 4337 continue; ··· 4349 4349 if (!rxr) 4350 4350 goto skip_rx; 4351 4351 4352 - rxq = __netif_get_rx_queue(bp->dev, i); 4353 - rxr->rx_page_size = rxq->qcfg.rx_page_size; 4352 + netdev_queue_config(bp->dev, i, &qcfg); 4353 + rxr->rx_page_size = qcfg.rx_page_size; 4354 4354 4355 4355 ring = &rxr->rx_ring_struct; 4356 4356 rmem = &ring->ring_mem; ··· 15983 15983 qcfg->rx_page_size = BNXT_RX_PAGE_SIZE; 15984 15984 } 15985 15985 15986 - static int bnxt_validate_qcfg(struct bnxt *bp, struct netdev_queue_config *qcfg) 15986 + static int bnxt_validate_qcfg(struct net_device *dev, 15987 + struct netdev_queue_config *qcfg, 15988 + struct netlink_ext_ack *extack) 15987 15989 { 15990 + struct bnxt *bp = netdev_priv(dev); 15991 + 15988 15992 /* Older chips need MSS calc so rx_page_size is not supported */ 15989 15993 if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && 15990 15994 qcfg->rx_page_size != BNXT_RX_PAGE_SIZE) ··· 16015 16011 16016 16012 if (!bp->rx_ring) 16017 16013 return -ENETDOWN; 16018 - 16019 - rc = bnxt_validate_qcfg(bp, qcfg); 16020 - if (rc < 0) 16021 - return rc; 16022 16014 16023 16015 rxr = &bp->rx_ring[idx]; 16024 16016 clone = qmem; ··· 16311 16311 .ndo_queue_start = bnxt_queue_start, 16312 16312 .ndo_queue_stop = bnxt_queue_stop, 16313 16313 .ndo_default_qcfg = bnxt_queue_default_qcfg, 16314 + .ndo_validate_qcfg = bnxt_validate_qcfg, 16314 16315 .supported_params = QCFG_RX_PAGE_SIZE, 16316 + }; 16317 + 16318 + static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops_unsupp = { 16315 16319 }; 16316 16320 16317 16321 static void bnxt_remove_one(struct pci_dev *pdev) ··· 16970 16966 16971 16967 if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) 16972 16968 bp->rss_cap |= BNXT_RSS_CAP_MULTI_RSS_CTX; 16969 + 16970 + dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops_unsupp; 16973 16971 if (BNXT_SUPPORTS_QUEUE_API(bp)) 16974 16972 dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops; 16975 - dev->request_ops_lock = true; 16976 16973 dev->netmem_tx = true; 16977 16974 16978 16975 rc = register_netdev(dev);
+16 -1
include/net/netdev_queues.h
··· 139 139 * @ndo_queue_get_dma_dev: Get dma device for zero-copy operations to be used 140 140 * for this queue. Return NULL on error. 141 141 * 142 - * @ndo_default_qcfg: Populate queue config struct with defaults. Optional. 142 + * @ndo_default_qcfg: (Optional) Populate queue config struct with defaults. 143 + * Queue config structs are passed to this helper before 144 + * the user-requested settings are applied. 145 + * 146 + * @ndo_validate_qcfg: (Optional) Check if queue config is supported. 147 + * Called when configuration affecting a queue may be 148 + * changing, either due to NIC-wide config, or config 149 + * scoped to the queue at a specified index. 150 + * When NIC-wide config is changed the callback will 151 + * be invoked for all queues. 143 152 * 144 153 * @supported_params: Bitmask of supported parameters, see QCFG_*. 145 154 * ··· 173 164 int idx); 174 165 void (*ndo_default_qcfg)(struct net_device *dev, 175 166 struct netdev_queue_config *qcfg); 167 + int (*ndo_validate_qcfg)(struct net_device *dev, 168 + struct netdev_queue_config *qcfg, 169 + struct netlink_ext_ack *extack); 176 170 struct device * (*ndo_queue_get_dma_dev)(struct net_device *dev, 177 171 int idx); 178 172 179 173 unsigned int supported_params; 180 174 }; 175 + 176 + void netdev_queue_config(struct net_device *dev, int rxq, 177 + struct netdev_queue_config *qcfg); 181 178 182 179 bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx); 183 180
+1
net/core/Makefile
··· 19 19 20 20 obj-y += net-sysfs.o 21 21 obj-y += hotdata.o 22 + obj-y += netdev_config.o 22 23 obj-y += netdev_rx_queue.o 23 24 obj-y += netdev_queues.o 24 25 obj-$(CONFIG_PAGE_POOL) += page_pool.o page_pool_user.o
-17
net/core/dev.c
··· 11282 11282 } 11283 11283 } 11284 11284 11285 - static void init_rx_queue_cfgs(struct net_device *dev) 11286 - { 11287 - const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops; 11288 - struct netdev_rx_queue *rxq; 11289 - int i; 11290 - 11291 - if (!qops || !qops->ndo_default_qcfg) 11292 - return; 11293 - 11294 - for (i = 0; i < dev->num_rx_queues; i++) { 11295 - rxq = __netif_get_rx_queue(dev, i); 11296 - qops->ndo_default_qcfg(dev, &rxq->qcfg); 11297 - } 11298 - } 11299 - 11300 11285 /** 11301 11286 * register_netdevice() - register a network device 11302 11287 * @dev: device to register ··· 11326 11341 dev->name_node = netdev_name_node_head_alloc(dev); 11327 11342 if (!dev->name_node) 11328 11343 goto out; 11329 - 11330 - init_rx_queue_cfgs(dev); 11331 11344 11332 11345 /* Init, if this function is available */ 11333 11346 if (dev->netdev_ops->ndo_init) {
+5
net/core/dev.h
··· 10 10 11 11 struct net; 12 12 struct netlink_ext_ack; 13 + struct netdev_queue_config; 13 14 struct cpumask; 14 15 15 16 /* Random bits of netdevice that don't need to be exposed */ ··· 91 90 /* rtnl helpers */ 92 91 extern struct list_head net_todo_list; 93 92 void netdev_run_todo(void); 93 + 94 + int netdev_queue_config_validate(struct net_device *dev, int rxq_idx, 95 + struct netdev_queue_config *qcfg, 96 + struct netlink_ext_ack *extack); 94 97 95 98 /* netdev management, shared between various uAPI entry points */ 96 99 struct netdev_name_node {
+78
net/core/netdev_config.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/netdevice.h> 4 + #include <net/netdev_queues.h> 5 + #include <net/netdev_rx_queue.h> 6 + 7 + #include "dev.h" 8 + 9 + static int netdev_nop_validate_qcfg(struct net_device *dev, 10 + struct netdev_queue_config *qcfg, 11 + struct netlink_ext_ack *extack) 12 + { 13 + return 0; 14 + } 15 + 16 + static int __netdev_queue_config(struct net_device *dev, int rxq_idx, 17 + struct netdev_queue_config *qcfg, 18 + struct netlink_ext_ack *extack, 19 + bool validate) 20 + { 21 + int (*validate_cb)(struct net_device *dev, 22 + struct netdev_queue_config *qcfg, 23 + struct netlink_ext_ack *extack); 24 + struct pp_memory_provider_params *mpp; 25 + int err; 26 + 27 + validate_cb = netdev_nop_validate_qcfg; 28 + if (validate && dev->queue_mgmt_ops->ndo_validate_qcfg) 29 + validate_cb = dev->queue_mgmt_ops->ndo_validate_qcfg; 30 + 31 + memset(qcfg, 0, sizeof(*qcfg)); 32 + 33 + /* Get defaults from the driver, in case user config not set */ 34 + if (dev->queue_mgmt_ops->ndo_default_qcfg) 35 + dev->queue_mgmt_ops->ndo_default_qcfg(dev, qcfg); 36 + err = validate_cb(dev, qcfg, extack); 37 + if (err) 38 + return err; 39 + 40 + /* Apply MP overrides */ 41 + mpp = &__netif_get_rx_queue(dev, rxq_idx)->mp_params; 42 + if (mpp->rx_page_size) 43 + qcfg->rx_page_size = mpp->rx_page_size; 44 + err = validate_cb(dev, qcfg, extack); 45 + if (err) 46 + return err; 47 + 48 + return 0; 49 + } 50 + 51 + /** 52 + * netdev_queue_config() - get configuration for a given queue 53 + * @dev: net_device instance 54 + * @rxq_idx: index of the queue of interest 55 + * @qcfg: queue configuration struct (output) 56 + * 57 + * Render the configuration for a given queue. This helper should be used 58 + * by drivers which support queue configuration to retrieve config for 59 + * a particular queue. 60 + * 61 + * @qcfg is an output parameter and is always fully initialized by this 62 + * function. Some values may not be set by the user, drivers may either 63 + * deal with the "unset" values in @qcfg, or provide the callback 64 + * to populate defaults in queue_management_ops. 65 + */ 66 + void netdev_queue_config(struct net_device *dev, int rxq_idx, 67 + struct netdev_queue_config *qcfg) 68 + { 69 + __netdev_queue_config(dev, rxq_idx, qcfg, NULL, false); 70 + } 71 + EXPORT_SYMBOL(netdev_queue_config); 72 + 73 + int netdev_queue_config_validate(struct net_device *dev, int rxq_idx, 74 + struct netdev_queue_config *qcfg, 75 + struct netlink_ext_ack *extack) 76 + { 77 + return __netdev_queue_config(dev, rxq_idx, qcfg, extack, true); 78 + }
+38 -22
net/core/netdev_rx_queue.c
··· 7 7 #include <net/netdev_rx_queue.h> 8 8 #include <net/page_pool/memory_provider.h> 9 9 10 + #include "dev.h" 10 11 #include "page_pool_priv.h" 11 12 12 13 /* See also page_pool_is_unreadable() */ ··· 19 18 } 20 19 EXPORT_SYMBOL(netif_rxq_has_unreadable_mp); 21 20 22 - int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx) 21 + static int netdev_rx_queue_reconfig(struct net_device *dev, 22 + unsigned int rxq_idx, 23 + struct netdev_queue_config *qcfg_old, 24 + struct netdev_queue_config *qcfg_new) 23 25 { 24 26 struct netdev_rx_queue *rxq = __netif_get_rx_queue(dev, rxq_idx); 25 27 const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops; 26 - struct netdev_queue_config qcfg; 27 28 void *new_mem, *old_mem; 28 29 int err; 29 30 ··· 33 30 !qops->ndo_queue_mem_alloc || !qops->ndo_queue_start) 34 31 return -EOPNOTSUPP; 35 32 36 - if (WARN_ON_ONCE(qops->supported_params && !qops->ndo_default_qcfg)) 37 - return -EINVAL; 38 - 39 33 netdev_assert_locked(dev); 40 - 41 - memset(&qcfg, 0, sizeof(qcfg)); 42 - if (qops->ndo_default_qcfg) 43 - qops->ndo_default_qcfg(dev, &qcfg); 44 - 45 - if (rxq->mp_params.rx_page_size) { 46 - if (!(qops->supported_params & QCFG_RX_PAGE_SIZE)) 47 - return -EOPNOTSUPP; 48 - qcfg.rx_page_size = rxq->mp_params.rx_page_size; 49 - } 50 34 51 35 new_mem = kvzalloc(qops->ndo_queue_mem_size, GFP_KERNEL); 52 36 if (!new_mem) ··· 45 55 goto err_free_new_mem; 46 56 } 47 57 48 - err = qops->ndo_queue_mem_alloc(dev, &qcfg, new_mem, rxq_idx); 58 + err = qops->ndo_queue_mem_alloc(dev, qcfg_new, new_mem, rxq_idx); 49 59 if (err) 50 60 goto err_free_old_mem; 51 61 ··· 58 68 if (err) 59 69 goto err_free_new_queue_mem; 60 70 61 - err = qops->ndo_queue_start(dev, &qcfg, new_mem, rxq_idx); 71 + err = qops->ndo_queue_start(dev, qcfg_new, new_mem, rxq_idx); 62 72 if (err) 63 73 goto err_start_queue; 64 74 } else { ··· 70 80 kvfree(old_mem); 71 81 kvfree(new_mem); 72 82 73 - rxq->qcfg = qcfg; 74 83 return 0; 75 84 76 85 err_start_queue: ··· 80 91 * WARN if we fail to recover the old rx queue, and at least free 81 92 * old_mem so we don't also leak that. 82 93 */ 83 - if (qops->ndo_queue_start(dev, &rxq->qcfg, old_mem, rxq_idx)) { 94 + if (qops->ndo_queue_start(dev, qcfg_old, old_mem, rxq_idx)) { 84 95 WARN(1, 85 96 "Failed to restart old queue in error path. RX queue %d may be unhealthy.", 86 97 rxq_idx); ··· 98 109 99 110 return err; 100 111 } 112 + 113 + int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx) 114 + { 115 + struct netdev_queue_config qcfg; 116 + 117 + netdev_queue_config(dev, rxq_idx, &qcfg); 118 + return netdev_rx_queue_reconfig(dev, rxq_idx, &qcfg, &qcfg); 119 + } 101 120 EXPORT_SYMBOL_NS_GPL(netdev_rx_queue_restart, "NETDEV_INTERNAL"); 102 121 103 122 int __net_mp_open_rxq(struct net_device *dev, unsigned int rxq_idx, 104 123 const struct pp_memory_provider_params *p, 105 124 struct netlink_ext_ack *extack) 106 125 { 126 + const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops; 127 + struct netdev_queue_config qcfg[2]; 107 128 struct netdev_rx_queue *rxq; 108 129 int ret; 109 130 ··· 138 139 NL_SET_ERR_MSG(extack, "unable to custom memory provider to device with XDP program attached"); 139 140 return -EEXIST; 140 141 } 142 + if (p->rx_page_size && !(qops->supported_params & QCFG_RX_PAGE_SIZE)) { 143 + NL_SET_ERR_MSG(extack, "device does not support: rx_page_size"); 144 + return -EOPNOTSUPP; 145 + } 141 146 142 147 rxq = __netif_get_rx_queue(dev, rxq_idx); 143 148 if (rxq->mp_params.mp_ops) { ··· 155 152 } 156 153 #endif 157 154 155 + netdev_queue_config(dev, rxq_idx, &qcfg[0]); 158 156 rxq->mp_params = *p; 159 - ret = netdev_rx_queue_restart(dev, rxq_idx); 157 + ret = netdev_queue_config_validate(dev, rxq_idx, &qcfg[1], extack); 160 158 if (ret) 161 - memset(&rxq->mp_params, 0, sizeof(rxq->mp_params)); 159 + goto err_clear_mp; 162 160 161 + ret = netdev_rx_queue_reconfig(dev, rxq_idx, &qcfg[0], &qcfg[1]); 162 + if (ret) 163 + goto err_clear_mp; 164 + 165 + return 0; 166 + 167 + err_clear_mp: 168 + memset(&rxq->mp_params, 0, sizeof(rxq->mp_params)); 163 169 return ret; 164 170 } 165 171 ··· 186 174 void __net_mp_close_rxq(struct net_device *dev, unsigned int ifq_idx, 187 175 const struct pp_memory_provider_params *old_p) 188 176 { 177 + struct netdev_queue_config qcfg[2]; 189 178 struct netdev_rx_queue *rxq; 190 179 int err; 191 180 ··· 206 193 rxq->mp_params.mp_priv != old_p->mp_priv)) 207 194 return; 208 195 196 + netdev_queue_config(dev, ifq_idx, &qcfg[0]); 209 197 memset(&rxq->mp_params, 0, sizeof(rxq->mp_params)); 210 - err = netdev_rx_queue_restart(dev, ifq_idx); 198 + netdev_queue_config(dev, ifq_idx, &qcfg[1]); 199 + 200 + err = netdev_rx_queue_reconfig(dev, ifq_idx, &qcfg[0], &qcfg[1]); 211 201 WARN_ON(err && err != -ENETDOWN); 212 202 } 213 203