fsi-scom.c (14600B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * SCOM FSI Client device driver 4 * 5 * Copyright (C) IBM Corporation 2016 6 */ 7 8#include <linux/fsi.h> 9#include <linux/module.h> 10#include <linux/cdev.h> 11#include <linux/delay.h> 12#include <linux/fs.h> 13#include <linux/uaccess.h> 14#include <linux/slab.h> 15#include <linux/list.h> 16 17#include <uapi/linux/fsi.h> 18 19#define FSI_ENGID_SCOM 0x5 20 21/* SCOM engine register set */ 22#define SCOM_DATA0_REG 0x00 23#define SCOM_DATA1_REG 0x04 24#define SCOM_CMD_REG 0x08 25#define SCOM_FSI2PIB_RESET_REG 0x18 26#define SCOM_STATUS_REG 0x1C /* Read */ 27#define SCOM_PIB_RESET_REG 0x1C /* Write */ 28 29/* Command register */ 30#define SCOM_WRITE_CMD 0x80000000 31#define SCOM_READ_CMD 0x00000000 32 33/* Status register bits */ 34#define SCOM_STATUS_ERR_SUMMARY 0x80000000 35#define SCOM_STATUS_PROTECTION 0x01000000 36#define SCOM_STATUS_PARITY 0x04000000 37#define SCOM_STATUS_PIB_ABORT 0x00100000 38#define SCOM_STATUS_PIB_RESP_MASK 0x00007000 39#define SCOM_STATUS_PIB_RESP_SHIFT 12 40 41#define SCOM_STATUS_FSI2PIB_ERROR (SCOM_STATUS_PROTECTION | \ 42 SCOM_STATUS_PARITY | \ 43 SCOM_STATUS_PIB_ABORT) 44#define SCOM_STATUS_ANY_ERR (SCOM_STATUS_FSI2PIB_ERROR | \ 45 SCOM_STATUS_PIB_RESP_MASK) 46/* SCOM address encodings */ 47#define XSCOM_ADDR_IND_FLAG BIT_ULL(63) 48#define XSCOM_ADDR_INF_FORM1 BIT_ULL(60) 49 50/* SCOM indirect stuff */ 51#define XSCOM_ADDR_DIRECT_PART 0x7fffffffull 52#define XSCOM_ADDR_INDIRECT_PART 0x000fffff00000000ull 53#define XSCOM_DATA_IND_READ BIT_ULL(63) 54#define XSCOM_DATA_IND_COMPLETE BIT_ULL(31) 55#define XSCOM_DATA_IND_ERR_MASK 0x70000000ull 56#define XSCOM_DATA_IND_ERR_SHIFT 28 57#define XSCOM_DATA_IND_DATA 0x0000ffffull 58#define XSCOM_DATA_IND_FORM1_DATA 0x000fffffffffffffull 59#define XSCOM_ADDR_FORM1_LOW 0x000ffffffffull 60#define XSCOM_ADDR_FORM1_HI 0xfff00000000ull 61#define XSCOM_ADDR_FORM1_HI_SHIFT 20 62 63/* Retries */ 64#define SCOM_MAX_IND_RETRIES 10 /* Retries indirect not ready */ 65 66struct scom_device { 67 struct list_head link; 68 struct fsi_device *fsi_dev; 69 struct device dev; 70 struct cdev cdev; 71 struct mutex lock; 72 bool dead; 73}; 74 75static int __put_scom(struct scom_device *scom_dev, uint64_t value, 76 uint32_t addr, uint32_t *status) 77{ 78 __be32 data, raw_status; 79 int rc; 80 81 data = cpu_to_be32((value >> 32) & 0xffffffff); 82 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data, 83 sizeof(uint32_t)); 84 if (rc) 85 return rc; 86 87 data = cpu_to_be32(value & 0xffffffff); 88 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data, 89 sizeof(uint32_t)); 90 if (rc) 91 return rc; 92 93 data = cpu_to_be32(SCOM_WRITE_CMD | addr); 94 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, 95 sizeof(uint32_t)); 96 if (rc) 97 return rc; 98 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status, 99 sizeof(uint32_t)); 100 if (rc) 101 return rc; 102 *status = be32_to_cpu(raw_status); 103 104 return 0; 105} 106 107static int __get_scom(struct scom_device *scom_dev, uint64_t *value, 108 uint32_t addr, uint32_t *status) 109{ 110 __be32 data, raw_status; 111 int rc; 112 113 114 *value = 0ULL; 115 data = cpu_to_be32(SCOM_READ_CMD | addr); 116 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, 117 sizeof(uint32_t)); 118 if (rc) 119 return rc; 120 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status, 121 sizeof(uint32_t)); 122 if (rc) 123 return rc; 124 125 /* 126 * Read the data registers even on error, so we don't have 127 * to interpret the status register here. 128 */ 129 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &data, 130 sizeof(uint32_t)); 131 if (rc) 132 return rc; 133 *value |= (uint64_t)be32_to_cpu(data) << 32; 134 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &data, 135 sizeof(uint32_t)); 136 if (rc) 137 return rc; 138 *value |= be32_to_cpu(data); 139 *status = be32_to_cpu(raw_status); 140 141 return rc; 142} 143 144static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value, 145 uint64_t addr, uint32_t *status) 146{ 147 uint64_t ind_data, ind_addr; 148 int rc, err; 149 150 if (value & ~XSCOM_DATA_IND_DATA) 151 return -EINVAL; 152 153 ind_addr = addr & XSCOM_ADDR_DIRECT_PART; 154 ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | value; 155 rc = __put_scom(scom, ind_data, ind_addr, status); 156 if (rc || (*status & SCOM_STATUS_ANY_ERR)) 157 return rc; 158 159 rc = __get_scom(scom, &ind_data, addr, status); 160 if (rc || (*status & SCOM_STATUS_ANY_ERR)) 161 return rc; 162 163 err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; 164 *status = err << SCOM_STATUS_PIB_RESP_SHIFT; 165 166 return 0; 167} 168 169static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value, 170 uint64_t addr, uint32_t *status) 171{ 172 uint64_t ind_data, ind_addr; 173 174 if (value & ~XSCOM_DATA_IND_FORM1_DATA) 175 return -EINVAL; 176 177 ind_addr = addr & XSCOM_ADDR_FORM1_LOW; 178 ind_data = value | (addr & XSCOM_ADDR_FORM1_HI) << XSCOM_ADDR_FORM1_HI_SHIFT; 179 return __put_scom(scom, ind_data, ind_addr, status); 180} 181 182static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value, 183 uint64_t addr, uint32_t *status) 184{ 185 uint64_t ind_data, ind_addr; 186 int rc, err; 187 188 ind_addr = addr & XSCOM_ADDR_DIRECT_PART; 189 ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ; 190 rc = __put_scom(scom, ind_data, ind_addr, status); 191 if (rc || (*status & SCOM_STATUS_ANY_ERR)) 192 return rc; 193 194 rc = __get_scom(scom, &ind_data, addr, status); 195 if (rc || (*status & SCOM_STATUS_ANY_ERR)) 196 return rc; 197 198 err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; 199 *status = err << SCOM_STATUS_PIB_RESP_SHIFT; 200 *value = ind_data & XSCOM_DATA_IND_DATA; 201 202 return 0; 203} 204 205static int raw_put_scom(struct scom_device *scom, uint64_t value, 206 uint64_t addr, uint32_t *status) 207{ 208 if (addr & XSCOM_ADDR_IND_FLAG) { 209 if (addr & XSCOM_ADDR_INF_FORM1) 210 return put_indirect_scom_form1(scom, value, addr, status); 211 else 212 return put_indirect_scom_form0(scom, value, addr, status); 213 } else 214 return __put_scom(scom, value, addr, status); 215} 216 217static int raw_get_scom(struct scom_device *scom, uint64_t *value, 218 uint64_t addr, uint32_t *status) 219{ 220 if (addr & XSCOM_ADDR_IND_FLAG) { 221 if (addr & XSCOM_ADDR_INF_FORM1) 222 return -ENXIO; 223 return get_indirect_scom_form0(scom, value, addr, status); 224 } else 225 return __get_scom(scom, value, addr, status); 226} 227 228static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status) 229{ 230 uint32_t dummy = -1; 231 232 if (status & SCOM_STATUS_FSI2PIB_ERROR) 233 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy, 234 sizeof(uint32_t)); 235 236 if (status & SCOM_STATUS_PROTECTION) 237 return -EPERM; 238 if (status & SCOM_STATUS_PARITY) 239 return -EIO; 240 241 if (status & SCOM_STATUS_PIB_ABORT) 242 return -EBUSY; 243 return 0; 244} 245 246static int handle_pib_status(struct scom_device *scom, uint8_t status) 247{ 248 uint32_t dummy = -1; 249 250 if (status == SCOM_PIB_SUCCESS) 251 return 0; 252 if (status == SCOM_PIB_BLOCKED) 253 return -EBUSY; 254 255 /* Reset the bridge */ 256 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy, 257 sizeof(uint32_t)); 258 259 switch(status) { 260 case SCOM_PIB_OFFLINE: 261 return -ENODEV; 262 case SCOM_PIB_BAD_ADDR: 263 return -ENXIO; 264 case SCOM_PIB_TIMEOUT: 265 return -ETIMEDOUT; 266 case SCOM_PIB_PARTIAL: 267 case SCOM_PIB_CLK_ERR: 268 case SCOM_PIB_PARITY_ERR: 269 default: 270 return -EIO; 271 } 272} 273 274static int put_scom(struct scom_device *scom, uint64_t value, 275 uint64_t addr) 276{ 277 uint32_t status; 278 int rc; 279 280 rc = raw_put_scom(scom, value, addr, &status); 281 if (rc) 282 return rc; 283 284 rc = handle_fsi2pib_status(scom, status); 285 if (rc) 286 return rc; 287 288 return handle_pib_status(scom, 289 (status & SCOM_STATUS_PIB_RESP_MASK) 290 >> SCOM_STATUS_PIB_RESP_SHIFT); 291} 292 293static int get_scom(struct scom_device *scom, uint64_t *value, 294 uint64_t addr) 295{ 296 uint32_t status; 297 int rc; 298 299 rc = raw_get_scom(scom, value, addr, &status); 300 if (rc) 301 return rc; 302 303 rc = handle_fsi2pib_status(scom, status); 304 if (rc) 305 return rc; 306 307 return handle_pib_status(scom, 308 (status & SCOM_STATUS_PIB_RESP_MASK) 309 >> SCOM_STATUS_PIB_RESP_SHIFT); 310} 311 312static ssize_t scom_read(struct file *filep, char __user *buf, size_t len, 313 loff_t *offset) 314{ 315 struct scom_device *scom = filep->private_data; 316 struct device *dev = &scom->fsi_dev->dev; 317 uint64_t val; 318 int rc; 319 320 if (len != sizeof(uint64_t)) 321 return -EINVAL; 322 323 mutex_lock(&scom->lock); 324 if (scom->dead) 325 rc = -ENODEV; 326 else 327 rc = get_scom(scom, &val, *offset); 328 mutex_unlock(&scom->lock); 329 if (rc) { 330 dev_dbg(dev, "get_scom fail:%d\n", rc); 331 return rc; 332 } 333 334 rc = copy_to_user(buf, &val, len); 335 if (rc) 336 dev_dbg(dev, "copy to user failed:%d\n", rc); 337 338 return rc ? rc : len; 339} 340 341static ssize_t scom_write(struct file *filep, const char __user *buf, 342 size_t len, loff_t *offset) 343{ 344 int rc; 345 struct scom_device *scom = filep->private_data; 346 struct device *dev = &scom->fsi_dev->dev; 347 uint64_t val; 348 349 if (len != sizeof(uint64_t)) 350 return -EINVAL; 351 352 rc = copy_from_user(&val, buf, len); 353 if (rc) { 354 dev_dbg(dev, "copy from user failed:%d\n", rc); 355 return -EINVAL; 356 } 357 358 mutex_lock(&scom->lock); 359 if (scom->dead) 360 rc = -ENODEV; 361 else 362 rc = put_scom(scom, val, *offset); 363 mutex_unlock(&scom->lock); 364 if (rc) { 365 dev_dbg(dev, "put_scom failed with:%d\n", rc); 366 return rc; 367 } 368 369 return len; 370} 371 372static loff_t scom_llseek(struct file *file, loff_t offset, int whence) 373{ 374 switch (whence) { 375 case SEEK_CUR: 376 break; 377 case SEEK_SET: 378 file->f_pos = offset; 379 break; 380 default: 381 return -EINVAL; 382 } 383 384 return offset; 385} 386 387static void raw_convert_status(struct scom_access *acc, uint32_t status) 388{ 389 acc->pib_status = (status & SCOM_STATUS_PIB_RESP_MASK) >> 390 SCOM_STATUS_PIB_RESP_SHIFT; 391 acc->intf_errors = 0; 392 393 if (status & SCOM_STATUS_PROTECTION) 394 acc->intf_errors |= SCOM_INTF_ERR_PROTECTION; 395 else if (status & SCOM_STATUS_PARITY) 396 acc->intf_errors |= SCOM_INTF_ERR_PARITY; 397 else if (status & SCOM_STATUS_PIB_ABORT) 398 acc->intf_errors |= SCOM_INTF_ERR_ABORT; 399 else if (status & SCOM_STATUS_ERR_SUMMARY) 400 acc->intf_errors |= SCOM_INTF_ERR_UNKNOWN; 401} 402 403static int scom_raw_read(struct scom_device *scom, void __user *argp) 404{ 405 struct scom_access acc; 406 uint32_t status; 407 int rc; 408 409 if (copy_from_user(&acc, argp, sizeof(struct scom_access))) 410 return -EFAULT; 411 412 rc = raw_get_scom(scom, &acc.data, acc.addr, &status); 413 if (rc) 414 return rc; 415 raw_convert_status(&acc, status); 416 if (copy_to_user(argp, &acc, sizeof(struct scom_access))) 417 return -EFAULT; 418 return 0; 419} 420 421static int scom_raw_write(struct scom_device *scom, void __user *argp) 422{ 423 u64 prev_data, mask, data; 424 struct scom_access acc; 425 uint32_t status; 426 int rc; 427 428 if (copy_from_user(&acc, argp, sizeof(struct scom_access))) 429 return -EFAULT; 430 431 if (acc.mask) { 432 rc = raw_get_scom(scom, &prev_data, acc.addr, &status); 433 if (rc) 434 return rc; 435 if (status & SCOM_STATUS_ANY_ERR) 436 goto fail; 437 mask = acc.mask; 438 } else { 439 prev_data = mask = -1ull; 440 } 441 data = (prev_data & ~mask) | (acc.data & mask); 442 rc = raw_put_scom(scom, data, acc.addr, &status); 443 if (rc) 444 return rc; 445 fail: 446 raw_convert_status(&acc, status); 447 if (copy_to_user(argp, &acc, sizeof(struct scom_access))) 448 return -EFAULT; 449 return 0; 450} 451 452static int scom_reset(struct scom_device *scom, void __user *argp) 453{ 454 uint32_t flags, dummy = -1; 455 int rc = 0; 456 457 if (get_user(flags, (__u32 __user *)argp)) 458 return -EFAULT; 459 if (flags & SCOM_RESET_PIB) 460 rc = fsi_device_write(scom->fsi_dev, SCOM_PIB_RESET_REG, &dummy, 461 sizeof(uint32_t)); 462 if (!rc && (flags & (SCOM_RESET_PIB | SCOM_RESET_INTF))) 463 rc = fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy, 464 sizeof(uint32_t)); 465 return rc; 466} 467 468static int scom_check(struct scom_device *scom, void __user *argp) 469{ 470 /* Still need to find out how to get "protected" */ 471 return put_user(SCOM_CHECK_SUPPORTED, (__u32 __user *)argp); 472} 473 474static long scom_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 475{ 476 struct scom_device *scom = file->private_data; 477 void __user *argp = (void __user *)arg; 478 int rc = -ENOTTY; 479 480 mutex_lock(&scom->lock); 481 if (scom->dead) { 482 mutex_unlock(&scom->lock); 483 return -ENODEV; 484 } 485 switch(cmd) { 486 case FSI_SCOM_CHECK: 487 rc = scom_check(scom, argp); 488 break; 489 case FSI_SCOM_READ: 490 rc = scom_raw_read(scom, argp); 491 break; 492 case FSI_SCOM_WRITE: 493 rc = scom_raw_write(scom, argp); 494 break; 495 case FSI_SCOM_RESET: 496 rc = scom_reset(scom, argp); 497 break; 498 } 499 mutex_unlock(&scom->lock); 500 return rc; 501} 502 503static int scom_open(struct inode *inode, struct file *file) 504{ 505 struct scom_device *scom = container_of(inode->i_cdev, struct scom_device, cdev); 506 507 file->private_data = scom; 508 509 return 0; 510} 511 512static const struct file_operations scom_fops = { 513 .owner = THIS_MODULE, 514 .open = scom_open, 515 .llseek = scom_llseek, 516 .read = scom_read, 517 .write = scom_write, 518 .unlocked_ioctl = scom_ioctl, 519}; 520 521static void scom_free(struct device *dev) 522{ 523 struct scom_device *scom = container_of(dev, struct scom_device, dev); 524 525 put_device(&scom->fsi_dev->dev); 526 kfree(scom); 527} 528 529static int scom_probe(struct device *dev) 530{ 531 struct fsi_device *fsi_dev = to_fsi_dev(dev); 532 struct scom_device *scom; 533 int rc, didx; 534 535 scom = kzalloc(sizeof(*scom), GFP_KERNEL); 536 if (!scom) 537 return -ENOMEM; 538 dev_set_drvdata(dev, scom); 539 mutex_init(&scom->lock); 540 541 /* Grab a reference to the device (parent of our cdev), we'll drop it later */ 542 if (!get_device(dev)) { 543 kfree(scom); 544 return -ENODEV; 545 } 546 scom->fsi_dev = fsi_dev; 547 548 /* Create chardev for userspace access */ 549 scom->dev.type = &fsi_cdev_type; 550 scom->dev.parent = dev; 551 scom->dev.release = scom_free; 552 device_initialize(&scom->dev); 553 554 /* Allocate a minor in the FSI space */ 555 rc = fsi_get_new_minor(fsi_dev, fsi_dev_scom, &scom->dev.devt, &didx); 556 if (rc) 557 goto err; 558 559 dev_set_name(&scom->dev, "scom%d", didx); 560 cdev_init(&scom->cdev, &scom_fops); 561 rc = cdev_device_add(&scom->cdev, &scom->dev); 562 if (rc) { 563 dev_err(dev, "Error %d creating char device %s\n", 564 rc, dev_name(&scom->dev)); 565 goto err_free_minor; 566 } 567 568 return 0; 569 err_free_minor: 570 fsi_free_minor(scom->dev.devt); 571 err: 572 put_device(&scom->dev); 573 return rc; 574} 575 576static int scom_remove(struct device *dev) 577{ 578 struct scom_device *scom = dev_get_drvdata(dev); 579 580 mutex_lock(&scom->lock); 581 scom->dead = true; 582 mutex_unlock(&scom->lock); 583 cdev_device_del(&scom->cdev, &scom->dev); 584 fsi_free_minor(scom->dev.devt); 585 put_device(&scom->dev); 586 587 return 0; 588} 589 590static const struct fsi_device_id scom_ids[] = { 591 { 592 .engine_type = FSI_ENGID_SCOM, 593 .version = FSI_VERSION_ANY, 594 }, 595 { 0 } 596}; 597 598static struct fsi_driver scom_drv = { 599 .id_table = scom_ids, 600 .drv = { 601 .name = "scom", 602 .bus = &fsi_bus_type, 603 .probe = scom_probe, 604 .remove = scom_remove, 605 } 606}; 607 608static int scom_init(void) 609{ 610 return fsi_driver_register(&scom_drv); 611} 612 613static void scom_exit(void) 614{ 615 fsi_driver_unregister(&scom_drv); 616} 617 618module_init(scom_init); 619module_exit(scom_exit); 620MODULE_LICENSE("GPL");