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 } 291