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

ixgbe: devlink: add devlink region support for E610

Provide support for the following devlink cmds:
-DEVLINK_CMD_REGION_GET
-DEVLINK_CMD_REGION_NEW
-DEVLINK_CMD_REGION_DEL
-DEVLINK_CMD_REGION_READ

ixgbe devlink region implementation, similarly to the ice one,
lets user to create snapshots of content of Non Volatile Memory,
content of Shadow RAM, and capabilities of the device.

For both NVM and SRAM regions provide .read() handler to let user
read their contents without the need to create full snapshots.

Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Tested-by: Bharath R <bharath.r@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>

authored by

Slawomir Mrozowicz and committed by
Tony Nguyen
fe259a1b 4bf2d119

+349 -1
+49
Documentation/networking/devlink/ixgbe.rst
··· 120 120 121 121 The driver does not currently support reloading the driver via 122 122 ``DEVLINK_RELOAD_ACTION_DRIVER_REINIT``. 123 + 124 + Regions 125 + ======= 126 + 127 + The ``ixgbe`` driver implements the following regions for accessing internal 128 + device data. 129 + 130 + .. list-table:: regions implemented 131 + :widths: 15 85 132 + 133 + * - Name 134 + - Description 135 + * - ``nvm-flash`` 136 + - The contents of the entire flash chip, sometimes referred to as 137 + the device's Non Volatile Memory. 138 + * - ``shadow-ram`` 139 + - The contents of the Shadow RAM, which is loaded from the beginning 140 + of the flash. Although the contents are primarily from the flash, 141 + this area also contains data generated during device boot which is 142 + not stored in flash. 143 + * - ``device-caps`` 144 + - The contents of the device firmware's capabilities buffer. Useful to 145 + determine the current state and configuration of the device. 146 + 147 + Both the ``nvm-flash`` and ``shadow-ram`` regions can be accessed without a 148 + snapshot. The ``device-caps`` region requires a snapshot as the contents are 149 + sent by firmware and can't be split into separate reads. 150 + 151 + Users can request an immediate capture of a snapshot for all three regions 152 + via the ``DEVLINK_CMD_REGION_NEW`` command. 153 + 154 + .. code:: shell 155 + 156 + $ devlink region show 157 + pci/0000:01:00.0/nvm-flash: size 10485760 snapshot [] max 1 158 + pci/0000:01:00.0/device-caps: size 4096 snapshot [] max 10 159 + 160 + $ devlink region new pci/0000:01:00.0/nvm-flash snapshot 1 161 + 162 + $ devlink region dump pci/0000:01:00.0/nvm-flash snapshot 1 163 + 0000000000000000 0014 95dc 0014 9514 0035 1670 0034 db30 164 + 0000000000000010 0000 0000 ffff ff04 0029 8c00 0028 8cc8 165 + 0000000000000020 0016 0bb8 0016 1720 0000 0000 c00f 3ffc 166 + 0000000000000030 bada cce5 bada cce5 bada cce5 bada cce5 167 + 168 + $ devlink region read pci/0000:01:00.0/nvm-flash snapshot 1 address 0 length 16 169 + 0000000000000000 0014 95dc 0014 9514 0035 1670 0034 db30 170 + 171 + $ devlink region delete pci/0000:01:00.0/device-caps snapshot 1
+2 -1
drivers/net/ethernet/intel/ixgbe/Makefile
··· 10 10 ixgbe-y := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ 11 11 ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ 12 12 ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o \ 13 - ixgbe_xsk.o ixgbe_e610.o devlink/devlink.o ixgbe_fw_update.o 13 + ixgbe_xsk.o ixgbe_e610.o devlink/devlink.o ixgbe_fw_update.o \ 14 + devlink/region.o 14 15 15 16 ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ 16 17 ixgbe_dcb_82599.o ixgbe_dcb_nl.o
+2
drivers/net/ethernet/intel/ixgbe/devlink/devlink.h
··· 6 6 7 7 struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev); 8 8 int ixgbe_devlink_register_port(struct ixgbe_adapter *adapter); 9 + void ixgbe_devlink_init_regions(struct ixgbe_adapter *adapter); 10 + void ixgbe_devlink_destroy_regions(struct ixgbe_adapter *adapter); 9 11 10 12 #endif /* _IXGBE_DEVLINK_H_ */
+290
drivers/net/ethernet/intel/ixgbe/devlink/region.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025, Intel Corporation. */ 3 + 4 + #include "ixgbe.h" 5 + #include "devlink.h" 6 + 7 + #define IXGBE_DEVLINK_READ_BLK_SIZE (1024 * 1024) 8 + 9 + static const struct devlink_region_ops ixgbe_nvm_region_ops; 10 + static const struct devlink_region_ops ixgbe_sram_region_ops; 11 + 12 + static int ixgbe_devlink_parse_region(struct ixgbe_hw *hw, 13 + const struct devlink_region_ops *ops, 14 + bool *read_shadow_ram, u32 *nvm_size) 15 + { 16 + if (ops == &ixgbe_nvm_region_ops) { 17 + *read_shadow_ram = false; 18 + *nvm_size = hw->flash.flash_size; 19 + } else if (ops == &ixgbe_sram_region_ops) { 20 + *read_shadow_ram = true; 21 + *nvm_size = hw->flash.sr_words * 2u; 22 + } else { 23 + return -EOPNOTSUPP; 24 + } 25 + 26 + return 0; 27 + } 28 + 29 + /** 30 + * ixgbe_devlink_nvm_snapshot - Capture a snapshot of the NVM content 31 + * @devlink: the devlink instance 32 + * @ops: the devlink region being snapshotted 33 + * @extack: extended ACK response structure 34 + * @data: on exit points to snapshot data buffer 35 + * 36 + * This function is called in response to the DEVLINK_CMD_REGION_NEW cmd. 37 + * 38 + * Capture a snapshot of the whole requested NVM region. 39 + * 40 + * No need to worry with freeing @data, devlink core takes care if it. 41 + * 42 + * Return: 0 on success, -EOPNOTSUPP for unsupported regions, -EBUSY when 43 + * cannot lock NVM, -ENOMEM when cannot alloc mem and -EIO when error 44 + * occurs during reading. 45 + */ 46 + static int ixgbe_devlink_nvm_snapshot(struct devlink *devlink, 47 + const struct devlink_region_ops *ops, 48 + struct netlink_ext_ack *extack, u8 **data) 49 + { 50 + struct ixgbe_adapter *adapter = devlink_priv(devlink); 51 + struct ixgbe_hw *hw = &adapter->hw; 52 + bool read_shadow_ram; 53 + u8 *nvm_data, *buf; 54 + u32 nvm_size, left; 55 + u8 num_blks; 56 + int err; 57 + 58 + err = ixgbe_devlink_parse_region(hw, ops, &read_shadow_ram, &nvm_size); 59 + if (err) 60 + return err; 61 + 62 + nvm_data = kvzalloc(nvm_size, GFP_KERNEL); 63 + if (!nvm_data) 64 + return -ENOMEM; 65 + 66 + num_blks = DIV_ROUND_UP(nvm_size, IXGBE_DEVLINK_READ_BLK_SIZE); 67 + buf = nvm_data; 68 + left = nvm_size; 69 + 70 + for (int i = 0; i < num_blks; i++) { 71 + u32 read_sz = min_t(u32, IXGBE_DEVLINK_READ_BLK_SIZE, left); 72 + 73 + /* Need to acquire NVM lock during each loop run because the 74 + * total period of reading whole NVM is longer than the maximum 75 + * period the lock can be taken defined by the IXGBE_NVM_TIMEOUT. 76 + */ 77 + err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ); 78 + if (err) { 79 + NL_SET_ERR_MSG_MOD(extack, 80 + "Failed to acquire NVM semaphore"); 81 + kvfree(nvm_data); 82 + return -EBUSY; 83 + } 84 + 85 + err = ixgbe_read_flat_nvm(hw, i * IXGBE_DEVLINK_READ_BLK_SIZE, 86 + &read_sz, buf, read_shadow_ram); 87 + if (err) { 88 + NL_SET_ERR_MSG_MOD(extack, 89 + "Failed to read RAM content"); 90 + ixgbe_release_nvm(hw); 91 + kvfree(nvm_data); 92 + return -EIO; 93 + } 94 + 95 + ixgbe_release_nvm(hw); 96 + 97 + buf += read_sz; 98 + left -= read_sz; 99 + } 100 + 101 + *data = nvm_data; 102 + return 0; 103 + } 104 + 105 + /** 106 + * ixgbe_devlink_devcaps_snapshot - Capture a snapshot of device capabilities 107 + * @devlink: the devlink instance 108 + * @ops: the devlink region being snapshotted 109 + * @extack: extended ACK response structure 110 + * @data: on exit points to snapshot data buffer 111 + * 112 + * This function is called in response to the DEVLINK_CMD_REGION_NEW for 113 + * the device-caps devlink region. 114 + * 115 + * Capture a snapshot of the device capabilities reported by firmware. 116 + * 117 + * No need to worry with freeing @data, devlink core takes care if it. 118 + * 119 + * Return: 0 on success, -ENOMEM when cannot alloc mem, or return code of 120 + * the reading operation. 121 + */ 122 + static int ixgbe_devlink_devcaps_snapshot(struct devlink *devlink, 123 + const struct devlink_region_ops *ops, 124 + struct netlink_ext_ack *extack, 125 + u8 **data) 126 + { 127 + struct ixgbe_adapter *adapter = devlink_priv(devlink); 128 + struct ixgbe_aci_cmd_list_caps_elem *caps; 129 + struct ixgbe_hw *hw = &adapter->hw; 130 + int err; 131 + 132 + caps = kvzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); 133 + if (!caps) 134 + return -ENOMEM; 135 + 136 + err = ixgbe_aci_list_caps(hw, caps, IXGBE_ACI_MAX_BUFFER_SIZE, NULL, 137 + ixgbe_aci_opc_list_dev_caps); 138 + if (err) { 139 + NL_SET_ERR_MSG_MOD(extack, 140 + "Failed to read device capabilities"); 141 + kvfree(caps); 142 + return err; 143 + } 144 + 145 + *data = (u8 *)caps; 146 + return 0; 147 + } 148 + 149 + /** 150 + * ixgbe_devlink_nvm_read - Read a portion of NVM flash content 151 + * @devlink: the devlink instance 152 + * @ops: the devlink region to snapshot 153 + * @extack: extended ACK response structure 154 + * @offset: the offset to start at 155 + * @size: the amount to read 156 + * @data: the data buffer to read into 157 + * 158 + * This function is called in response to DEVLINK_CMD_REGION_READ to directly 159 + * read a section of the NVM contents. 160 + * 161 + * Read from either the nvm-flash region either shadow-ram region. 162 + * 163 + * Return: 0 on success, -EOPNOTSUPP for unsupported regions, -EBUSY when 164 + * cannot lock NVM, -ERANGE when buffer limit exceeded and -EIO when error 165 + * occurs during reading. 166 + */ 167 + static int ixgbe_devlink_nvm_read(struct devlink *devlink, 168 + const struct devlink_region_ops *ops, 169 + struct netlink_ext_ack *extack, 170 + u64 offset, u32 size, u8 *data) 171 + { 172 + struct ixgbe_adapter *adapter = devlink_priv(devlink); 173 + struct ixgbe_hw *hw = &adapter->hw; 174 + bool read_shadow_ram; 175 + u32 nvm_size; 176 + int err; 177 + 178 + err = ixgbe_devlink_parse_region(hw, ops, &read_shadow_ram, &nvm_size); 179 + if (err) 180 + return err; 181 + 182 + if (offset + size > nvm_size) { 183 + NL_SET_ERR_MSG_MOD(extack, "Cannot read beyond the region size"); 184 + return -ERANGE; 185 + } 186 + 187 + err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ); 188 + if (err) { 189 + NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); 190 + return -EBUSY; 191 + } 192 + 193 + err = ixgbe_read_flat_nvm(hw, (u32)offset, &size, data, read_shadow_ram); 194 + if (err) { 195 + NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents"); 196 + ixgbe_release_nvm(hw); 197 + return -EIO; 198 + } 199 + 200 + ixgbe_release_nvm(hw); 201 + return 0; 202 + } 203 + 204 + static const struct devlink_region_ops ixgbe_nvm_region_ops = { 205 + .name = "nvm-flash", 206 + .destructor = kvfree, 207 + .snapshot = ixgbe_devlink_nvm_snapshot, 208 + .read = ixgbe_devlink_nvm_read, 209 + }; 210 + 211 + static const struct devlink_region_ops ixgbe_sram_region_ops = { 212 + .name = "shadow-ram", 213 + .destructor = kvfree, 214 + .snapshot = ixgbe_devlink_nvm_snapshot, 215 + .read = ixgbe_devlink_nvm_read, 216 + }; 217 + 218 + static const struct devlink_region_ops ixgbe_devcaps_region_ops = { 219 + .name = "device-caps", 220 + .destructor = kvfree, 221 + .snapshot = ixgbe_devlink_devcaps_snapshot, 222 + }; 223 + 224 + /** 225 + * ixgbe_devlink_init_regions - Initialize devlink regions 226 + * @adapter: adapter instance 227 + * 228 + * Create devlink regions used to enable access to dump the contents of the 229 + * flash memory of the device. 230 + */ 231 + void ixgbe_devlink_init_regions(struct ixgbe_adapter *adapter) 232 + { 233 + struct devlink *devlink = adapter->devlink; 234 + struct device *dev = &adapter->pdev->dev; 235 + u64 nvm_size, sram_size; 236 + 237 + if (adapter->hw.mac.type != ixgbe_mac_e610) 238 + return; 239 + 240 + nvm_size = adapter->hw.flash.flash_size; 241 + adapter->nvm_region = devl_region_create(devlink, &ixgbe_nvm_region_ops, 242 + 1, nvm_size); 243 + if (IS_ERR(adapter->nvm_region)) { 244 + dev_err(dev, 245 + "Failed to create NVM devlink region, err %ld\n", 246 + PTR_ERR(adapter->nvm_region)); 247 + adapter->nvm_region = NULL; 248 + } 249 + 250 + sram_size = adapter->hw.flash.sr_words * 2u; 251 + adapter->sram_region = devl_region_create(devlink, &ixgbe_sram_region_ops, 252 + 1, sram_size); 253 + if (IS_ERR(adapter->sram_region)) { 254 + dev_err(dev, 255 + "Failed to create shadow-ram devlink region, err %ld\n", 256 + PTR_ERR(adapter->sram_region)); 257 + adapter->sram_region = NULL; 258 + } 259 + 260 + adapter->devcaps_region = devl_region_create(devlink, 261 + &ixgbe_devcaps_region_ops, 262 + 10, IXGBE_ACI_MAX_BUFFER_SIZE); 263 + if (IS_ERR(adapter->devcaps_region)) { 264 + dev_err(dev, 265 + "Failed to create device-caps devlink region, err %ld\n", 266 + PTR_ERR(adapter->devcaps_region)); 267 + adapter->devcaps_region = NULL; 268 + } 269 + } 270 + 271 + /** 272 + * ixgbe_devlink_destroy_regions - Destroy devlink regions 273 + * @adapter: adapter instance 274 + * 275 + * Remove previously created regions for this adapter instance. 276 + */ 277 + void ixgbe_devlink_destroy_regions(struct ixgbe_adapter *adapter) 278 + { 279 + if (adapter->hw.mac.type != ixgbe_mac_e610) 280 + return; 281 + 282 + if (adapter->nvm_region) 283 + devl_region_destroy(adapter->nvm_region); 284 + 285 + if (adapter->sram_region) 286 + devl_region_destroy(adapter->sram_region); 287 + 288 + if (adapter->devcaps_region) 289 + devl_region_destroy(adapter->devcaps_region); 290 + }
+3
drivers/net/ethernet/intel/ixgbe/ixgbe.h
··· 616 616 struct mii_bus *mii_bus; 617 617 struct devlink *devlink; 618 618 struct devlink_port devlink_port; 619 + struct devlink_region *nvm_region; 620 + struct devlink_region *sram_region; 621 + struct devlink_region *devcaps_region; 619 622 620 623 unsigned long state; 621 624
+3
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
··· 11317 11317 ixgbe_devlink_register_port(adapter); 11318 11318 SET_NETDEV_DEVLINK_PORT(adapter->netdev, 11319 11319 &adapter->devlink_port); 11320 + ixgbe_devlink_init_regions(adapter); 11320 11321 devl_register(adapter->devlink); 11321 11322 devl_unlock(adapter->devlink); 11322 11323 ··· 11825 11824 if (err) 11826 11825 goto err_netdev; 11827 11826 11827 + ixgbe_devlink_init_regions(adapter); 11828 11828 devl_register(adapter->devlink); 11829 11829 devl_unlock(adapter->devlink); 11830 11830 return 0; ··· 11884 11882 netdev = adapter->netdev; 11885 11883 devl_lock(adapter->devlink); 11886 11884 devl_unregister(adapter->devlink); 11885 + ixgbe_devlink_destroy_regions(adapter); 11887 11886 ixgbe_dbg_adapter_exit(adapter); 11888 11887 11889 11888 set_bit(__IXGBE_REMOVING, &adapter->state);