Skip to content

Commit 116ec2e

Browse files
Figo-zhangRuss Weight
authored andcommitted
fpga: m10bmc-sec: support power on image
This patch supports the ability to set a default power-on FPGA image. Additionally, one can select the fall-back image sequence. Two sysfs files are added to the Intel MAX10 BMC Secure driver: available_fpga_images (RO) power-on-image (RW) The expected string to be read from available_fpga_images is: fpga_factory fpga_user1 fpga_user2 A string to be written to power-on-image is expected to be one of the following: fpga_user1 fpga_user2 fpga_factory fpga_factory fpga_user1 fpga_factory fpga_user2 A read from power-on-image will result in one of the following strings: fpga_user1 fpga_user2 fpga_factory fpga_user2 fpga_user1 fpga_factory fpga_factory fpga_user1 fpga_user2 fpga_factory fpga_user2 fpga_user1 Signed-off-by: Russ Weight <russell.h.weight@intel.com>
1 parent afc3d2b commit 116ec2e

3 files changed

Lines changed: 250 additions & 0 deletions

File tree

Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-secure

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,31 @@ Contact: Russ Weight <russell.h.weight@intel.com>
5959
Description: Read only. Returns number of times the secure update
6060
staging area has been flashed.
6161
Format: "%u".
62+
63+
What: /sys/bus/platform/drivers/intel-m10bmc-secure/.../available_fpga_images
64+
Date: April 2021
65+
KernelVersion: 5.13
66+
Contact: Tianfei zhang <tianfei.zhang@intel.com>
67+
Description: Read-only. This file returns a space separated list of
68+
key words that may be written into the power_on_image file
69+
described below. These keywords identify the possible fpga
70+
images that may be used as a default on the next boot of
71+
the FPGA card.
72+
73+
What: /sys/bus/platform/drivers/intel-m10bmc-secure/.../power_on_image
74+
Date: April 2021
75+
KernelVersion: 5.13
76+
Contact: Tianfei zhang <tianfei.zhang@intel.com>
77+
Description: Read/Write. A key word from the available_fpga_images file
78+
may be written to this file to select the FPGA image to be
79+
configured on the next boot of the FPGA card. One or more
80+
additional keywords may be specified, separated by spaces,
81+
to identify a sequence of fall-back images in the event that
82+
the selected FPGA image fails to load. Reading this file
83+
will return the space separated list of keywords identifying
84+
the default power-on image and the current fall-back sequence.
85+
Your specific device may not support all possible fall-back
86+
sequences. The EINVAL error code will be returned if you
87+
attempt to select an unsupported image or fall-back sequence.
88+
Consult your product documentation for supported
89+
configurations.

drivers/fpga/intel-m10-bmc-secure.c

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <linux/platform_device.h>
1515
#include <linux/slab.h>
1616

17+
struct m10bmc_sec;
18+
1719
/* Supported fpga secure manager types */
1820
enum fpga_sec_type {
1921
N3000BMC_SEC,
@@ -22,10 +24,31 @@ enum fpga_sec_type {
2224
N6010BMC_SEC
2325
};
2426

27+
/* Supported names for power-on images */
28+
enum fpga_image {
29+
FPGA_FACTORY,
30+
FPGA_USER1,
31+
FPGA_USER2,
32+
FPGA_MAX
33+
};
34+
35+
static const char * const fpga_image_names[] = {
36+
[FPGA_FACTORY] = "fpga_factory",
37+
[FPGA_USER1] = "fpga_user1",
38+
[FPGA_USER2] = "fpga_user2"
39+
};
40+
41+
struct fpga_power_on {
42+
u32 avail_image_mask;
43+
int (*get_sequence)(struct m10bmc_sec *sec, char *buf);
44+
int (*set_sequence)(struct m10bmc_sec *sec, enum fpga_image images[]);
45+
};
46+
2547
struct m10bmc_sec {
2648
struct device *dev;
2749
struct intel_m10bmc *m10bmc;
2850
enum fpga_sec_type type;
51+
const struct fpga_power_on *poc; /* power on image configuration */
2952
};
3053

3154
/* Root Entry Hash (REH) support */
@@ -158,6 +181,189 @@ static ssize_t flash_count_show(struct device *dev,
158181
}
159182
static DEVICE_ATTR_RO(flash_count);
160183

184+
static enum fpga_image
185+
fpga_image_by_name(struct m10bmc_sec *sec, char *image_name)
186+
{
187+
enum fpga_image i;
188+
189+
for (i = 0; i < FPGA_MAX; i++)
190+
if (sysfs_streq(image_name, fpga_image_names[i]))
191+
return i;
192+
193+
return FPGA_MAX;
194+
}
195+
196+
static int
197+
fpga_images(struct m10bmc_sec *sec, char *names, enum fpga_image images[])
198+
{
199+
u32 image_mask = sec->poc->avail_image_mask;
200+
enum fpga_image image;
201+
char *image_name;
202+
int i = 0;
203+
204+
while ((image_name = strsep(&names, " \n"))) {
205+
image = fpga_image_by_name(sec, image_name);
206+
if (image >= FPGA_MAX || !(image_mask & BIT(image)))
207+
return -EINVAL;
208+
209+
images[i++] = image;
210+
image_mask &= ~BIT(image);
211+
}
212+
213+
return (i == 0) ? -EINVAL : 0;
214+
}
215+
216+
static int
217+
pmci_set_power_on_image(struct m10bmc_sec *sec, enum fpga_image images[])
218+
{
219+
u32 poc_mask = PMCI_FACTORY_IMAGE_SEL;
220+
int ret, first_user = 0;
221+
u32 poc = 0;
222+
223+
if (images[1] == FPGA_FACTORY)
224+
return -EINVAL;
225+
226+
if (images[0] == FPGA_FACTORY) {
227+
poc = PMCI_FACTORY_IMAGE_SEL;
228+
first_user = 1;
229+
}
230+
231+
if (images[first_user] == FPGA_USER1 || images[first_user] == FPGA_USER2) {
232+
poc_mask |= PMCI_USER_IMAGE_PAGE;
233+
if (images[first_user] == FPGA_USER1)
234+
poc |= FIELD_PREP(PMCI_USER_IMAGE_PAGE, POC_USER_IMAGE_1);
235+
else
236+
poc |= FIELD_PREP(PMCI_USER_IMAGE_PAGE, POC_USER_IMAGE_2);
237+
}
238+
239+
ret = m10bmc_sys_update_bits(sec->m10bmc,
240+
m10bmc_base(sec->m10bmc) + M10BMC_PMCI_FPGA_POC,
241+
poc_mask | PMCI_FPGA_POC, poc | PMCI_FPGA_POC);
242+
if (ret)
243+
return ret;
244+
245+
ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
246+
m10bmc_base(sec->m10bmc) + M10BMC_PMCI_FPGA_POC,
247+
poc,
248+
(!(poc & PMCI_FPGA_POC)),
249+
NIOS_HANDSHAKE_INTERVAL_US,
250+
NIOS_HANDSHAKE_TIMEOUT_US);
251+
252+
if (ret || (FIELD_GET(PMCI_NIOS_STATUS, poc) != NIOS_STATUS_SUCCESS))
253+
return -EIO;
254+
255+
return 0;
256+
}
257+
258+
static int pmci_get_power_on_image(struct m10bmc_sec *sec, char *buf)
259+
{
260+
const char *image_names[FPGA_MAX] = { 0 };
261+
int ret, i = 0;
262+
u32 poc;
263+
264+
ret = m10bmc_sys_read(sec->m10bmc, M10BMC_PMCI_FPGA_POC, &poc);
265+
if (ret)
266+
return ret;
267+
268+
if (poc & PMCI_FACTORY_IMAGE_SEL)
269+
image_names[i++] = fpga_image_names[FPGA_FACTORY];
270+
271+
if (FIELD_GET(PMCI_USER_IMAGE_PAGE, poc) == POC_USER_IMAGE_1) {
272+
image_names[i++] = fpga_image_names[FPGA_USER1];
273+
image_names[i++] = fpga_image_names[FPGA_USER2];
274+
} else {
275+
image_names[i++] = fpga_image_names[FPGA_USER2];
276+
image_names[i++] = fpga_image_names[FPGA_USER1];
277+
}
278+
279+
if (!(poc & PMCI_FACTORY_IMAGE_SEL))
280+
image_names[i] = fpga_image_names[FPGA_FACTORY];
281+
282+
return sysfs_emit(buf, "%s %s %s\n", image_names[0],
283+
image_names[1], image_names[2]);
284+
}
285+
286+
static ssize_t
287+
available_fpga_images_show(struct device *dev,
288+
struct device_attribute *attr, char *buf)
289+
{
290+
struct m10bmc_sec *sec = dev_get_drvdata(dev);
291+
ssize_t count = 0;
292+
enum fpga_image i;
293+
294+
for (i = 0; i < FPGA_MAX; i++)
295+
if (BIT(i) & sec->poc->avail_image_mask)
296+
count += scnprintf(buf + count, PAGE_SIZE - count,
297+
"%s ", fpga_image_names[i]);
298+
buf[count - 1] = '\n';
299+
300+
return count;
301+
}
302+
static DEVICE_ATTR_RO(available_fpga_images);
303+
304+
static ssize_t
305+
power_on_image_show(struct device *dev,
306+
struct device_attribute *attr, char *buf)
307+
{
308+
struct m10bmc_sec *sec = dev_get_drvdata(dev);
309+
310+
return sec->poc->get_sequence(sec, buf);
311+
}
312+
313+
static ssize_t
314+
power_on_image_store(struct device *dev,
315+
struct device_attribute *attr, const char *buf, size_t count)
316+
{
317+
enum fpga_image images[FPGA_MAX] = { [0 ... FPGA_MAX - 1] = FPGA_MAX };
318+
struct m10bmc_sec *sec = dev_get_drvdata(dev);
319+
char *tokens;
320+
int ret;
321+
322+
tokens = kmemdup_nul(buf, count, GFP_KERNEL);
323+
if (!tokens)
324+
ret = -ENOMEM;
325+
326+
ret = fpga_images(sec, tokens, images);
327+
if (ret)
328+
goto free_exit;
329+
330+
ret = sec->poc->set_sequence(sec, images);
331+
332+
free_exit:
333+
kfree(tokens);
334+
return ret ? : count;
335+
}
336+
static DEVICE_ATTR_RW(power_on_image);
337+
338+
static umode_t
339+
m10bmc_is_visible(struct kobject *kobj,
340+
struct attribute *attr, int n)
341+
{
342+
struct m10bmc_sec *sec = dev_get_drvdata(kobj_to_dev(kobj));
343+
344+
if (sec->type != N6010BMC_SEC)
345+
return 0;
346+
347+
return attr->mode;
348+
}
349+
350+
static const struct fpga_power_on pmci_power_on_image = {
351+
.avail_image_mask = BIT(FPGA_FACTORY) | BIT(FPGA_USER1) | BIT(FPGA_USER2),
352+
.set_sequence = pmci_set_power_on_image,
353+
.get_sequence = pmci_get_power_on_image,
354+
};
355+
356+
static struct attribute *m10bmc_image_attrs[] = {
357+
&dev_attr_power_on_image.attr,
358+
&dev_attr_available_fpga_images.attr,
359+
NULL,
360+
};
361+
362+
static struct attribute_group m10bmc_image_attr_group = {
363+
.attrs = m10bmc_image_attrs,
364+
.is_visible = m10bmc_is_visible,
365+
};
366+
161367
static struct attribute *m10bmc_security_attrs[] = {
162368
&dev_attr_flash_count.attr,
163369
&dev_attr_bmc_root_entry_hash.attr,
@@ -176,6 +382,7 @@ static struct attribute_group m10bmc_security_attr_group = {
176382

177383
static const struct attribute_group *m10bmc_sec_attr_groups[] = {
178384
&m10bmc_security_attr_group,
385+
&m10bmc_image_attr_group,
179386
NULL,
180387
};
181388

@@ -981,6 +1188,9 @@ static int m10bmc_secure_probe(struct platform_device *pdev)
9811188
return -EINVAL;
9821189
}
9831190

1191+
if (type == N6010BMC_SEC)
1192+
sec->poc = &pmci_power_on_image;
1193+
9841194
smgr = devm_fpga_sec_mgr_create(sec->dev, "Max10 BMC Secure Update",
9851195
sops, sec);
9861196
if (!smgr) {

include/linux/mfd/intel-m10-bmc.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,18 @@ enum m10bmc_type {
204204
#define PMCI_MAX10_REBOOT_REQ BIT(0)
205205
#define PMCI_MAX10_REBOOT_PAGE BIT(1)
206206

207+
#define M10BMC_PMCI_FPGA_POC 0xb0
208+
#define PMCI_FPGA_POC BIT(0)
209+
#define PMCI_NIOS_REQ_CLEAR BIT(1)
210+
#define PMCI_NIOS_STATUS GENMASK(5, 4)
211+
#define NIOS_STATUS_IDLE 0
212+
#define NIOS_STATUS_SUCCESS 1
213+
#define NIOS_STATUS_FAIL 2
214+
#define PMCI_USER_IMAGE_PAGE GENMASK(10, 8)
215+
#define POC_USER_IMAGE_1 1
216+
#define POC_USER_IMAGE_2 2
217+
#define PMCI_FACTORY_IMAGE_SEL BIT(31)
218+
207219
#define M10BMC_PMCI_FPGA_RECONF 0xb8
208220
#define PMCI_FPGA_RECONF_PAGE GENMASK(22, 20)
209221
#define PMCI_FPGA_RP_LOAD BIT(23)

0 commit comments

Comments
 (0)