764 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/device.h>4#include <linux/err.h>5#include <linux/errno.h>6#include <linux/fs.h>7#include <linux/fsi-sbefifo.h>8#include <linux/gfp.h>9#include <linux/idr.h>10#include <linux/kernel.h>11#include <linux/list.h>12#include <linux/miscdevice.h>13#include <linux/mm.h>14#include <linux/module.h>15#include <linux/mutex.h>16#include <linux/fsi-occ.h>17#include <linux/of.h>18#include <linux/of_platform.h>19#include <linux/platform_device.h>20#include <linux/sched.h>21#include <linux/slab.h>22#include <linux/uaccess.h>23#include <linux/unaligned.h>24 25#define OCC_SRAM_BYTES 409626#define OCC_CMD_DATA_BYTES 409027#define OCC_RESP_DATA_BYTES 408928 29#define OCC_P9_SRAM_CMD_ADDR 0xFFFBE00030#define OCC_P9_SRAM_RSP_ADDR 0xFFFBF00031 32#define OCC_P10_SRAM_CMD_ADDR 0xFFFFD00033#define OCC_P10_SRAM_RSP_ADDR 0xFFFFE00034 35#define OCC_P10_SRAM_MODE 0x58 /* Normal mode, OCB channel 2 */36 37#define OCC_TIMEOUT_MS 100038#define OCC_CMD_IN_PRG_WAIT_MS 5039 40enum versions { occ_p9, occ_p10 };41 42struct occ {43 struct device *dev;44 struct device *sbefifo;45 char name[32];46 int idx;47 bool platform_hwmon;48 u8 sequence_number;49 void *buffer;50 void *client_buffer;51 size_t client_buffer_size;52 size_t client_response_size;53 enum versions version;54 struct miscdevice mdev;55 struct mutex occ_lock;56};57 58#define to_occ(x) container_of((x), struct occ, mdev)59 60struct occ_response {61 u8 seq_no;62 u8 cmd_type;63 u8 return_status;64 __be16 data_length;65 u8 data[OCC_RESP_DATA_BYTES + 2]; /* two bytes checksum */66} __packed;67 68struct occ_client {69 struct occ *occ;70 struct mutex lock;71 size_t data_size;72 size_t read_offset;73 u8 *buffer;74};75 76#define to_client(x) container_of((x), struct occ_client, xfr)77 78static DEFINE_IDA(occ_ida);79 80static int occ_open(struct inode *inode, struct file *file)81{82 struct occ_client *client = kzalloc(sizeof(*client), GFP_KERNEL);83 struct miscdevice *mdev = file->private_data;84 struct occ *occ = to_occ(mdev);85 86 if (!client)87 return -ENOMEM;88 89 client->buffer = (u8 *)__get_free_page(GFP_KERNEL);90 if (!client->buffer) {91 kfree(client);92 return -ENOMEM;93 }94 95 client->occ = occ;96 mutex_init(&client->lock);97 file->private_data = client;98 get_device(occ->dev);99 100 /* We allocate a 1-page buffer, make sure it all fits */101 BUILD_BUG_ON((OCC_CMD_DATA_BYTES + 3) > PAGE_SIZE);102 BUILD_BUG_ON((OCC_RESP_DATA_BYTES + 7) > PAGE_SIZE);103 104 return 0;105}106 107static ssize_t occ_read(struct file *file, char __user *buf, size_t len,108 loff_t *offset)109{110 struct occ_client *client = file->private_data;111 ssize_t rc = 0;112 113 if (!client)114 return -ENODEV;115 116 if (len > OCC_SRAM_BYTES)117 return -EINVAL;118 119 mutex_lock(&client->lock);120 121 /* This should not be possible ... */122 if (WARN_ON_ONCE(client->read_offset > client->data_size)) {123 rc = -EIO;124 goto done;125 }126 127 /* Grab how much data we have to read */128 rc = min(len, client->data_size - client->read_offset);129 if (copy_to_user(buf, client->buffer + client->read_offset, rc))130 rc = -EFAULT;131 else132 client->read_offset += rc;133 134 done:135 mutex_unlock(&client->lock);136 137 return rc;138}139 140static ssize_t occ_write(struct file *file, const char __user *buf,141 size_t len, loff_t *offset)142{143 struct occ_client *client = file->private_data;144 size_t rlen, data_length;145 ssize_t rc;146 u8 *cmd;147 148 if (!client)149 return -ENODEV;150 151 if (len > (OCC_CMD_DATA_BYTES + 3) || len < 3)152 return -EINVAL;153 154 mutex_lock(&client->lock);155 156 /* Construct the command */157 cmd = client->buffer;158 159 /*160 * Copy the user command (assume user data follows the occ command161 * format)162 * byte 0: command type163 * bytes 1-2: data length (msb first)164 * bytes 3-n: data165 */166 if (copy_from_user(&cmd[1], buf, len)) {167 rc = -EFAULT;168 goto done;169 }170 171 /* Extract data length */172 data_length = (cmd[2] << 8) + cmd[3];173 if (data_length > OCC_CMD_DATA_BYTES) {174 rc = -EINVAL;175 goto done;176 }177 178 /* Submit command; 4 bytes before the data and 2 bytes after */179 rlen = PAGE_SIZE;180 rc = fsi_occ_submit(client->occ->dev, cmd, data_length + 6, cmd,181 &rlen);182 if (rc)183 goto done;184 185 /* Set read tracking data */186 client->data_size = rlen;187 client->read_offset = 0;188 189 /* Done */190 rc = len;191 192 done:193 mutex_unlock(&client->lock);194 195 return rc;196}197 198static int occ_release(struct inode *inode, struct file *file)199{200 struct occ_client *client = file->private_data;201 202 put_device(client->occ->dev);203 free_page((unsigned long)client->buffer);204 kfree(client);205 206 return 0;207}208 209static const struct file_operations occ_fops = {210 .owner = THIS_MODULE,211 .open = occ_open,212 .read = occ_read,213 .write = occ_write,214 .release = occ_release,215};216 217static void occ_save_ffdc(struct occ *occ, __be32 *resp, size_t parsed_len,218 size_t resp_len)219{220 if (resp_len > parsed_len) {221 size_t dh = resp_len - parsed_len;222 size_t ffdc_len = (dh - 1) * 4; /* SBE words are four bytes */223 __be32 *ffdc = &resp[parsed_len];224 225 if (ffdc_len > occ->client_buffer_size)226 ffdc_len = occ->client_buffer_size;227 228 memcpy(occ->client_buffer, ffdc, ffdc_len);229 occ->client_response_size = ffdc_len;230 }231}232 233static int occ_verify_checksum(struct occ *occ, struct occ_response *resp,234 u16 data_length)235{236 /* Fetch the two bytes after the data for the checksum. */237 u16 checksum_resp = get_unaligned_be16(&resp->data[data_length]);238 u16 checksum;239 u16 i;240 241 checksum = resp->seq_no;242 checksum += resp->cmd_type;243 checksum += resp->return_status;244 checksum += (data_length >> 8) + (data_length & 0xFF);245 246 for (i = 0; i < data_length; ++i)247 checksum += resp->data[i];248 249 if (checksum != checksum_resp) {250 dev_err(occ->dev, "Bad checksum: %04x!=%04x\n", checksum,251 checksum_resp);252 return -EBADE;253 }254 255 return 0;256}257 258static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)259{260 u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */261 size_t cmd_len, parsed_len, resp_data_len;262 size_t resp_len = OCC_MAX_RESP_WORDS;263 __be32 *resp = occ->buffer;264 __be32 cmd[6];265 int idx = 0, rc;266 267 /*268 * Magic sequence to do SBE getsram command. SBE will fetch data from269 * specified SRAM address.270 */271 switch (occ->version) {272 default:273 case occ_p9:274 cmd_len = 5;275 cmd[2] = cpu_to_be32(1); /* Normal mode */276 cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);277 break;278 case occ_p10:279 idx = 1;280 cmd_len = 6;281 cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);282 cmd[3] = 0;283 cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);284 break;285 }286 287 cmd[0] = cpu_to_be32(cmd_len);288 cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);289 cmd[4 + idx] = cpu_to_be32(data_len);290 291 rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);292 if (rc)293 return rc;294 295 rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_GET_OCC_SRAM,296 resp, resp_len, &parsed_len);297 if (rc > 0) {298 dev_err(occ->dev, "SRAM read returned failure status: %08x\n",299 rc);300 occ_save_ffdc(occ, resp, parsed_len, resp_len);301 return -ECOMM;302 } else if (rc) {303 return rc;304 }305 306 resp_data_len = be32_to_cpu(resp[parsed_len - 1]);307 if (resp_data_len != data_len) {308 dev_err(occ->dev, "SRAM read expected %d bytes got %zd\n",309 data_len, resp_data_len);310 rc = -EBADMSG;311 } else {312 memcpy(data, resp, len);313 }314 315 return rc;316}317 318static int occ_putsram(struct occ *occ, const void *data, ssize_t len,319 u8 seq_no, u16 checksum)320{321 u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */322 size_t cmd_len, parsed_len, resp_data_len;323 size_t resp_len = OCC_MAX_RESP_WORDS;324 __be32 *buf = occ->buffer;325 u8 *byte_buf;326 int idx = 0, rc;327 328 cmd_len = (occ->version == occ_p10) ? 6 : 5;329 cmd_len += data_len >> 2;330 331 /*332 * Magic sequence to do SBE putsram command. SBE will transfer333 * data to specified SRAM address.334 */335 buf[0] = cpu_to_be32(cmd_len);336 buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);337 338 switch (occ->version) {339 default:340 case occ_p9:341 buf[2] = cpu_to_be32(1); /* Normal mode */342 buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);343 break;344 case occ_p10:345 idx = 1;346 buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);347 buf[3] = 0;348 buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);349 break;350 }351 352 buf[4 + idx] = cpu_to_be32(data_len);353 memcpy(&buf[5 + idx], data, len);354 355 byte_buf = (u8 *)&buf[5 + idx];356 /*357 * Overwrite the first byte with our sequence number and the last two358 * bytes with the checksum.359 */360 byte_buf[0] = seq_no;361 byte_buf[len - 2] = checksum >> 8;362 byte_buf[len - 1] = checksum & 0xff;363 364 rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);365 if (rc)366 return rc;367 368 rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_PUT_OCC_SRAM,369 buf, resp_len, &parsed_len);370 if (rc > 0) {371 dev_err(occ->dev, "SRAM write returned failure status: %08x\n",372 rc);373 occ_save_ffdc(occ, buf, parsed_len, resp_len);374 return -ECOMM;375 } else if (rc) {376 return rc;377 }378 379 if (parsed_len != 1) {380 dev_err(occ->dev, "SRAM write response length invalid: %zd\n",381 parsed_len);382 rc = -EBADMSG;383 } else {384 resp_data_len = be32_to_cpu(buf[0]);385 if (resp_data_len != data_len) {386 dev_err(occ->dev,387 "SRAM write expected %d bytes got %zd\n",388 data_len, resp_data_len);389 rc = -EBADMSG;390 }391 }392 393 return rc;394}395 396static int occ_trigger_attn(struct occ *occ)397{398 __be32 *buf = occ->buffer;399 size_t cmd_len, parsed_len, resp_data_len;400 size_t resp_len = OCC_MAX_RESP_WORDS;401 int idx = 0, rc;402 403 switch (occ->version) {404 default:405 case occ_p9:406 cmd_len = 7;407 buf[2] = cpu_to_be32(3); /* Circular mode */408 buf[3] = 0;409 break;410 case occ_p10:411 idx = 1;412 cmd_len = 8;413 buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */414 buf[3] = 0;415 buf[4] = 0;416 break;417 }418 419 buf[0] = cpu_to_be32(cmd_len); /* Chip-op length in words */420 buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);421 buf[4 + idx] = cpu_to_be32(8); /* Data length in bytes */422 buf[5 + idx] = cpu_to_be32(0x20010000); /* Trigger OCC attention */423 buf[6 + idx] = 0;424 425 rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);426 if (rc)427 return rc;428 429 rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_PUT_OCC_SRAM,430 buf, resp_len, &parsed_len);431 if (rc > 0) {432 dev_err(occ->dev, "SRAM attn returned failure status: %08x\n",433 rc);434 occ_save_ffdc(occ, buf, parsed_len, resp_len);435 return -ECOMM;436 } else if (rc) {437 return rc;438 }439 440 if (parsed_len != 1) {441 dev_err(occ->dev, "SRAM attn response length invalid: %zd\n",442 parsed_len);443 rc = -EBADMSG;444 } else {445 resp_data_len = be32_to_cpu(buf[0]);446 if (resp_data_len != 8) {447 dev_err(occ->dev,448 "SRAM attn expected 8 bytes got %zd\n",449 resp_data_len);450 rc = -EBADMSG;451 }452 }453 454 return rc;455}456 457static bool fsi_occ_response_not_ready(struct occ_response *resp, u8 seq_no,458 u8 cmd_type)459{460 return resp->return_status == OCC_RESP_CMD_IN_PRG ||461 resp->return_status == OCC_RESP_CRIT_INIT ||462 resp->seq_no != seq_no || resp->cmd_type != cmd_type;463}464 465int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,466 void *response, size_t *resp_len)467{468 const unsigned long timeout = msecs_to_jiffies(OCC_TIMEOUT_MS);469 const unsigned long wait_time =470 msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS);471 struct occ *occ = dev_get_drvdata(dev);472 struct occ_response *resp = response;473 size_t user_resp_len = *resp_len;474 u8 seq_no;475 u8 cmd_type;476 u16 checksum = 0;477 u16 resp_data_length;478 const u8 *byte_request = (const u8 *)request;479 unsigned long end;480 int rc;481 size_t i;482 483 *resp_len = 0;484 485 if (!occ)486 return -ENODEV;487 488 if (user_resp_len < 7) {489 dev_dbg(dev, "Bad resplen %zd\n", user_resp_len);490 return -EINVAL;491 }492 493 cmd_type = byte_request[1];494 495 /* Checksum the request, ignoring first byte (sequence number). */496 for (i = 1; i < req_len - 2; ++i)497 checksum += byte_request[i];498 499 rc = mutex_lock_interruptible(&occ->occ_lock);500 if (rc)501 return rc;502 503 occ->client_buffer = response;504 occ->client_buffer_size = user_resp_len;505 occ->client_response_size = 0;506 507 if (!occ->buffer) {508 rc = -ENOENT;509 goto done;510 }511 512 /*513 * Get a sequence number and update the counter. Avoid a sequence514 * number of 0 which would pass the response check below even if the515 * OCC response is uninitialized. Any sequence number the user is516 * trying to send is overwritten since this function is the only common517 * interface to the OCC and therefore the only place we can guarantee518 * unique sequence numbers.519 */520 seq_no = occ->sequence_number++;521 if (!occ->sequence_number)522 occ->sequence_number = 1;523 checksum += seq_no;524 525 rc = occ_putsram(occ, request, req_len, seq_no, checksum);526 if (rc)527 goto done;528 529 rc = occ_trigger_attn(occ);530 if (rc)531 goto done;532 533 end = jiffies + timeout;534 while (true) {535 /* Read occ response header */536 rc = occ_getsram(occ, 0, resp, 8);537 if (rc)538 goto done;539 540 if (fsi_occ_response_not_ready(resp, seq_no, cmd_type)) {541 if (time_after(jiffies, end)) {542 dev_err(occ->dev,543 "resp timeout status=%02x seq=%d cmd=%d, our seq=%d cmd=%d\n",544 resp->return_status, resp->seq_no,545 resp->cmd_type, seq_no, cmd_type);546 rc = -ETIMEDOUT;547 goto done;548 }549 550 set_current_state(TASK_UNINTERRUPTIBLE);551 schedule_timeout(wait_time);552 } else {553 /* Extract size of response data */554 resp_data_length =555 get_unaligned_be16(&resp->data_length);556 557 /*558 * Message size is data length + 5 bytes header + 2559 * bytes checksum560 */561 if ((resp_data_length + 7) > user_resp_len) {562 rc = -EMSGSIZE;563 goto done;564 }565 566 /*567 * Get the entire response including the header again,568 * in case it changed569 */570 if (resp_data_length > 1) {571 rc = occ_getsram(occ, 0, resp,572 resp_data_length + 7);573 if (rc)574 goto done;575 576 if (!fsi_occ_response_not_ready(resp, seq_no,577 cmd_type))578 break;579 } else {580 break;581 }582 }583 }584 585 dev_dbg(dev, "resp_status=%02x resp_data_len=%d\n",586 resp->return_status, resp_data_length);587 588 rc = occ_verify_checksum(occ, resp, resp_data_length);589 if (rc)590 goto done;591 592 occ->client_response_size = resp_data_length + 7;593 594 done:595 *resp_len = occ->client_response_size;596 mutex_unlock(&occ->occ_lock);597 598 return rc;599}600EXPORT_SYMBOL_GPL(fsi_occ_submit);601 602static int occ_unregister_platform_child(struct device *dev, void *data)603{604 struct platform_device *hwmon_dev = to_platform_device(dev);605 606 platform_device_unregister(hwmon_dev);607 608 return 0;609}610 611static int occ_unregister_of_child(struct device *dev, void *data)612{613 struct platform_device *hwmon_dev = to_platform_device(dev);614 615 of_device_unregister(hwmon_dev);616 if (dev->of_node)617 of_node_clear_flag(dev->of_node, OF_POPULATED);618 619 return 0;620}621 622static int occ_probe(struct platform_device *pdev)623{624 int rc;625 u32 reg;626 char child_name[32];627 struct occ *occ;628 struct platform_device *hwmon_dev = NULL;629 struct device_node *hwmon_node;630 struct device *dev = &pdev->dev;631 struct platform_device_info hwmon_dev_info = {632 .parent = dev,633 .name = "occ-hwmon",634 };635 636 occ = devm_kzalloc(dev, sizeof(*occ), GFP_KERNEL);637 if (!occ)638 return -ENOMEM;639 640 /* SBE words are always four bytes */641 occ->buffer = kvmalloc(OCC_MAX_RESP_WORDS * 4, GFP_KERNEL);642 if (!occ->buffer)643 return -ENOMEM;644 645 occ->version = (uintptr_t)of_device_get_match_data(dev);646 occ->dev = dev;647 occ->sbefifo = dev->parent;648 /*649 * Quickly derive a pseudo-random number from jiffies so that650 * re-probing the driver doesn't accidentally overlap sequence numbers.651 */652 occ->sequence_number = (u8)((jiffies % 0xff) + 1);653 mutex_init(&occ->occ_lock);654 655 if (dev->of_node) {656 rc = of_property_read_u32(dev->of_node, "reg", ®);657 if (!rc) {658 /* make sure we don't have a duplicate from dts */659 occ->idx = ida_alloc_range(&occ_ida, reg, reg,660 GFP_KERNEL);661 if (occ->idx < 0)662 occ->idx = ida_alloc_min(&occ_ida, 1,663 GFP_KERNEL);664 } else {665 occ->idx = ida_alloc_min(&occ_ida, 1, GFP_KERNEL);666 }667 } else {668 occ->idx = ida_alloc_min(&occ_ida, 1, GFP_KERNEL);669 }670 671 platform_set_drvdata(pdev, occ);672 673 snprintf(occ->name, sizeof(occ->name), "occ%d", occ->idx);674 occ->mdev.fops = &occ_fops;675 occ->mdev.minor = MISC_DYNAMIC_MINOR;676 occ->mdev.name = occ->name;677 occ->mdev.parent = dev;678 679 rc = misc_register(&occ->mdev);680 if (rc) {681 dev_err(dev, "failed to register miscdevice: %d\n", rc);682 ida_free(&occ_ida, occ->idx);683 kvfree(occ->buffer);684 return rc;685 }686 687 hwmon_node = of_get_child_by_name(dev->of_node, hwmon_dev_info.name);688 if (hwmon_node) {689 snprintf(child_name, sizeof(child_name), "%s.%d", hwmon_dev_info.name, occ->idx);690 hwmon_dev = of_platform_device_create(hwmon_node, child_name, dev);691 of_node_put(hwmon_node);692 }693 694 if (!hwmon_dev) {695 occ->platform_hwmon = true;696 hwmon_dev_info.id = occ->idx;697 hwmon_dev = platform_device_register_full(&hwmon_dev_info);698 if (IS_ERR(hwmon_dev))699 dev_warn(dev, "failed to create hwmon device\n");700 }701 702 return 0;703}704 705static void occ_remove(struct platform_device *pdev)706{707 struct occ *occ = platform_get_drvdata(pdev);708 709 misc_deregister(&occ->mdev);710 711 mutex_lock(&occ->occ_lock);712 kvfree(occ->buffer);713 occ->buffer = NULL;714 mutex_unlock(&occ->occ_lock);715 716 if (occ->platform_hwmon)717 device_for_each_child(&pdev->dev, NULL, occ_unregister_platform_child);718 else719 device_for_each_child(&pdev->dev, NULL, occ_unregister_of_child);720 721 ida_free(&occ_ida, occ->idx);722}723 724static const struct of_device_id occ_match[] = {725 {726 .compatible = "ibm,p9-occ",727 .data = (void *)occ_p9728 },729 {730 .compatible = "ibm,p10-occ",731 .data = (void *)occ_p10732 },733 { },734};735MODULE_DEVICE_TABLE(of, occ_match);736 737static struct platform_driver occ_driver = {738 .driver = {739 .name = "occ",740 .of_match_table = occ_match,741 },742 .probe = occ_probe,743 .remove_new = occ_remove,744};745 746static int occ_init(void)747{748 return platform_driver_register(&occ_driver);749}750 751static void occ_exit(void)752{753 platform_driver_unregister(&occ_driver);754 755 ida_destroy(&occ_ida);756}757 758module_init(occ_init);759module_exit(occ_exit);760 761MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");762MODULE_DESCRIPTION("BMC P9 OCC driver");763MODULE_LICENSE("GPL");764