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