File Index
Files and directories
Sign in
FILE

region.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/intel/ixgbe/devlink/region.c 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
  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, &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 */
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, 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 */
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, &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
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, &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 */
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(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}
~/ Read-only file preview.