xref: /linux/drivers/net/ethernet/intel/ixgbe/devlink/region.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
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 
ixgbe_devlink_parse_region(struct ixgbe_hw * hw,const struct devlink_region_ops * ops,bool * read_shadow_ram,u32 * nvm_size)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  */
ixgbe_devlink_nvm_snapshot(struct devlink * devlink,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)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, LIBIE_AQC_RES_ACCESS_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  */
ixgbe_devlink_devcaps_snapshot(struct devlink * devlink,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)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  */
ixgbe_devlink_nvm_read(struct devlink * devlink,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u64 offset,u32 size,u8 * data)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, LIBIE_AQC_RES_ACCESS_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  */
ixgbe_devlink_init_regions(struct ixgbe_adapter * adapter)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  */
ixgbe_devlink_destroy_regions(struct ixgbe_adapter * adapter)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