Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * SCOM FSI Client device driver
0004  *
0005  * Copyright (C) IBM Corporation 2016
0006  */
0007 
0008 #include <linux/fsi.h>
0009 #include <linux/module.h>
0010 #include <linux/cdev.h>
0011 #include <linux/delay.h>
0012 #include <linux/fs.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/slab.h>
0015 #include <linux/list.h>
0016 
0017 #include <uapi/linux/fsi.h>
0018 
0019 #define FSI_ENGID_SCOM      0x5
0020 
0021 /* SCOM engine register set */
0022 #define SCOM_DATA0_REG      0x00
0023 #define SCOM_DATA1_REG      0x04
0024 #define SCOM_CMD_REG        0x08
0025 #define SCOM_FSI2PIB_RESET_REG  0x18
0026 #define SCOM_STATUS_REG     0x1C /* Read */
0027 #define SCOM_PIB_RESET_REG  0x1C /* Write */
0028 
0029 /* Command register */
0030 #define SCOM_WRITE_CMD      0x80000000
0031 #define SCOM_READ_CMD       0x00000000
0032 
0033 /* Status register bits */
0034 #define SCOM_STATUS_ERR_SUMMARY     0x80000000
0035 #define SCOM_STATUS_PROTECTION      0x01000000
0036 #define SCOM_STATUS_PARITY      0x04000000
0037 #define SCOM_STATUS_PIB_ABORT       0x00100000
0038 #define SCOM_STATUS_PIB_RESP_MASK   0x00007000
0039 #define SCOM_STATUS_PIB_RESP_SHIFT  12
0040 
0041 #define SCOM_STATUS_FSI2PIB_ERROR   (SCOM_STATUS_PROTECTION |   \
0042                      SCOM_STATUS_PARITY |       \
0043                      SCOM_STATUS_PIB_ABORT)
0044 #define SCOM_STATUS_ANY_ERR     (SCOM_STATUS_FSI2PIB_ERROR |    \
0045                      SCOM_STATUS_PIB_RESP_MASK)
0046 /* SCOM address encodings */
0047 #define XSCOM_ADDR_IND_FLAG     BIT_ULL(63)
0048 #define XSCOM_ADDR_INF_FORM1        BIT_ULL(60)
0049 
0050 /* SCOM indirect stuff */
0051 #define XSCOM_ADDR_DIRECT_PART      0x7fffffffull
0052 #define XSCOM_ADDR_INDIRECT_PART    0x000fffff00000000ull
0053 #define XSCOM_DATA_IND_READ     BIT_ULL(63)
0054 #define XSCOM_DATA_IND_COMPLETE     BIT_ULL(31)
0055 #define XSCOM_DATA_IND_ERR_MASK     0x70000000ull
0056 #define XSCOM_DATA_IND_ERR_SHIFT    28
0057 #define XSCOM_DATA_IND_DATA     0x0000ffffull
0058 #define XSCOM_DATA_IND_FORM1_DATA   0x000fffffffffffffull
0059 #define XSCOM_ADDR_FORM1_LOW        0x000ffffffffull
0060 #define XSCOM_ADDR_FORM1_HI     0xfff00000000ull
0061 #define XSCOM_ADDR_FORM1_HI_SHIFT   20
0062 
0063 /* Retries */
0064 #define SCOM_MAX_IND_RETRIES        10  /* Retries indirect not ready */
0065 
0066 struct scom_device {
0067     struct list_head link;
0068     struct fsi_device *fsi_dev;
0069     struct device dev;
0070     struct cdev cdev;
0071     struct mutex lock;
0072     bool dead;
0073 };
0074 
0075 static int __put_scom(struct scom_device *scom_dev, uint64_t value,
0076               uint32_t addr, uint32_t *status)
0077 {
0078     __be32 data, raw_status;
0079     int rc;
0080 
0081     data = cpu_to_be32((value >> 32) & 0xffffffff);
0082     rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
0083                 sizeof(uint32_t));
0084     if (rc)
0085         return rc;
0086 
0087     data = cpu_to_be32(value & 0xffffffff);
0088     rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
0089                 sizeof(uint32_t));
0090     if (rc)
0091         return rc;
0092 
0093     data = cpu_to_be32(SCOM_WRITE_CMD | addr);
0094     rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
0095                 sizeof(uint32_t));
0096     if (rc)
0097         return rc;
0098     rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
0099                  sizeof(uint32_t));
0100     if (rc)
0101         return rc;
0102     *status = be32_to_cpu(raw_status);
0103 
0104     return 0;
0105 }
0106 
0107 static int __get_scom(struct scom_device *scom_dev, uint64_t *value,
0108               uint32_t addr, uint32_t *status)
0109 {
0110     __be32 data, raw_status;
0111     int rc;
0112 
0113 
0114     *value = 0ULL;
0115     data = cpu_to_be32(SCOM_READ_CMD | addr);
0116     rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
0117                 sizeof(uint32_t));
0118     if (rc)
0119         return rc;
0120     rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
0121                  sizeof(uint32_t));
0122     if (rc)
0123         return rc;
0124 
0125     /*
0126      * Read the data registers even on error, so we don't have
0127      * to interpret the status register here.
0128      */
0129     rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
0130                 sizeof(uint32_t));
0131     if (rc)
0132         return rc;
0133     *value |= (uint64_t)be32_to_cpu(data) << 32;
0134     rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
0135                 sizeof(uint32_t));
0136     if (rc)
0137         return rc;
0138     *value |= be32_to_cpu(data);
0139     *status = be32_to_cpu(raw_status);
0140 
0141     return rc;
0142 }
0143 
0144 static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
0145                    uint64_t addr, uint32_t *status)
0146 {
0147     uint64_t ind_data, ind_addr;
0148     int rc, err;
0149 
0150     if (value & ~XSCOM_DATA_IND_DATA)
0151         return -EINVAL;
0152 
0153     ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
0154     ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | value;
0155     rc = __put_scom(scom, ind_data, ind_addr, status);
0156     if (rc || (*status & SCOM_STATUS_ANY_ERR))
0157         return rc;
0158 
0159     rc = __get_scom(scom, &ind_data, addr, status);
0160     if (rc || (*status & SCOM_STATUS_ANY_ERR))
0161         return rc;
0162 
0163     err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
0164     *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
0165 
0166     return 0;
0167 }
0168 
0169 static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value,
0170                    uint64_t addr, uint32_t *status)
0171 {
0172     uint64_t ind_data, ind_addr;
0173 
0174     if (value & ~XSCOM_DATA_IND_FORM1_DATA)
0175         return -EINVAL;
0176 
0177     ind_addr = addr & XSCOM_ADDR_FORM1_LOW;
0178     ind_data = value | (addr & XSCOM_ADDR_FORM1_HI) << XSCOM_ADDR_FORM1_HI_SHIFT;
0179     return __put_scom(scom, ind_data, ind_addr, status);
0180 }
0181 
0182 static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
0183                    uint64_t addr, uint32_t *status)
0184 {
0185     uint64_t ind_data, ind_addr;
0186     int rc, err;
0187 
0188     ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
0189     ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ;
0190     rc = __put_scom(scom, ind_data, ind_addr, status);
0191     if (rc || (*status & SCOM_STATUS_ANY_ERR))
0192         return rc;
0193 
0194     rc = __get_scom(scom, &ind_data, addr, status);
0195     if (rc || (*status & SCOM_STATUS_ANY_ERR))
0196         return rc;
0197 
0198     err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
0199     *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
0200     *value = ind_data & XSCOM_DATA_IND_DATA;
0201 
0202     return 0;
0203 }
0204 
0205 static int raw_put_scom(struct scom_device *scom, uint64_t value,
0206             uint64_t addr, uint32_t *status)
0207 {
0208     if (addr & XSCOM_ADDR_IND_FLAG) {
0209         if (addr & XSCOM_ADDR_INF_FORM1)
0210             return put_indirect_scom_form1(scom, value, addr, status);
0211         else
0212             return put_indirect_scom_form0(scom, value, addr, status);
0213     } else
0214         return __put_scom(scom, value, addr, status);
0215 }
0216 
0217 static int raw_get_scom(struct scom_device *scom, uint64_t *value,
0218             uint64_t addr, uint32_t *status)
0219 {
0220     if (addr & XSCOM_ADDR_IND_FLAG) {
0221         if (addr & XSCOM_ADDR_INF_FORM1)
0222             return -ENXIO;
0223         return get_indirect_scom_form0(scom, value, addr, status);
0224     } else
0225         return __get_scom(scom, value, addr, status);
0226 }
0227 
0228 static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
0229 {
0230     uint32_t dummy = -1;
0231 
0232     if (status & SCOM_STATUS_FSI2PIB_ERROR)
0233         fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
0234                  sizeof(uint32_t));
0235 
0236     if (status & SCOM_STATUS_PROTECTION)
0237         return -EPERM;
0238     if (status & SCOM_STATUS_PARITY)
0239         return -EIO;
0240 
0241     if (status & SCOM_STATUS_PIB_ABORT)
0242         return -EBUSY;
0243     return 0;
0244 }
0245 
0246 static int handle_pib_status(struct scom_device *scom, uint8_t status)
0247 {
0248     uint32_t dummy = -1;
0249 
0250     if (status == SCOM_PIB_SUCCESS)
0251         return 0;
0252     if (status == SCOM_PIB_BLOCKED)
0253         return -EBUSY;
0254 
0255     /* Reset the bridge */
0256     fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
0257              sizeof(uint32_t));
0258 
0259     switch(status) {
0260     case SCOM_PIB_OFFLINE:
0261         return -ENODEV;
0262     case SCOM_PIB_BAD_ADDR:
0263         return -ENXIO;
0264     case SCOM_PIB_TIMEOUT:
0265         return -ETIMEDOUT;
0266     case SCOM_PIB_PARTIAL:
0267     case SCOM_PIB_CLK_ERR:
0268     case SCOM_PIB_PARITY_ERR:
0269     default:
0270         return -EIO;
0271     }
0272 }
0273 
0274 static int put_scom(struct scom_device *scom, uint64_t value,
0275             uint64_t addr)
0276 {
0277     uint32_t status;
0278     int rc;
0279 
0280     rc = raw_put_scom(scom, value, addr, &status);
0281     if (rc)
0282         return rc;
0283 
0284     rc = handle_fsi2pib_status(scom, status);
0285     if (rc)
0286         return rc;
0287 
0288     return handle_pib_status(scom,
0289                  (status & SCOM_STATUS_PIB_RESP_MASK)
0290                  >> SCOM_STATUS_PIB_RESP_SHIFT);
0291 }
0292 
0293 static int get_scom(struct scom_device *scom, uint64_t *value,
0294             uint64_t addr)
0295 {
0296     uint32_t status;
0297     int rc;
0298 
0299     rc = raw_get_scom(scom, value, addr, &status);
0300     if (rc)
0301         return rc;
0302 
0303     rc = handle_fsi2pib_status(scom, status);
0304     if (rc)
0305         return rc;
0306 
0307     return handle_pib_status(scom,
0308                  (status & SCOM_STATUS_PIB_RESP_MASK)
0309                  >> SCOM_STATUS_PIB_RESP_SHIFT);
0310 }
0311 
0312 static ssize_t scom_read(struct file *filep, char __user *buf, size_t len,
0313              loff_t *offset)
0314 {
0315     struct scom_device *scom = filep->private_data;
0316     struct device *dev = &scom->fsi_dev->dev;
0317     uint64_t val;
0318     int rc;
0319 
0320     if (len != sizeof(uint64_t))
0321         return -EINVAL;
0322 
0323     mutex_lock(&scom->lock);
0324     if (scom->dead)
0325         rc = -ENODEV;
0326     else
0327         rc = get_scom(scom, &val, *offset);
0328     mutex_unlock(&scom->lock);
0329     if (rc) {
0330         dev_dbg(dev, "get_scom fail:%d\n", rc);
0331         return rc;
0332     }
0333 
0334     rc = copy_to_user(buf, &val, len);
0335     if (rc)
0336         dev_dbg(dev, "copy to user failed:%d\n", rc);
0337 
0338     return rc ? rc : len;
0339 }
0340 
0341 static ssize_t scom_write(struct file *filep, const char __user *buf,
0342               size_t len, loff_t *offset)
0343 {
0344     int rc;
0345     struct scom_device *scom = filep->private_data;
0346     struct device *dev = &scom->fsi_dev->dev;
0347     uint64_t val;
0348 
0349     if (len != sizeof(uint64_t))
0350         return -EINVAL;
0351 
0352     rc = copy_from_user(&val, buf, len);
0353     if (rc) {
0354         dev_dbg(dev, "copy from user failed:%d\n", rc);
0355         return -EINVAL;
0356     }
0357 
0358     mutex_lock(&scom->lock);
0359     if (scom->dead)
0360         rc = -ENODEV;
0361     else
0362         rc = put_scom(scom, val, *offset);
0363     mutex_unlock(&scom->lock);
0364     if (rc) {
0365         dev_dbg(dev, "put_scom failed with:%d\n", rc);
0366         return rc;
0367     }
0368 
0369     return len;
0370 }
0371 
0372 static loff_t scom_llseek(struct file *file, loff_t offset, int whence)
0373 {
0374     switch (whence) {
0375     case SEEK_CUR:
0376         break;
0377     case SEEK_SET:
0378         file->f_pos = offset;
0379         break;
0380     default:
0381         return -EINVAL;
0382     }
0383 
0384     return offset;
0385 }
0386 
0387 static void raw_convert_status(struct scom_access *acc, uint32_t status)
0388 {
0389     acc->pib_status = (status & SCOM_STATUS_PIB_RESP_MASK) >>
0390         SCOM_STATUS_PIB_RESP_SHIFT;
0391     acc->intf_errors = 0;
0392 
0393     if (status & SCOM_STATUS_PROTECTION)
0394         acc->intf_errors |= SCOM_INTF_ERR_PROTECTION;
0395     else if (status & SCOM_STATUS_PARITY)
0396         acc->intf_errors |= SCOM_INTF_ERR_PARITY;
0397     else if (status & SCOM_STATUS_PIB_ABORT)
0398         acc->intf_errors |= SCOM_INTF_ERR_ABORT;
0399     else if (status & SCOM_STATUS_ERR_SUMMARY)
0400         acc->intf_errors |= SCOM_INTF_ERR_UNKNOWN;
0401 }
0402 
0403 static int scom_raw_read(struct scom_device *scom, void __user *argp)
0404 {
0405     struct scom_access acc;
0406     uint32_t status;
0407     int rc;
0408 
0409     if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
0410         return -EFAULT;
0411 
0412     rc = raw_get_scom(scom, &acc.data, acc.addr, &status);
0413     if (rc)
0414         return rc;
0415     raw_convert_status(&acc, status);
0416     if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
0417         return -EFAULT;
0418     return 0;
0419 }
0420 
0421 static int scom_raw_write(struct scom_device *scom, void __user *argp)
0422 {
0423     u64 prev_data, mask, data;
0424     struct scom_access acc;
0425     uint32_t status;
0426     int rc;
0427 
0428     if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
0429         return -EFAULT;
0430 
0431     if (acc.mask) {
0432         rc = raw_get_scom(scom, &prev_data, acc.addr, &status);
0433         if (rc)
0434             return rc;
0435         if (status & SCOM_STATUS_ANY_ERR)
0436             goto fail;
0437         mask = acc.mask;
0438     } else {
0439         prev_data = mask = -1ull;
0440     }
0441     data = (prev_data & ~mask) | (acc.data & mask);
0442     rc = raw_put_scom(scom, data, acc.addr, &status);
0443     if (rc)
0444         return rc;
0445  fail:
0446     raw_convert_status(&acc, status);
0447     if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
0448         return -EFAULT;
0449     return 0;
0450 }
0451 
0452 static int scom_reset(struct scom_device *scom, void __user *argp)
0453 {
0454     uint32_t flags, dummy = -1;
0455     int rc = 0;
0456 
0457     if (get_user(flags, (__u32 __user *)argp))
0458         return -EFAULT;
0459     if (flags & SCOM_RESET_PIB)
0460         rc = fsi_device_write(scom->fsi_dev, SCOM_PIB_RESET_REG, &dummy,
0461                       sizeof(uint32_t));
0462     if (!rc && (flags & (SCOM_RESET_PIB | SCOM_RESET_INTF)))
0463         rc = fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
0464                       sizeof(uint32_t));
0465     return rc;
0466 }
0467 
0468 static int scom_check(struct scom_device *scom, void __user *argp)
0469 {
0470     /* Still need to find out how to get "protected" */
0471     return put_user(SCOM_CHECK_SUPPORTED, (__u32 __user *)argp);
0472 }
0473 
0474 static long scom_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0475 {
0476     struct scom_device *scom = file->private_data;
0477     void __user *argp = (void __user *)arg;
0478     int rc = -ENOTTY;
0479 
0480     mutex_lock(&scom->lock);
0481     if (scom->dead) {
0482         mutex_unlock(&scom->lock);
0483         return -ENODEV;
0484     }
0485     switch(cmd) {
0486     case FSI_SCOM_CHECK:
0487         rc = scom_check(scom, argp);
0488         break;
0489     case FSI_SCOM_READ:
0490         rc = scom_raw_read(scom, argp);
0491         break;
0492     case FSI_SCOM_WRITE:
0493         rc = scom_raw_write(scom, argp);
0494         break;
0495     case FSI_SCOM_RESET:
0496         rc = scom_reset(scom, argp);
0497         break;
0498     }
0499     mutex_unlock(&scom->lock);
0500     return rc;
0501 }
0502 
0503 static int scom_open(struct inode *inode, struct file *file)
0504 {
0505     struct scom_device *scom = container_of(inode->i_cdev, struct scom_device, cdev);
0506 
0507     file->private_data = scom;
0508 
0509     return 0;
0510 }
0511 
0512 static const struct file_operations scom_fops = {
0513     .owner      = THIS_MODULE,
0514     .open       = scom_open,
0515     .llseek     = scom_llseek,
0516     .read       = scom_read,
0517     .write      = scom_write,
0518     .unlocked_ioctl = scom_ioctl,
0519 };
0520 
0521 static void scom_free(struct device *dev)
0522 {
0523     struct scom_device *scom = container_of(dev, struct scom_device, dev);
0524 
0525     put_device(&scom->fsi_dev->dev);
0526     kfree(scom);
0527 }
0528 
0529 static int scom_probe(struct device *dev)
0530 {
0531     struct fsi_device *fsi_dev = to_fsi_dev(dev);
0532     struct scom_device *scom;
0533     int rc, didx;
0534 
0535     scom = kzalloc(sizeof(*scom), GFP_KERNEL);
0536     if (!scom)
0537         return -ENOMEM;
0538     dev_set_drvdata(dev, scom);
0539     mutex_init(&scom->lock);
0540 
0541     /* Grab a reference to the device (parent of our cdev), we'll drop it later */
0542     if (!get_device(dev)) {
0543         kfree(scom);
0544         return -ENODEV;
0545     }
0546     scom->fsi_dev = fsi_dev;
0547 
0548     /* Create chardev for userspace access */
0549     scom->dev.type = &fsi_cdev_type;
0550     scom->dev.parent = dev;
0551     scom->dev.release = scom_free;
0552     device_initialize(&scom->dev);
0553 
0554     /* Allocate a minor in the FSI space */
0555     rc = fsi_get_new_minor(fsi_dev, fsi_dev_scom, &scom->dev.devt, &didx);
0556     if (rc)
0557         goto err;
0558 
0559     dev_set_name(&scom->dev, "scom%d", didx);
0560     cdev_init(&scom->cdev, &scom_fops);
0561     rc = cdev_device_add(&scom->cdev, &scom->dev);
0562     if (rc) {
0563         dev_err(dev, "Error %d creating char device %s\n",
0564             rc, dev_name(&scom->dev));
0565         goto err_free_minor;
0566     }
0567 
0568     return 0;
0569  err_free_minor:
0570     fsi_free_minor(scom->dev.devt);
0571  err:
0572     put_device(&scom->dev);
0573     return rc;
0574 }
0575 
0576 static int scom_remove(struct device *dev)
0577 {
0578     struct scom_device *scom = dev_get_drvdata(dev);
0579 
0580     mutex_lock(&scom->lock);
0581     scom->dead = true;
0582     mutex_unlock(&scom->lock);
0583     cdev_device_del(&scom->cdev, &scom->dev);
0584     fsi_free_minor(scom->dev.devt);
0585     put_device(&scom->dev);
0586 
0587     return 0;
0588 }
0589 
0590 static const struct fsi_device_id scom_ids[] = {
0591     {
0592         .engine_type = FSI_ENGID_SCOM,
0593         .version = FSI_VERSION_ANY,
0594     },
0595     { 0 }
0596 };
0597 
0598 static struct fsi_driver scom_drv = {
0599     .id_table = scom_ids,
0600     .drv = {
0601         .name = "scom",
0602         .bus = &fsi_bus_type,
0603         .probe = scom_probe,
0604         .remove = scom_remove,
0605     }
0606 };
0607 
0608 static int scom_init(void)
0609 {
0610     return fsi_driver_register(&scom_drv);
0611 }
0612 
0613 static void scom_exit(void)
0614 {
0615     fsi_driver_unregister(&scom_drv);
0616 }
0617 
0618 module_init(scom_init);
0619 module_exit(scom_exit);
0620 MODULE_LICENSE("GPL");