1 // SPDX-License-Identifier: GPL-2.0
3 * Intel On Demand (Software Defined Silicon) driver
5 * Copyright (c) 2022, Intel Corporation.
8 * Author: "David E. Box" <david.e.box@linux.intel.com>
11 #include <linux/auxiliary_bus.h>
12 #include <linux/bits.h>
13 #include <linux/bitfield.h>
14 #include <linux/device.h>
15 #include <linux/intel_vsec.h>
16 #include <linux/iopoll.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/overflow.h>
20 #include <linux/pci.h>
21 #include <linux/slab.h>
22 #include <linux/sysfs.h>
23 #include <linux/types.h>
24 #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_MAILBOX 1024
31 #define SDSI_SIZE_REGS 80
32 #define SDSI_SIZE_CMD sizeof(u64)
35 * Write messages are currently up to the size of the mailbox
36 * while read messages are up to 4 times the size of the
37 * mailbox, sent in packets
39 #define SDSI_SIZE_WRITE_MSG SDSI_SIZE_MAILBOX
40 #define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4)
42 #define SDSI_ENABLED_FEATURES_OFFSET 16
43 #define SDSI_FEATURE_SDSI BIT(3)
44 #define SDSI_FEATURE_METERING BIT(26)
46 #define SDSI_SOCKET_ID_OFFSET 64
47 #define SDSI_SOCKET_ID GENMASK(3, 0)
49 #define SDSI_MBOX_CMD_SUCCESS 0x40
50 #define SDSI_MBOX_CMD_TIMEOUT 0x80
52 #define MBOX_TIMEOUT_US 500000
53 #define MBOX_TIMEOUT_ACQUIRE_US 1000
54 #define MBOX_POLLING_PERIOD_US 100
55 #define MBOX_ACQUIRE_NUM_RETRIES 5
56 #define MBOX_ACQUIRE_RETRY_DELAY_MS 500
57 #define MBOX_MAX_PACKETS 4
59 #define MBOX_OWNER_NONE 0x00
60 #define MBOX_OWNER_INBAND 0x01
62 #define CTRL_RUN_BUSY BIT(0)
63 #define CTRL_READ_WRITE BIT(1)
64 #define CTRL_SOM BIT(2)
65 #define CTRL_EOM BIT(3)
66 #define CTRL_OWNER GENMASK(5, 4)
67 #define CTRL_COMPLETE BIT(6)
68 #define CTRL_READY BIT(7)
69 #define CTRL_INBAND_LOCK BIT(32)
70 #define CTRL_METER_ENABLE_DRAM BIT(33)
71 #define CTRL_STATUS GENMASK(15, 8)
72 #define CTRL_PACKET_SIZE GENMASK(31, 16)
73 #define CTRL_MSG_SIZE GENMASK(63, 48)
75 #define DISC_TABLE_SIZE 12
76 #define DT_ACCESS_TYPE GENMASK(3, 0)
77 #define DT_SIZE GENMASK(27, 12)
78 #define DT_TBIR GENMASK(2, 0)
79 #define DT_OFFSET(v) ((v) & GENMASK(31, 3))
81 #define SDSI_GUID_V1 0x006DD191
82 #define GUID_V1_CNTRL_SIZE 8
83 #define GUID_V1_REGS_SIZE 72
84 #define SDSI_GUID_V2 0xF210D9EF
85 #define GUID_V2_CNTRL_SIZE 16
86 #define GUID_V2_REGS_SIZE 80
89 SDSI_CMD_PROVISION_AKC
= 0x0004,
90 SDSI_CMD_PROVISION_CAP
= 0x0008,
91 SDSI_CMD_READ_STATE
= 0x0010,
92 SDSI_CMD_READ_METER
= 0x0014,
95 struct sdsi_mbox_info
{
109 struct mutex mb_lock
; /* Mailbox access lock */
111 void __iomem
*control_addr
;
112 void __iomem
*mbox_addr
;
113 void __iomem
*regs_addr
;
121 /* SDSi mailbox operations must be performed using 64bit mov instructions */
122 static __always_inline
void
123 sdsi_memcpy64_toio(u64 __iomem
*to
, const u64
*from
, size_t count_bytes
)
125 size_t count
= count_bytes
/ sizeof(*to
);
128 for (i
= 0; i
< count
; i
++)
129 writeq(from
[i
], &to
[i
]);
132 static __always_inline
void
133 sdsi_memcpy64_fromio(u64
*to
, const u64 __iomem
*from
, size_t count_bytes
)
135 size_t count
= count_bytes
/ sizeof(*to
);
138 for (i
= 0; i
< count
; i
++)
139 to
[i
] = readq(&from
[i
]);
142 static inline void sdsi_complete_transaction(struct sdsi_priv
*priv
)
144 u64 control
= FIELD_PREP(CTRL_COMPLETE
, 1);
146 lockdep_assert_held(&priv
->mb_lock
);
147 writeq(control
, priv
->control_addr
);
150 static int sdsi_status_to_errno(u32 status
)
153 case SDSI_MBOX_CMD_SUCCESS
:
155 case SDSI_MBOX_CMD_TIMEOUT
:
162 static int sdsi_mbox_poll(struct sdsi_priv
*priv
, struct sdsi_mbox_info
*info
,
165 struct device
*dev
= priv
->dev
;
166 u32 total
, loop
, eom
, status
, message_size
;
170 lockdep_assert_held(&priv
->mb_lock
);
172 /* For reads, data sizes that are larger than the mailbox size are read in packets. */
178 /* Poll on ready bit */
179 ret
= readq_poll_timeout(priv
->control_addr
, control
, control
& CTRL_READY
,
180 MBOX_POLLING_PERIOD_US
, MBOX_TIMEOUT_US
);
184 eom
= FIELD_GET(CTRL_EOM
, control
);
185 status
= FIELD_GET(CTRL_STATUS
, control
);
186 packet_size
= FIELD_GET(CTRL_PACKET_SIZE
, control
);
187 message_size
= FIELD_GET(CTRL_MSG_SIZE
, control
);
189 ret
= sdsi_status_to_errno(status
);
194 sdsi_complete_transaction(priv
);
198 /* Only the last packet can be less than the mailbox size. */
199 if (!eom
&& packet_size
!= SDSI_SIZE_MAILBOX
) {
200 dev_err(dev
, "Invalid packet size\n");
205 if (packet_size
> SDSI_SIZE_MAILBOX
) {
206 dev_err(dev
, "Packet size too large\n");
212 void *buf
= info
->buffer
+ array_size(SDSI_SIZE_MAILBOX
, loop
);
214 sdsi_memcpy64_fromio(buf
, priv
->mbox_addr
,
215 round_up(packet_size
, SDSI_SIZE_CMD
));
216 total
+= packet_size
;
219 sdsi_complete_transaction(priv
);
220 } while (!eom
&& ++loop
< MBOX_MAX_PACKETS
);
223 sdsi_complete_transaction(priv
);
228 dev_err(dev
, "Exceeded read attempts\n");
232 /* Message size check is only valid for multi-packet transfers */
233 if (loop
&& total
!= message_size
)
234 dev_warn(dev
, "Read count %u differs from expected count %u\n",
235 total
, message_size
);
243 static int sdsi_mbox_cmd_read(struct sdsi_priv
*priv
, struct sdsi_mbox_info
*info
,
248 lockdep_assert_held(&priv
->mb_lock
);
250 /* Format and send the read command */
251 control
= FIELD_PREP(CTRL_EOM
, 1) |
252 FIELD_PREP(CTRL_SOM
, 1) |
253 FIELD_PREP(CTRL_RUN_BUSY
, 1) |
254 FIELD_PREP(CTRL_PACKET_SIZE
, info
->size
) |
256 writeq(control
, priv
->control_addr
);
258 return sdsi_mbox_poll(priv
, info
, data_size
);
261 static int sdsi_mbox_cmd_write(struct sdsi_priv
*priv
, struct sdsi_mbox_info
*info
,
266 lockdep_assert_held(&priv
->mb_lock
);
268 /* Write rest of the payload */
269 sdsi_memcpy64_toio(priv
->mbox_addr
+ SDSI_SIZE_CMD
, info
->payload
+ 1,
270 info
->size
- SDSI_SIZE_CMD
);
272 /* Format and send the write command */
273 control
= FIELD_PREP(CTRL_EOM
, 1) |
274 FIELD_PREP(CTRL_SOM
, 1) |
275 FIELD_PREP(CTRL_RUN_BUSY
, 1) |
276 FIELD_PREP(CTRL_READ_WRITE
, 1) |
277 FIELD_PREP(CTRL_MSG_SIZE
, info
->size
) |
278 FIELD_PREP(CTRL_PACKET_SIZE
, info
->size
);
279 writeq(control
, priv
->control_addr
);
281 return sdsi_mbox_poll(priv
, info
, data_size
);
284 static int sdsi_mbox_acquire(struct sdsi_priv
*priv
, struct sdsi_mbox_info
*info
)
288 int ret
, retries
= 0;
290 lockdep_assert_held(&priv
->mb_lock
);
292 /* Check mailbox is available */
293 control
= readq(priv
->control_addr
);
294 owner
= FIELD_GET(CTRL_OWNER
, control
);
295 if (owner
!= MBOX_OWNER_NONE
)
299 * If there has been no recent transaction and no one owns the mailbox,
300 * we should acquire it in under 1ms. However, if we've accessed it
301 * recently it may take up to 2.1 seconds to acquire it again.
304 /* Write first qword of payload */
305 writeq(info
->payload
[0], priv
->mbox_addr
);
307 /* Check for ownership */
308 ret
= readq_poll_timeout(priv
->control_addr
, control
,
309 FIELD_GET(CTRL_OWNER
, control
) == MBOX_OWNER_INBAND
,
310 MBOX_POLLING_PERIOD_US
, MBOX_TIMEOUT_ACQUIRE_US
);
312 if (FIELD_GET(CTRL_OWNER
, control
) == MBOX_OWNER_NONE
&&
313 retries
++ < MBOX_ACQUIRE_NUM_RETRIES
) {
314 msleep(MBOX_ACQUIRE_RETRY_DELAY_MS
);
318 /* Either we got it or someone else did. */
325 static int sdsi_mbox_write(struct sdsi_priv
*priv
, struct sdsi_mbox_info
*info
,
330 lockdep_assert_held(&priv
->mb_lock
);
332 ret
= sdsi_mbox_acquire(priv
, info
);
336 return sdsi_mbox_cmd_write(priv
, info
, data_size
);
339 static int sdsi_mbox_read(struct sdsi_priv
*priv
, struct sdsi_mbox_info
*info
, size_t *data_size
)
343 lockdep_assert_held(&priv
->mb_lock
);
345 ret
= sdsi_mbox_acquire(priv
, info
);
349 return sdsi_mbox_cmd_read(priv
, info
, data_size
);
352 static bool sdsi_ib_locked(struct sdsi_priv
*priv
)
354 return !!FIELD_GET(CTRL_INBAND_LOCK
, readq(priv
->control_addr
));
357 static ssize_t
sdsi_provision(struct sdsi_priv
*priv
, char *buf
, size_t count
,
358 enum sdsi_command command
)
360 struct sdsi_mbox_info info
= {};
363 if (count
> (SDSI_SIZE_WRITE_MSG
- SDSI_SIZE_CMD
))
366 /* Make sure In-band lock is not set */
367 if (sdsi_ib_locked(priv
))
370 /* Qword aligned message + command qword */
371 info
.size
= round_up(count
, SDSI_SIZE_CMD
) + SDSI_SIZE_CMD
;
373 info
.payload
= kzalloc(info
.size
, GFP_KERNEL
);
377 /* Copy message to payload buffer */
378 memcpy(info
.payload
, buf
, count
);
380 /* Command is last qword of payload buffer */
381 info
.payload
[(info
.size
- SDSI_SIZE_CMD
) / SDSI_SIZE_CMD
] = command
;
383 ret
= mutex_lock_interruptible(&priv
->mb_lock
);
387 ret
= sdsi_mbox_write(priv
, &info
, NULL
);
389 mutex_unlock(&priv
->mb_lock
);
400 static ssize_t
provision_akc_write(struct file
*filp
, struct kobject
*kobj
,
401 struct bin_attribute
*attr
, char *buf
, loff_t off
,
404 struct device
*dev
= kobj_to_dev(kobj
);
405 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
410 return sdsi_provision(priv
, buf
, count
, SDSI_CMD_PROVISION_AKC
);
412 static BIN_ATTR_WO(provision_akc
, SDSI_SIZE_WRITE_MSG
);
414 static ssize_t
provision_cap_write(struct file
*filp
, struct kobject
*kobj
,
415 struct bin_attribute
*attr
, char *buf
, loff_t off
,
418 struct device
*dev
= kobj_to_dev(kobj
);
419 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
424 return sdsi_provision(priv
, buf
, count
, SDSI_CMD_PROVISION_CAP
);
426 static BIN_ATTR_WO(provision_cap
, SDSI_SIZE_WRITE_MSG
);
429 certificate_read(u64 command
, u64 control_flags
, struct sdsi_priv
*priv
,
430 char *buf
, loff_t off
, size_t count
)
432 struct sdsi_mbox_info info
= {};
439 /* Buffer for return data */
440 info
.buffer
= kmalloc(SDSI_SIZE_READ_MSG
, GFP_KERNEL
);
444 info
.payload
= &command
;
445 info
.size
= sizeof(command
);
446 info
.control_flags
= control_flags
;
448 ret
= mutex_lock_interruptible(&priv
->mb_lock
);
451 ret
= sdsi_mbox_read(priv
, &info
, &size
);
452 mutex_unlock(&priv
->mb_lock
);
459 memcpy(buf
, info
.buffer
, size
);
471 state_certificate_read(struct file
*filp
, struct kobject
*kobj
,
472 struct bin_attribute
*attr
, char *buf
, loff_t off
,
475 struct device
*dev
= kobj_to_dev(kobj
);
476 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
478 return certificate_read(SDSI_CMD_READ_STATE
, 0, priv
, buf
, off
, count
);
480 static BIN_ATTR_ADMIN_RO(state_certificate
, SDSI_SIZE_READ_MSG
);
483 meter_certificate_read(struct file
*filp
, struct kobject
*kobj
,
484 struct bin_attribute
*attr
, char *buf
, loff_t off
,
487 struct device
*dev
= kobj_to_dev(kobj
);
488 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
490 return certificate_read(SDSI_CMD_READ_METER
, 0, priv
, buf
, off
, count
);
492 static BIN_ATTR_ADMIN_RO(meter_certificate
, SDSI_SIZE_READ_MSG
);
495 meter_current_read(struct file
*filp
, struct kobject
*kobj
,
496 struct bin_attribute
*attr
, char *buf
, loff_t off
,
499 struct device
*dev
= kobj_to_dev(kobj
);
500 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
502 return certificate_read(SDSI_CMD_READ_METER
, CTRL_METER_ENABLE_DRAM
,
503 priv
, buf
, off
, count
);
505 static BIN_ATTR_ADMIN_RO(meter_current
, SDSI_SIZE_READ_MSG
);
507 static ssize_t
registers_read(struct file
*filp
, struct kobject
*kobj
,
508 struct bin_attribute
*attr
, char *buf
, loff_t off
,
511 struct device
*dev
= kobj_to_dev(kobj
);
512 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
513 void __iomem
*addr
= priv
->regs_addr
;
514 int size
= priv
->registers_size
;
517 * The check below is performed by the sysfs caller based on the static
518 * file size. But this may be greater than the actual size which is based
519 * on the GUID. So check here again based on actual size before reading.
524 if (off
+ count
> size
)
527 memcpy_fromio(buf
, addr
+ off
, count
);
531 static BIN_ATTR_ADMIN_RO(registers
, SDSI_SIZE_REGS
);
533 static struct bin_attribute
*sdsi_bin_attrs
[] = {
535 &bin_attr_state_certificate
,
536 &bin_attr_meter_certificate
,
537 &bin_attr_meter_current
,
538 &bin_attr_provision_akc
,
539 &bin_attr_provision_cap
,
544 sdsi_battr_is_visible(struct kobject
*kobj
, const struct bin_attribute
*attr
, int n
)
546 struct device
*dev
= kobj_to_dev(kobj
);
547 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
549 /* Registers file is always readable if the device is present */
550 if (attr
== &bin_attr_registers
)
551 return attr
->attr
.mode
;
553 /* All other attributes not visible if BIOS has not enabled On Demand */
554 if (!(priv
->features
& SDSI_FEATURE_SDSI
))
557 if (attr
== &bin_attr_meter_certificate
|| attr
== &bin_attr_meter_current
)
558 return (priv
->features
& SDSI_FEATURE_METERING
) ?
561 return attr
->attr
.mode
;
564 static ssize_t
guid_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
566 struct sdsi_priv
*priv
= dev_get_drvdata(dev
);
568 return sysfs_emit(buf
, "0x%x\n", priv
->guid
);
570 static DEVICE_ATTR_RO(guid
);
572 static struct attribute
*sdsi_attrs
[] = {
577 static const struct attribute_group sdsi_group
= {
579 .bin_attrs
= sdsi_bin_attrs
,
580 .is_bin_visible
= sdsi_battr_is_visible
,
582 __ATTRIBUTE_GROUPS(sdsi
);
584 static int sdsi_get_layout(struct sdsi_priv
*priv
, struct disc_table
*table
)
586 switch (table
->guid
) {
588 priv
->control_size
= GUID_V1_CNTRL_SIZE
;
589 priv
->registers_size
= GUID_V1_REGS_SIZE
;
592 priv
->control_size
= GUID_V2_CNTRL_SIZE
;
593 priv
->registers_size
= GUID_V2_REGS_SIZE
;
596 dev_err(priv
->dev
, "Unrecognized GUID 0x%x\n", table
->guid
);
602 static int sdsi_map_mbox_registers(struct sdsi_priv
*priv
, struct pci_dev
*parent
,
603 struct disc_table
*disc_table
, struct resource
*disc_res
)
605 u32 access_type
= FIELD_GET(DT_ACCESS_TYPE
, disc_table
->access_info
);
606 u32 size
= FIELD_GET(DT_SIZE
, disc_table
->access_info
);
607 u32 tbir
= FIELD_GET(DT_TBIR
, disc_table
->offset
);
608 u32 offset
= DT_OFFSET(disc_table
->offset
);
609 struct resource res
= {};
611 /* Starting location of SDSi MMIO region based on access type */
612 switch (access_type
) {
613 case ACCESS_TYPE_LOCAL
:
615 dev_err(priv
->dev
, "Unsupported BAR index %u for access type %u\n",
621 * For access_type LOCAL, the base address is as follows:
622 * base address = end of discovery region + base offset + 1
624 res
.start
= disc_res
->end
+ offset
+ 1;
627 case ACCESS_TYPE_BARID
:
628 res
.start
= pci_resource_start(parent
, tbir
) + offset
;
632 dev_err(priv
->dev
, "Unrecognized access_type %u\n", access_type
);
636 res
.end
= res
.start
+ size
* sizeof(u32
) - 1;
637 res
.flags
= IORESOURCE_MEM
;
639 priv
->control_addr
= devm_ioremap_resource(priv
->dev
, &res
);
640 if (IS_ERR(priv
->control_addr
))
641 return PTR_ERR(priv
->control_addr
);
643 priv
->mbox_addr
= priv
->control_addr
+ priv
->control_size
;
644 priv
->regs_addr
= priv
->mbox_addr
+ SDSI_SIZE_MAILBOX
;
646 priv
->features
= readq(priv
->regs_addr
+ SDSI_ENABLED_FEATURES_OFFSET
);
651 static int sdsi_probe(struct auxiliary_device
*auxdev
, const struct auxiliary_device_id
*id
)
653 struct intel_vsec_device
*intel_cap_dev
= auxdev_to_ivdev(auxdev
);
654 struct disc_table disc_table
;
655 struct resource
*disc_res
;
656 void __iomem
*disc_addr
;
657 struct sdsi_priv
*priv
;
660 priv
= devm_kzalloc(&auxdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
664 priv
->dev
= &auxdev
->dev
;
665 mutex_init(&priv
->mb_lock
);
666 auxiliary_set_drvdata(auxdev
, priv
);
668 /* Get the SDSi discovery table */
669 disc_res
= &intel_cap_dev
->resource
[0];
670 disc_addr
= devm_ioremap_resource(&auxdev
->dev
, disc_res
);
671 if (IS_ERR(disc_addr
))
672 return PTR_ERR(disc_addr
);
674 memcpy_fromio(&disc_table
, disc_addr
, DISC_TABLE_SIZE
);
676 priv
->guid
= disc_table
.guid
;
678 /* Get guid based layout info */
679 ret
= sdsi_get_layout(priv
, &disc_table
);
683 /* Map the SDSi mailbox registers */
684 ret
= sdsi_map_mbox_registers(priv
, intel_cap_dev
->pcidev
, &disc_table
, disc_res
);
691 static const struct auxiliary_device_id sdsi_aux_id_table
[] = {
692 { .name
= "intel_vsec.sdsi" },
695 MODULE_DEVICE_TABLE(auxiliary
, sdsi_aux_id_table
);
697 static struct auxiliary_driver sdsi_aux_driver
= {
699 .dev_groups
= sdsi_groups
,
701 .id_table
= sdsi_aux_id_table
,
703 /* No remove. All resources are handled under devm */
705 module_auxiliary_driver(sdsi_aux_driver
);
707 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
708 MODULE_DESCRIPTION("Intel On Demand (SDSi) driver");
709 MODULE_LICENSE("GPL");