Skip to content

Commit e24431a

Browse files
author
Paolo Abeni
committed
Merge branch 'eth-fbnic-add-devlink-dev-flash-support'
Lee Trager says: ==================== eth: fbnic: Add devlink dev flash support fbnic supports updating firmware using signed PLDM images. PLDM images are written into the flash. Flashing does not interrupt the operation of the device. V4: https://lore.kernel.org/netdev/[email protected]/T/#t V3: https://lore.kernel.org/lkml/[email protected]/T/ V2: https://lore.kernel.org/all/[email protected]/ ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 1046536 + 82534f4 commit e24431a

File tree

9 files changed

+616
-23
lines changed

9 files changed

+616
-23
lines changed

Documentation/networking/device_drivers/ethernet/meta/fbnic.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ devlink dev info provides version information for all three components. In
2828
addition to the version the hg commit hash of the build is included as a
2929
separate entry.
3030

31+
Upgrading Firmware
32+
------------------
33+
34+
fbnic supports updating firmware using signed PLDM images with devlink dev
35+
flash. PLDM images are written into the flash. Flashing does not interrupt
36+
the operation of the device.
37+
38+
On host boot the latest UEFI driver is always used, no explicit activation
39+
is required. Firmware activation is required to run new control firmware. cmrt
40+
firmware can only be activated by power cycling the NIC.
41+
3142
Statistics
3243
----------
3344

drivers/net/ethernet/meta/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ config FBNIC
2727
select NET_DEVLINK
2828
select PAGE_POOL
2929
select PHYLINK
30+
select PLDMFW
3031
help
3132
This driver supports Meta Platforms Host Network Interface.
3233

drivers/net/ethernet/meta/fbnic/fbnic.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
struct fbnic_napi_vector;
2020

2121
#define FBNIC_MAX_NAPI_VECTORS 128u
22+
#define FBNIC_MBX_CMPL_SLOTS 4
2223

2324
struct fbnic_dev {
2425
struct device *dev;
@@ -42,7 +43,7 @@ struct fbnic_dev {
4243

4344
struct fbnic_fw_mbx mbx[FBNIC_IPC_MBX_INDICES];
4445
struct fbnic_fw_cap fw_cap;
45-
struct fbnic_fw_completion *cmpl_data;
46+
struct fbnic_fw_completion *cmpl_data[FBNIC_MBX_CMPL_SLOTS];
4647
/* Lock protecting Tx Mailbox queue to prevent possible races */
4748
spinlock_t fw_tx_lock;
4849

drivers/net/ethernet/meta/fbnic/fbnic_devlink.c

Lines changed: 259 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
#include <linux/unaligned.h>
55
#include <linux/pci.h>
6+
#include <linux/pldmfw.h>
67
#include <linux/types.h>
78
#include <net/devlink.h>
89

910
#include "fbnic.h"
11+
#include "fbnic_tlv.h"
1012

1113
#define FBNIC_SN_STR_LEN 24
1214

@@ -109,8 +111,264 @@ static int fbnic_devlink_info_get(struct devlink *devlink,
109111
return 0;
110112
}
111113

114+
static bool
115+
fbnic_pldm_match_record(struct pldmfw *context, struct pldmfw_record *record)
116+
{
117+
struct pldmfw_desc_tlv *desc;
118+
u32 anti_rollback_ver = 0;
119+
struct devlink *devlink;
120+
struct fbnic_dev *fbd;
121+
struct pci_dev *pdev;
122+
123+
/* First, use the standard PCI matching function */
124+
if (!pldmfw_op_pci_match_record(context, record))
125+
return false;
126+
127+
pdev = to_pci_dev(context->dev);
128+
fbd = pci_get_drvdata(pdev);
129+
devlink = priv_to_devlink(fbd);
130+
131+
/* If PCI match is successful, check for vendor-specific descriptors */
132+
list_for_each_entry(desc, &record->descs, entry) {
133+
if (desc->type != PLDM_DESC_ID_VENDOR_DEFINED)
134+
continue;
135+
136+
if (desc->size < 21 || desc->data[0] != 1 ||
137+
desc->data[1] != 15)
138+
continue;
139+
140+
if (memcmp(desc->data + 2, "AntiRollbackVer", 15) != 0)
141+
continue;
142+
143+
anti_rollback_ver = get_unaligned_le32(desc->data + 17);
144+
break;
145+
}
146+
147+
/* Compare versions and return error if they do not match */
148+
if (anti_rollback_ver < fbd->fw_cap.anti_rollback_version) {
149+
char buf[128];
150+
151+
snprintf(buf, sizeof(buf),
152+
"New firmware anti-rollback version (0x%x) is older than device version (0x%x)!",
153+
anti_rollback_ver, fbd->fw_cap.anti_rollback_version);
154+
devlink_flash_update_status_notify(devlink, buf,
155+
"Anti-Rollback", 0, 0);
156+
157+
return false;
158+
}
159+
160+
return true;
161+
}
162+
163+
static int
164+
fbnic_flash_start(struct fbnic_dev *fbd, struct pldmfw_component *component)
165+
{
166+
struct fbnic_fw_completion *cmpl;
167+
int err;
168+
169+
cmpl = kzalloc(sizeof(*cmpl), GFP_KERNEL);
170+
if (!cmpl)
171+
return -ENOMEM;
172+
173+
fbnic_fw_init_cmpl(cmpl, FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ);
174+
err = fbnic_fw_xmit_fw_start_upgrade(fbd, cmpl,
175+
component->identifier,
176+
component->component_size);
177+
if (err)
178+
goto cmpl_free;
179+
180+
/* Wait for firmware to ack firmware upgrade start */
181+
if (wait_for_completion_timeout(&cmpl->done, 10 * HZ))
182+
err = cmpl->result;
183+
else
184+
err = -ETIMEDOUT;
185+
186+
fbnic_fw_clear_cmpl(fbd, cmpl);
187+
cmpl_free:
188+
fbnic_fw_put_cmpl(cmpl);
189+
190+
return err;
191+
}
192+
193+
static int
194+
fbnic_flash_component(struct pldmfw *context,
195+
struct pldmfw_component *component)
196+
{
197+
const u8 *data = component->component_data;
198+
const u32 size = component->component_size;
199+
struct fbnic_fw_completion *cmpl;
200+
const char *component_name;
201+
struct devlink *devlink;
202+
struct fbnic_dev *fbd;
203+
struct pci_dev *pdev;
204+
u32 offset = 0;
205+
u32 length = 0;
206+
char buf[32];
207+
int err;
208+
209+
pdev = to_pci_dev(context->dev);
210+
fbd = pci_get_drvdata(pdev);
211+
devlink = priv_to_devlink(fbd);
212+
213+
switch (component->identifier) {
214+
case QSPI_SECTION_CMRT:
215+
component_name = "boot1";
216+
break;
217+
case QSPI_SECTION_CONTROL_FW:
218+
component_name = "boot2";
219+
break;
220+
case QSPI_SECTION_OPTION_ROM:
221+
component_name = "option-rom";
222+
break;
223+
default:
224+
snprintf(buf, sizeof(buf), "Unknown component ID %u!",
225+
component->identifier);
226+
devlink_flash_update_status_notify(devlink, buf, NULL, 0,
227+
size);
228+
return -EINVAL;
229+
}
230+
231+
/* Once firmware receives the request to start upgrading it responds
232+
* with two messages:
233+
* 1. An ACK that it received the message and possible error code
234+
* indicating that an upgrade is not currently possible.
235+
* 2. A request for the first chunk of data
236+
*
237+
* Setup completions for write before issuing the start message so
238+
* the driver can catch both messages.
239+
*/
240+
cmpl = kzalloc(sizeof(*cmpl), GFP_KERNEL);
241+
if (!cmpl)
242+
return -ENOMEM;
243+
244+
fbnic_fw_init_cmpl(cmpl, FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ);
245+
err = fbnic_mbx_set_cmpl(fbd, cmpl);
246+
if (err)
247+
goto cmpl_free;
248+
249+
devlink_flash_update_timeout_notify(devlink, "Initializing",
250+
component_name, 15);
251+
err = fbnic_flash_start(fbd, component);
252+
if (err)
253+
goto err_no_msg;
254+
255+
while (offset < size) {
256+
if (!wait_for_completion_timeout(&cmpl->done, 15 * HZ)) {
257+
err = -ETIMEDOUT;
258+
break;
259+
}
260+
261+
err = cmpl->result;
262+
if (err)
263+
break;
264+
265+
/* Verify firmware is requesting the next chunk in the seq. */
266+
if (cmpl->u.fw_update.offset != offset + length) {
267+
err = -EFAULT;
268+
break;
269+
}
270+
271+
offset = cmpl->u.fw_update.offset;
272+
length = cmpl->u.fw_update.length;
273+
274+
if (length > TLV_MAX_DATA || offset + length > size) {
275+
err = -EFAULT;
276+
break;
277+
}
278+
279+
devlink_flash_update_status_notify(devlink, "Flashing",
280+
component_name,
281+
offset, size);
282+
283+
/* Mailbox will set length to 0 once it receives the finish
284+
* message.
285+
*/
286+
if (!length)
287+
continue;
288+
289+
reinit_completion(&cmpl->done);
290+
err = fbnic_fw_xmit_fw_write_chunk(fbd, data, offset, length,
291+
0);
292+
if (err)
293+
break;
294+
}
295+
296+
if (err) {
297+
fbnic_fw_xmit_fw_write_chunk(fbd, NULL, 0, 0, err);
298+
err_no_msg:
299+
snprintf(buf, sizeof(buf), "Mailbox encountered error %d!",
300+
err);
301+
devlink_flash_update_status_notify(devlink, buf,
302+
component_name, 0, 0);
303+
}
304+
305+
fbnic_fw_clear_cmpl(fbd, cmpl);
306+
cmpl_free:
307+
fbnic_fw_put_cmpl(cmpl);
308+
309+
return err;
310+
}
311+
312+
static const struct pldmfw_ops fbnic_pldmfw_ops = {
313+
.match_record = fbnic_pldm_match_record,
314+
.flash_component = fbnic_flash_component,
315+
};
316+
317+
static int
318+
fbnic_devlink_flash_update(struct devlink *devlink,
319+
struct devlink_flash_update_params *params,
320+
struct netlink_ext_ack *extack)
321+
{
322+
struct fbnic_dev *fbd = devlink_priv(devlink);
323+
const struct firmware *fw = params->fw;
324+
struct device *dev = fbd->dev;
325+
struct pldmfw context;
326+
char *err_msg;
327+
int err;
328+
329+
context.ops = &fbnic_pldmfw_ops;
330+
context.dev = dev;
331+
332+
err = pldmfw_flash_image(&context, fw);
333+
if (err) {
334+
switch (err) {
335+
case -EINVAL:
336+
err_msg = "Invalid image";
337+
break;
338+
case -EOPNOTSUPP:
339+
err_msg = "Unsupported image";
340+
break;
341+
case -ENOMEM:
342+
err_msg = "Out of memory";
343+
break;
344+
case -EFAULT:
345+
err_msg = "Invalid header";
346+
break;
347+
case -ENOENT:
348+
err_msg = "No matching record";
349+
break;
350+
case -ENODEV:
351+
err_msg = "No matching device";
352+
break;
353+
case -ETIMEDOUT:
354+
err_msg = "Timed out waiting for reply";
355+
break;
356+
default:
357+
err_msg = "Unknown error";
358+
break;
359+
}
360+
361+
NL_SET_ERR_MSG_FMT_MOD(extack,
362+
"Failed to flash PLDM Image: %s (error: %d)",
363+
err_msg, err);
364+
}
365+
366+
return err;
367+
}
368+
112369
static const struct devlink_ops fbnic_devlink_ops = {
113-
.info_get = fbnic_devlink_info_get,
370+
.info_get = fbnic_devlink_info_get,
371+
.flash_update = fbnic_devlink_flash_update,
114372
};
115373

116374
void fbnic_devlink_free(struct fbnic_dev *fbd)

0 commit comments

Comments
 (0)