1 // SPDX-License-Identifier: GPL-2.0
3 * Intel Software Defined Silicon driver
5 * Copyright (c) 2022, Intel Corporation.
11 #include <linux/auxiliary_bus.h>
12 #include <linux/bits.h>
13 #include <linux/bitfield.h>
14 #include <linux/device.h>
15 #include <linux/iopoll.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/pci.h>
19 #include <linux/slab.h>
20 #include <linux/sysfs.h>
21 #include <linux/types.h>
22 #include <linux/uaccess.h>
26 #define ACCESS_TYPE_BARID 2
27 #define ACCESS_TYPE_LOCAL 3
29 #define SDSI_MIN_SIZE_DWORDS 276
30 #define SDSI_SIZE_CONTROL 8
31 #define SDSI_SIZE_MAILBOX 1024
32 #define SDSI_SIZE_REGS 72
33 #define SDSI_SIZE_CMD sizeof(u64)
36 * Write messages are currently up to the size of the mailbox
37 * while read messages are up to 4 times the size of the
38 * mailbox, sent in packets
40 #define SDSI_SIZE_WRITE_MSG SDSI_SIZE_MAILBOX
41 #define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4)
43 #define SDSI_ENABLED_FEATURES_OFFSET 16
44 #define SDSI_ENABLED BIT(3)
45 #define SDSI_SOCKET_ID_OFFSET 64
46 #define SDSI_SOCKET_ID GENMASK(3, 0)
48 #define SDSI_MBOX_CMD_SUCCESS 0x40
49 #define SDSI_MBOX_CMD_TIMEOUT 0x80
51 #define MBOX_TIMEOUT_US 2000
52 #define MBOX_TIMEOUT_ACQUIRE_US 1000
53 #define MBOX_POLLING_PERIOD_US 100
54 #define MBOX_MAX_PACKETS 4
56 #define MBOX_OWNER_NONE 0x00
57 #define MBOX_OWNER_INBAND 0x01
59 #define CTRL_RUN_BUSY BIT(0)
60 #define CTRL_READ_WRITE BIT(1)
61 #define CTRL_SOM BIT(2)
62 #define CTRL_EOM BIT(3)
63 #define CTRL_OWNER GENMASK(5, 4)
64 #define CTRL_COMPLETE BIT(6)
65 #define CTRL_READY BIT(7)
66 #define CTRL_STATUS GENMASK(15, 8)
67 #define CTRL_PACKET_SIZE GENMASK(31, 16)
68 #define CTRL_MSG_SIZE GENMASK(63, 48)
70 #define DISC_TABLE_SIZE 12
71 #define DT_ACCESS_TYPE GENMASK(3, 0)
72 #define DT_SIZE GENMASK(27, 12)
73 #define DT_TBIR GENMASK(2, 0)
74 #define DT_OFFSET(v) ((v) & GENMASK(31, 3))
77 SDSI_CMD_PROVISION_AKC = 0x04,
78 SDSI_CMD_PROVISION_CAP = 0x08,
79 SDSI_CMD_READ_STATE = 0x10,
82 struct sdsi_mbox_info {
95 struct mutex mb_lock; /* Mailbox access lock */
97 void __iomem *control_addr;
98 void __iomem *mbox_addr;
99 void __iomem *regs_addr;
104 /* SDSi mailbox operations must be performed using 64bit mov instructions */
105 static __always_inline void
106 sdsi_memcpy64_toio(u64 __iomem *to, const u64 *from, size_t count_bytes)
108 size_t count = count_bytes / sizeof(*to);
111 for (i = 0; i < count; i++)
112 writeq(from[i], &to[i]);
115 static __always_inline void
116 sdsi_memcpy64_fromio(u64 *to, const u64 __iomem *from, size_t count_bytes)
118 size_t count = count_bytes / sizeof(*to);
121 for (i = 0; i < count; i++)
122 to[i] = readq(&from[i]);
125 static inline void sdsi_complete_transaction(struct sdsi_priv *priv)
127 u64 control = FIELD_PREP(CTRL_COMPLETE, 1);
129 lockdep_assert_held(&priv->mb_lock);
130 writeq(control, priv->control_addr);
133 static int sdsi_status_to_errno(u32 status)
136 case SDSI_MBOX_CMD_SUCCESS:
138 case SDSI_MBOX_CMD_TIMEOUT:
145 static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
148 struct device *dev = priv->dev;
149 u32 total, loop, eom, status, message_size;
153 lockdep_assert_held(&priv->mb_lock);
155 /* Format and send the read command */
156 control = FIELD_PREP(CTRL_EOM, 1) |
157 FIELD_PREP(CTRL_SOM, 1) |
158 FIELD_PREP(CTRL_RUN_BUSY, 1) |
159 FIELD_PREP(CTRL_PACKET_SIZE, info->size);
160 writeq(control, priv->control_addr);
162 /* For reads, data sizes that are larger than the mailbox size are read in packets. */
166 int offset = SDSI_SIZE_MAILBOX * loop;
167 void __iomem *addr = priv->mbox_addr + offset;
168 u64 *buf = info->buffer + offset / SDSI_SIZE_CMD;
171 /* Poll on ready bit */
172 ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY,
173 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
177 eom = FIELD_GET(CTRL_EOM, control);
178 status = FIELD_GET(CTRL_STATUS, control);
179 packet_size = FIELD_GET(CTRL_PACKET_SIZE, control);
180 message_size = FIELD_GET(CTRL_MSG_SIZE, control);
182 ret = sdsi_status_to_errno(status);
186 /* Only the last packet can be less than the mailbox size. */
187 if (!eom && packet_size != SDSI_SIZE_MAILBOX) {
188 dev_err(dev, "Invalid packet size\n");
193 if (packet_size > SDSI_SIZE_MAILBOX) {
194 dev_err(dev, "Packet size too large\n");
199 sdsi_memcpy64_fromio(buf, addr, round_up(packet_size, SDSI_SIZE_CMD));
201 total += packet_size;
203 sdsi_complete_transaction(priv);
204 } while (!eom && ++loop < MBOX_MAX_PACKETS);
207 sdsi_complete_transaction(priv);
212 dev_err(dev, "Exceeded read attempts\n");
216 /* Message size check is only valid for multi-packet transfers */
217 if (loop && total != message_size)
218 dev_warn(dev, "Read count %u differs from expected count %u\n",
219 total, message_size);
226 static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
232 lockdep_assert_held(&priv->mb_lock);
234 /* Write rest of the payload */
235 sdsi_memcpy64_toio(priv->mbox_addr + SDSI_SIZE_CMD, info->payload + 1,
236 info->size - SDSI_SIZE_CMD);
238 /* Format and send the write command */
239 control = FIELD_PREP(CTRL_EOM, 1) |
240 FIELD_PREP(CTRL_SOM, 1) |
241 FIELD_PREP(CTRL_RUN_BUSY, 1) |
242 FIELD_PREP(CTRL_READ_WRITE, 1) |
243 FIELD_PREP(CTRL_PACKET_SIZE, info->size);
244 writeq(control, priv->control_addr);
246 /* Poll on run_busy bit */
247 ret = readq_poll_timeout(priv->control_addr, control, !(control & CTRL_RUN_BUSY),
248 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
253 status = FIELD_GET(CTRL_STATUS, control);
254 ret = sdsi_status_to_errno(status);
257 sdsi_complete_transaction(priv);
262 static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
268 lockdep_assert_held(&priv->mb_lock);
270 /* Check mailbox is available */
271 control = readq(priv->control_addr);
272 owner = FIELD_GET(CTRL_OWNER, control);
273 if (owner != MBOX_OWNER_NONE)
276 /* Write first qword of payload */
277 writeq(info->payload[0], priv->mbox_addr);
279 /* Check for ownership */
280 ret = readq_poll_timeout(priv->control_addr, control,
281 FIELD_GET(CTRL_OWNER, control) & MBOX_OWNER_INBAND,
282 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_ACQUIRE_US);
287 static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
291 lockdep_assert_held(&priv->mb_lock);
293 ret = sdsi_mbox_acquire(priv, info);
297 return sdsi_mbox_cmd_write(priv, info);
300 static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size)
304 lockdep_assert_held(&priv->mb_lock);
306 ret = sdsi_mbox_acquire(priv, info);
310 return sdsi_mbox_cmd_read(priv, info, data_size);
313 static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,
314 enum sdsi_command command)
316 struct sdsi_mbox_info info;
319 if (!priv->sdsi_enabled)
322 if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))
325 /* Qword aligned message + command qword */
326 info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD;
328 info.payload = kzalloc(info.size, GFP_KERNEL);
332 /* Copy message to payload buffer */
333 memcpy(info.payload, buf, count);
335 /* Command is last qword of payload buffer */
336 info.payload[(info.size - SDSI_SIZE_CMD) / SDSI_SIZE_CMD] = command;
338 ret = mutex_lock_interruptible(&priv->mb_lock);
341 ret = sdsi_mbox_write(priv, &info);
342 mutex_unlock(&priv->mb_lock);
353 static ssize_t provision_akc_write(struct file *filp, struct kobject *kobj,
354 struct bin_attribute *attr, char *buf, loff_t off,
357 struct device *dev = kobj_to_dev(kobj);
358 struct sdsi_priv *priv = dev_get_drvdata(dev);
363 return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_AKC);
365 static BIN_ATTR_WO(provision_akc, SDSI_SIZE_WRITE_MSG);
367 static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,
368 struct bin_attribute *attr, char *buf, loff_t off,
371 struct device *dev = kobj_to_dev(kobj);
372 struct sdsi_priv *priv = dev_get_drvdata(dev);
377 return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_CAP);
379 static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);
381 static long state_certificate_read(struct file *filp, struct kobject *kobj,
382 struct bin_attribute *attr, char *buf, loff_t off,
385 struct device *dev = kobj_to_dev(kobj);
386 struct sdsi_priv *priv = dev_get_drvdata(dev);
387 u64 command = SDSI_CMD_READ_STATE;
388 struct sdsi_mbox_info info;
392 if (!priv->sdsi_enabled)
398 /* Buffer for return data */
399 info.buffer = kmalloc(SDSI_SIZE_READ_MSG, GFP_KERNEL);
403 info.payload = &command;
404 info.size = sizeof(command);
406 ret = mutex_lock_interruptible(&priv->mb_lock);
409 ret = sdsi_mbox_read(priv, &info, &size);
410 mutex_unlock(&priv->mb_lock);
417 memcpy(buf, info.buffer, size);
427 static BIN_ATTR(state_certificate, 0400, state_certificate_read, NULL, SDSI_SIZE_READ_MSG);
429 static ssize_t registers_read(struct file *filp, struct kobject *kobj,
430 struct bin_attribute *attr, char *buf, loff_t off,
433 struct device *dev = kobj_to_dev(kobj);
434 struct sdsi_priv *priv = dev_get_drvdata(dev);
435 void __iomem *addr = priv->regs_addr;
437 memcpy_fromio(buf, addr + off, count);
441 static BIN_ATTR(registers, 0400, registers_read, NULL, SDSI_SIZE_REGS);
443 static struct bin_attribute *sdsi_bin_attrs[] = {
445 &bin_attr_state_certificate,
446 &bin_attr_provision_akc,
447 &bin_attr_provision_cap,
451 static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)
453 struct sdsi_priv *priv = dev_get_drvdata(dev);
455 return sysfs_emit(buf, "0x%x\n", priv->guid);
457 static DEVICE_ATTR_RO(guid);
459 static struct attribute *sdsi_attrs[] = {
464 static const struct attribute_group sdsi_group = {
466 .bin_attrs = sdsi_bin_attrs,
468 __ATTRIBUTE_GROUPS(sdsi);
470 static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
471 struct disc_table *disc_table, struct resource *disc_res)
473 u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info);
474 u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
475 u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
476 u32 offset = DT_OFFSET(disc_table->offset);
478 struct resource res = {};
480 /* Starting location of SDSi MMIO region based on access type */
481 switch (access_type) {
482 case ACCESS_TYPE_LOCAL:
484 dev_err(priv->dev, "Unsupported BAR index %u for access type %u\n",
490 * For access_type LOCAL, the base address is as follows:
491 * base address = end of discovery region + base offset + 1
493 res.start = disc_res->end + offset + 1;
496 case ACCESS_TYPE_BARID:
497 res.start = pci_resource_start(parent, tbir) + offset;
501 dev_err(priv->dev, "Unrecognized access_type %u\n", access_type);
505 res.end = res.start + size * sizeof(u32) - 1;
506 res.flags = IORESOURCE_MEM;
508 priv->control_addr = devm_ioremap_resource(priv->dev, &res);
509 if (IS_ERR(priv->control_addr))
510 return PTR_ERR(priv->control_addr);
512 priv->mbox_addr = priv->control_addr + SDSI_SIZE_CONTROL;
513 priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;
515 features_offset = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
516 priv->sdsi_enabled = !!(features_offset & SDSI_ENABLED);
521 static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
523 struct intel_vsec_device *intel_cap_dev = auxdev_to_ivdev(auxdev);
524 struct disc_table disc_table;
525 struct resource *disc_res;
526 void __iomem *disc_addr;
527 struct sdsi_priv *priv;
530 priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
534 priv->dev = &auxdev->dev;
535 mutex_init(&priv->mb_lock);
536 auxiliary_set_drvdata(auxdev, priv);
538 /* Get the SDSi discovery table */
539 disc_res = &intel_cap_dev->resource[0];
540 disc_addr = devm_ioremap_resource(&auxdev->dev, disc_res);
541 if (IS_ERR(disc_addr))
542 return PTR_ERR(disc_addr);
544 memcpy_fromio(&disc_table, disc_addr, DISC_TABLE_SIZE);
546 priv->guid = disc_table.guid;
548 /* Map the SDSi mailbox registers */
549 ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
556 static const struct auxiliary_device_id sdsi_aux_id_table[] = {
557 { .name = "intel_vsec.sdsi" },
560 MODULE_DEVICE_TABLE(auxiliary, sdsi_aux_id_table);
562 static struct auxiliary_driver sdsi_aux_driver = {
564 .dev_groups = sdsi_groups,
566 .id_table = sdsi_aux_id_table,
568 /* No remove. All resources are handled under devm */
570 module_auxiliary_driver(sdsi_aux_driver);
573 MODULE_DESCRIPTION("Intel Software Defined Silicon driver");
574 MODULE_LICENSE("GPL");