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
9static const struct devlink_region_ops ixgbe_nvm_region_ops;
10static const struct devlink_region_ops ixgbe_sram_region_ops;
11
12static 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 */
46static 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: &read_shadow_ram, nvm_size: &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, access: IXGBE_RES_READ);
78 if (err) {
79 NL_SET_ERR_MSG_MOD(extack,
80 "Failed to acquire NVM semaphore");
81 kvfree(addr: nvm_data);
82 return -EBUSY;
83 }
84
85 err = ixgbe_read_flat_nvm(hw, offset: i * IXGBE_DEVLINK_READ_BLK_SIZE,
86 length: &read_sz, data: 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(addr: 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 */
122static 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, buf: caps, IXGBE_ACI_MAX_BUFFER_SIZE, NULL,
137 opc: ixgbe_aci_opc_list_dev_caps);
138 if (err) {
139 NL_SET_ERR_MSG_MOD(extack,
140 "Failed to read device capabilities");
141 kvfree(addr: 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 */
167static 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: &read_shadow_ram, nvm_size: &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, access: 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, offset: (u32)offset, length: &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
204static 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
211static 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
218static 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 */
231void 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, ops: &ixgbe_nvm_region_ops,
242 region_max_snapshots: 1, region_size: nvm_size);
243 if (IS_ERR(ptr: 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, ops: &ixgbe_sram_region_ops,
252 region_max_snapshots: 1, region_size: sram_size);
253 if (IS_ERR(ptr: 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 ops: &ixgbe_devcaps_region_ops,
262 region_max_snapshots: 10, IXGBE_ACI_MAX_BUFFER_SIZE);
263 if (IS_ERR(ptr: 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 */
277void 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(region: adapter->nvm_region);
284
285 if (adapter->sram_region)
286 devl_region_destroy(region: adapter->sram_region);
287
288 if (adapter->devcaps_region)
289 devl_region_destroy(region: adapter->devcaps_region);
290}
291

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/net/ethernet/intel/ixgbe/devlink/region.c