710 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel On Demand (Software Defined Silicon) driver4 *5 * Copyright (c) 2022, Intel Corporation.6 * All Rights Reserved.7 *8 * Author: "David E. Box" <david.e.box@linux.intel.com>9 */10 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>25 26#define ACCESS_TYPE_BARID 227#define ACCESS_TYPE_LOCAL 328 29#define SDSI_MIN_SIZE_DWORDS 27630#define SDSI_SIZE_MAILBOX 102431#define SDSI_SIZE_REGS 8032#define SDSI_SIZE_CMD sizeof(u64)33 34/*35 * Write messages are currently up to the size of the mailbox36 * while read messages are up to 4 times the size of the37 * mailbox, sent in packets38 */39#define SDSI_SIZE_WRITE_MSG SDSI_SIZE_MAILBOX40#define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4)41 42#define SDSI_ENABLED_FEATURES_OFFSET 1643#define SDSI_FEATURE_SDSI BIT(3)44#define SDSI_FEATURE_METERING BIT(26)45 46#define SDSI_SOCKET_ID_OFFSET 6447#define SDSI_SOCKET_ID GENMASK(3, 0)48 49#define SDSI_MBOX_CMD_SUCCESS 0x4050#define SDSI_MBOX_CMD_TIMEOUT 0x8051 52#define MBOX_TIMEOUT_US 50000053#define MBOX_TIMEOUT_ACQUIRE_US 100054#define MBOX_POLLING_PERIOD_US 10055#define MBOX_ACQUIRE_NUM_RETRIES 556#define MBOX_ACQUIRE_RETRY_DELAY_MS 50057#define MBOX_MAX_PACKETS 458 59#define MBOX_OWNER_NONE 0x0060#define MBOX_OWNER_INBAND 0x0161 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)74 75#define DISC_TABLE_SIZE 1276#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))80 81#define SDSI_GUID_V1 0x006DD19182#define GUID_V1_CNTRL_SIZE 883#define GUID_V1_REGS_SIZE 7284#define SDSI_GUID_V2 0xF210D9EF85#define GUID_V2_CNTRL_SIZE 1686#define GUID_V2_REGS_SIZE 8087 88enum sdsi_command {89 SDSI_CMD_PROVISION_AKC = 0x0004,90 SDSI_CMD_PROVISION_CAP = 0x0008,91 SDSI_CMD_READ_STATE = 0x0010,92 SDSI_CMD_READ_METER = 0x0014,93};94 95struct sdsi_mbox_info {96 u64 *payload;97 void *buffer;98 u64 control_flags;99 int size;100};101 102struct disc_table {103 u32 access_info;104 u32 guid;105 u32 offset;106};107 108struct sdsi_priv {109 struct mutex mb_lock; /* Mailbox access lock */110 struct device *dev;111 void __iomem *control_addr;112 void __iomem *mbox_addr;113 void __iomem *regs_addr;114 int control_size;115 int maibox_size;116 int registers_size;117 u32 guid;118 u32 features;119};120 121/* SDSi mailbox operations must be performed using 64bit mov instructions */122static __always_inline void123sdsi_memcpy64_toio(u64 __iomem *to, const u64 *from, size_t count_bytes)124{125 size_t count = count_bytes / sizeof(*to);126 int i;127 128 for (i = 0; i < count; i++)129 writeq(from[i], &to[i]);130}131 132static __always_inline void133sdsi_memcpy64_fromio(u64 *to, const u64 __iomem *from, size_t count_bytes)134{135 size_t count = count_bytes / sizeof(*to);136 int i;137 138 for (i = 0; i < count; i++)139 to[i] = readq(&from[i]);140}141 142static inline void sdsi_complete_transaction(struct sdsi_priv *priv)143{144 u64 control = FIELD_PREP(CTRL_COMPLETE, 1);145 146 lockdep_assert_held(&priv->mb_lock);147 writeq(control, priv->control_addr);148}149 150static int sdsi_status_to_errno(u32 status)151{152 switch (status) {153 case SDSI_MBOX_CMD_SUCCESS:154 return 0;155 case SDSI_MBOX_CMD_TIMEOUT:156 return -ETIMEDOUT;157 default:158 return -EIO;159 }160}161 162static int sdsi_mbox_poll(struct sdsi_priv *priv, struct sdsi_mbox_info *info,163 size_t *data_size)164{165 struct device *dev = priv->dev;166 u32 total, loop, eom, status, message_size;167 u64 control;168 int ret;169 170 lockdep_assert_held(&priv->mb_lock);171 172 /* For reads, data sizes that are larger than the mailbox size are read in packets. */173 total = 0;174 loop = 0;175 do {176 u32 packet_size;177 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);181 if (ret)182 break;183 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);188 189 ret = sdsi_status_to_errno(status);190 if (ret)191 break;192 193 if (!packet_size) {194 sdsi_complete_transaction(priv);195 break;196 }197 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");201 ret = -EPROTO;202 break;203 }204 205 if (packet_size > SDSI_SIZE_MAILBOX) {206 dev_err(dev, "Packet size too large\n");207 ret = -EPROTO;208 break;209 }210 211 if (info->buffer) {212 void *buf = info->buffer + array_size(SDSI_SIZE_MAILBOX, loop);213 214 sdsi_memcpy64_fromio(buf, priv->mbox_addr,215 round_up(packet_size, SDSI_SIZE_CMD));216 total += packet_size;217 }218 219 sdsi_complete_transaction(priv);220 } while (!eom && ++loop < MBOX_MAX_PACKETS);221 222 if (ret) {223 sdsi_complete_transaction(priv);224 return ret;225 }226 227 if (!eom) {228 dev_err(dev, "Exceeded read attempts\n");229 return -EPROTO;230 }231 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);236 237 if (data_size)238 *data_size = total;239 240 return 0;241}242 243static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info,244 size_t *data_size)245{246 u64 control;247 248 lockdep_assert_held(&priv->mb_lock);249 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) |255 info->control_flags;256 writeq(control, priv->control_addr);257 258 return sdsi_mbox_poll(priv, info, data_size);259}260 261static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info,262 size_t *data_size)263{264 u64 control;265 266 lockdep_assert_held(&priv->mb_lock);267 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);271 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);280 281 return sdsi_mbox_poll(priv, info, data_size);282}283 284static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info)285{286 u64 control;287 u32 owner;288 int ret, retries = 0;289 290 lockdep_assert_held(&priv->mb_lock);291 292 /* Check mailbox is available */293 control = readq(priv->control_addr);294 owner = FIELD_GET(CTRL_OWNER, control);295 if (owner != MBOX_OWNER_NONE)296 return -EBUSY;297 298 /*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 it301 * recently it may take up to 2.1 seconds to acquire it again.302 */303 do {304 /* Write first qword of payload */305 writeq(info->payload[0], priv->mbox_addr);306 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);311 312 if (FIELD_GET(CTRL_OWNER, control) == MBOX_OWNER_NONE &&313 retries++ < MBOX_ACQUIRE_NUM_RETRIES) {314 msleep(MBOX_ACQUIRE_RETRY_DELAY_MS);315 continue;316 }317 318 /* Either we got it or someone else did. */319 break;320 } while (true);321 322 return ret;323}324 325static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info,326 size_t *data_size)327{328 int ret;329 330 lockdep_assert_held(&priv->mb_lock);331 332 ret = sdsi_mbox_acquire(priv, info);333 if (ret)334 return ret;335 336 return sdsi_mbox_cmd_write(priv, info, data_size);337}338 339static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size)340{341 int ret;342 343 lockdep_assert_held(&priv->mb_lock);344 345 ret = sdsi_mbox_acquire(priv, info);346 if (ret)347 return ret;348 349 return sdsi_mbox_cmd_read(priv, info, data_size);350}351 352static bool sdsi_ib_locked(struct sdsi_priv *priv)353{354 return !!FIELD_GET(CTRL_INBAND_LOCK, readq(priv->control_addr));355}356 357static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,358 enum sdsi_command command)359{360 struct sdsi_mbox_info info = {};361 int ret;362 363 if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))364 return -EOVERFLOW;365 366 /* Make sure In-band lock is not set */367 if (sdsi_ib_locked(priv))368 return -EPERM;369 370 /* Qword aligned message + command qword */371 info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD;372 373 info.payload = kzalloc(info.size, GFP_KERNEL);374 if (!info.payload)375 return -ENOMEM;376 377 /* Copy message to payload buffer */378 memcpy(info.payload, buf, count);379 380 /* Command is last qword of payload buffer */381 info.payload[(info.size - SDSI_SIZE_CMD) / SDSI_SIZE_CMD] = command;382 383 ret = mutex_lock_interruptible(&priv->mb_lock);384 if (ret)385 goto free_payload;386 387 ret = sdsi_mbox_write(priv, &info, NULL);388 389 mutex_unlock(&priv->mb_lock);390 391free_payload:392 kfree(info.payload);393 394 if (ret)395 return ret;396 397 return count;398}399 400static ssize_t provision_akc_write(struct file *filp, struct kobject *kobj,401 struct bin_attribute *attr, char *buf, loff_t off,402 size_t count)403{404 struct device *dev = kobj_to_dev(kobj);405 struct sdsi_priv *priv = dev_get_drvdata(dev);406 407 if (off)408 return -ESPIPE;409 410 return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_AKC);411}412static BIN_ATTR_WO(provision_akc, SDSI_SIZE_WRITE_MSG);413 414static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,415 struct bin_attribute *attr, char *buf, loff_t off,416 size_t count)417{418 struct device *dev = kobj_to_dev(kobj);419 struct sdsi_priv *priv = dev_get_drvdata(dev);420 421 if (off)422 return -ESPIPE;423 424 return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_CAP);425}426static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);427 428static ssize_t429certificate_read(u64 command, u64 control_flags, struct sdsi_priv *priv,430 char *buf, loff_t off, size_t count)431{432 struct sdsi_mbox_info info = {};433 size_t size;434 int ret;435 436 if (off)437 return 0;438 439 /* Buffer for return data */440 info.buffer = kmalloc(SDSI_SIZE_READ_MSG, GFP_KERNEL);441 if (!info.buffer)442 return -ENOMEM;443 444 info.payload = &command;445 info.size = sizeof(command);446 info.control_flags = control_flags;447 448 ret = mutex_lock_interruptible(&priv->mb_lock);449 if (ret)450 goto free_buffer;451 ret = sdsi_mbox_read(priv, &info, &size);452 mutex_unlock(&priv->mb_lock);453 if (ret < 0)454 goto free_buffer;455 456 if (size > count)457 size = count;458 459 memcpy(buf, info.buffer, size);460 461free_buffer:462 kfree(info.buffer);463 464 if (ret)465 return ret;466 467 return size;468}469 470static ssize_t471state_certificate_read(struct file *filp, struct kobject *kobj,472 struct bin_attribute *attr, char *buf, loff_t off,473 size_t count)474{475 struct device *dev = kobj_to_dev(kobj);476 struct sdsi_priv *priv = dev_get_drvdata(dev);477 478 return certificate_read(SDSI_CMD_READ_STATE, 0, priv, buf, off, count);479}480static BIN_ATTR_ADMIN_RO(state_certificate, SDSI_SIZE_READ_MSG);481 482static ssize_t483meter_certificate_read(struct file *filp, struct kobject *kobj,484 struct bin_attribute *attr, char *buf, loff_t off,485 size_t count)486{487 struct device *dev = kobj_to_dev(kobj);488 struct sdsi_priv *priv = dev_get_drvdata(dev);489 490 return certificate_read(SDSI_CMD_READ_METER, 0, priv, buf, off, count);491}492static BIN_ATTR_ADMIN_RO(meter_certificate, SDSI_SIZE_READ_MSG);493 494static ssize_t495meter_current_read(struct file *filp, struct kobject *kobj,496 struct bin_attribute *attr, char *buf, loff_t off,497 size_t count)498{499 struct device *dev = kobj_to_dev(kobj);500 struct sdsi_priv *priv = dev_get_drvdata(dev);501 502 return certificate_read(SDSI_CMD_READ_METER, CTRL_METER_ENABLE_DRAM,503 priv, buf, off, count);504}505static BIN_ATTR_ADMIN_RO(meter_current, SDSI_SIZE_READ_MSG);506 507static ssize_t registers_read(struct file *filp, struct kobject *kobj,508 struct bin_attribute *attr, char *buf, loff_t off,509 size_t count)510{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;515 516 /*517 * The check below is performed by the sysfs caller based on the static518 * file size. But this may be greater than the actual size which is based519 * on the GUID. So check here again based on actual size before reading.520 */521 if (off >= size)522 return 0;523 524 if (off + count > size)525 count = size - off;526 527 memcpy_fromio(buf, addr + off, count);528 529 return count;530}531static BIN_ATTR_ADMIN_RO(registers, SDSI_SIZE_REGS);532 533static struct bin_attribute *sdsi_bin_attrs[] = {534 &bin_attr_registers,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,540 NULL541};542 543static umode_t544sdsi_battr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int n)545{546 struct device *dev = kobj_to_dev(kobj);547 struct sdsi_priv *priv = dev_get_drvdata(dev);548 549 /* Registers file is always readable if the device is present */550 if (attr == &bin_attr_registers)551 return attr->attr.mode;552 553 /* All other attributes not visible if BIOS has not enabled On Demand */554 if (!(priv->features & SDSI_FEATURE_SDSI))555 return 0;556 557 if (attr == &bin_attr_meter_certificate || attr == &bin_attr_meter_current)558 return (priv->features & SDSI_FEATURE_METERING) ?559 attr->attr.mode : 0;560 561 return attr->attr.mode;562}563 564static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)565{566 struct sdsi_priv *priv = dev_get_drvdata(dev);567 568 return sysfs_emit(buf, "0x%x\n", priv->guid);569}570static DEVICE_ATTR_RO(guid);571 572static struct attribute *sdsi_attrs[] = {573 &dev_attr_guid.attr,574 NULL575};576 577static const struct attribute_group sdsi_group = {578 .attrs = sdsi_attrs,579 .bin_attrs = sdsi_bin_attrs,580 .is_bin_visible = sdsi_battr_is_visible,581};582__ATTRIBUTE_GROUPS(sdsi);583 584static int sdsi_get_layout(struct sdsi_priv *priv, struct disc_table *table)585{586 switch (table->guid) {587 case SDSI_GUID_V1:588 priv->control_size = GUID_V1_CNTRL_SIZE;589 priv->registers_size = GUID_V1_REGS_SIZE;590 break;591 case SDSI_GUID_V2:592 priv->control_size = GUID_V2_CNTRL_SIZE;593 priv->registers_size = GUID_V2_REGS_SIZE;594 break;595 default:596 dev_err(priv->dev, "Unrecognized GUID 0x%x\n", table->guid);597 return -EINVAL;598 }599 return 0;600}601 602static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,603 struct disc_table *disc_table, struct resource *disc_res)604{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 = {};610 611 /* Starting location of SDSi MMIO region based on access type */612 switch (access_type) {613 case ACCESS_TYPE_LOCAL:614 if (tbir) {615 dev_err(priv->dev, "Unsupported BAR index %u for access type %u\n",616 tbir, access_type);617 return -EINVAL;618 }619 620 /*621 * For access_type LOCAL, the base address is as follows:622 * base address = end of discovery region + base offset + 1623 */624 res.start = disc_res->end + offset + 1;625 break;626 627 case ACCESS_TYPE_BARID:628 res.start = pci_resource_start(parent, tbir) + offset;629 break;630 631 default:632 dev_err(priv->dev, "Unrecognized access_type %u\n", access_type);633 return -EINVAL;634 }635 636 res.end = res.start + size * sizeof(u32) - 1;637 res.flags = IORESOURCE_MEM;638 639 priv->control_addr = devm_ioremap_resource(priv->dev, &res);640 if (IS_ERR(priv->control_addr))641 return PTR_ERR(priv->control_addr);642 643 priv->mbox_addr = priv->control_addr + priv->control_size;644 priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;645 646 priv->features = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);647 648 return 0;649}650 651static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)652{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;658 int ret;659 660 priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);661 if (!priv)662 return -ENOMEM;663 664 priv->dev = &auxdev->dev;665 mutex_init(&priv->mb_lock);666 auxiliary_set_drvdata(auxdev, priv);667 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);673 674 memcpy_fromio(&disc_table, disc_addr, DISC_TABLE_SIZE);675 676 priv->guid = disc_table.guid;677 678 /* Get guid based layout info */679 ret = sdsi_get_layout(priv, &disc_table);680 if (ret)681 return ret;682 683 /* Map the SDSi mailbox registers */684 ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);685 if (ret)686 return ret;687 688 return 0;689}690 691static const struct auxiliary_device_id sdsi_aux_id_table[] = {692 { .name = "intel_vsec.sdsi" },693 {}694};695MODULE_DEVICE_TABLE(auxiliary, sdsi_aux_id_table);696 697static struct auxiliary_driver sdsi_aux_driver = {698 .driver = {699 .dev_groups = sdsi_groups,700 },701 .id_table = sdsi_aux_id_table,702 .probe = sdsi_probe,703 /* No remove. All resources are handled under devm */704};705module_auxiliary_driver(sdsi_aux_driver);706 707MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");708MODULE_DESCRIPTION("Intel On Demand (SDSi) driver");709MODULE_LICENSE("GPL");710