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