xref: /linux/drivers/fsi/fsi-scom.c (revision 9221afb2d8e8db75bbf71a223010e37db1b64f30)
16b99076cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2680ca6dcSChristopher Bostic /*
3680ca6dcSChristopher Bostic  * SCOM FSI Client device driver
4680ca6dcSChristopher Bostic  *
5680ca6dcSChristopher Bostic  * Copyright (C) IBM Corporation 2016
6680ca6dcSChristopher Bostic  */
7680ca6dcSChristopher Bostic 
8680ca6dcSChristopher Bostic #include <linux/fsi.h>
9680ca6dcSChristopher Bostic #include <linux/module.h>
10680ca6dcSChristopher Bostic #include <linux/cdev.h>
11680ca6dcSChristopher Bostic #include <linux/delay.h>
12680ca6dcSChristopher Bostic #include <linux/fs.h>
13c21d322eSEddie James #include <linux/mod_devicetable.h>
14680ca6dcSChristopher Bostic #include <linux/uaccess.h>
15680ca6dcSChristopher Bostic #include <linux/slab.h>
16680ca6dcSChristopher Bostic #include <linux/list.h>
17680ca6dcSChristopher Bostic 
186b293258SBenjamin Herrenschmidt #include <uapi/linux/fsi.h>
196b293258SBenjamin Herrenschmidt 
20680ca6dcSChristopher Bostic #define FSI_ENGID_SCOM		0x5
21680ca6dcSChristopher Bostic 
22680ca6dcSChristopher Bostic /* SCOM engine register set */
23680ca6dcSChristopher Bostic #define SCOM_DATA0_REG		0x00
24680ca6dcSChristopher Bostic #define SCOM_DATA1_REG		0x04
25680ca6dcSChristopher Bostic #define SCOM_CMD_REG		0x08
26f1433044SBenjamin Herrenschmidt #define SCOM_FSI2PIB_RESET_REG	0x18
27f1433044SBenjamin Herrenschmidt #define SCOM_STATUS_REG		0x1C /* Read */
28f1433044SBenjamin Herrenschmidt #define SCOM_PIB_RESET_REG	0x1C /* Write */
29680ca6dcSChristopher Bostic 
30f1433044SBenjamin Herrenschmidt /* Command register */
31680ca6dcSChristopher Bostic #define SCOM_WRITE_CMD		0x80000000
32f1433044SBenjamin Herrenschmidt #define SCOM_READ_CMD		0x00000000
33f1433044SBenjamin Herrenschmidt 
34f1433044SBenjamin Herrenschmidt /* Status register bits */
35f1433044SBenjamin Herrenschmidt #define SCOM_STATUS_ERR_SUMMARY		0x80000000
36f1433044SBenjamin Herrenschmidt #define SCOM_STATUS_PROTECTION		0x01000000
376b293258SBenjamin Herrenschmidt #define SCOM_STATUS_PARITY		0x04000000
38f1433044SBenjamin Herrenschmidt #define SCOM_STATUS_PIB_ABORT		0x00100000
39f1433044SBenjamin Herrenschmidt #define SCOM_STATUS_PIB_RESP_MASK	0x00007000
40f1433044SBenjamin Herrenschmidt #define SCOM_STATUS_PIB_RESP_SHIFT	12
41f1433044SBenjamin Herrenschmidt 
42a5c317daSEddie James #define SCOM_STATUS_FSI2PIB_ERROR	(SCOM_STATUS_PROTECTION |	\
436b293258SBenjamin Herrenschmidt 					 SCOM_STATUS_PARITY |		\
44a5c317daSEddie James 					 SCOM_STATUS_PIB_ABORT)
45a5c317daSEddie James #define SCOM_STATUS_ANY_ERR		(SCOM_STATUS_FSI2PIB_ERROR |	\
46f1433044SBenjamin Herrenschmidt 					 SCOM_STATUS_PIB_RESP_MASK)
476b293258SBenjamin Herrenschmidt /* SCOM address encodings */
486b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_IND_FLAG		BIT_ULL(63)
496b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_INF_FORM1		BIT_ULL(60)
506b293258SBenjamin Herrenschmidt 
516b293258SBenjamin Herrenschmidt /* SCOM indirect stuff */
526b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_DIRECT_PART		0x7fffffffull
536b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_INDIRECT_PART	0x000fffff00000000ull
546b293258SBenjamin Herrenschmidt #define XSCOM_DATA_IND_READ		BIT_ULL(63)
556b293258SBenjamin Herrenschmidt #define XSCOM_DATA_IND_COMPLETE		BIT_ULL(31)
566b293258SBenjamin Herrenschmidt #define XSCOM_DATA_IND_ERR_MASK		0x70000000ull
576b293258SBenjamin Herrenschmidt #define XSCOM_DATA_IND_ERR_SHIFT	28
586b293258SBenjamin Herrenschmidt #define XSCOM_DATA_IND_DATA		0x0000ffffull
596b293258SBenjamin Herrenschmidt #define XSCOM_DATA_IND_FORM1_DATA	0x000fffffffffffffull
606b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_FORM1_LOW		0x000ffffffffull
616b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_FORM1_HI		0xfff00000000ull
626b293258SBenjamin Herrenschmidt #define XSCOM_ADDR_FORM1_HI_SHIFT	20
636b293258SBenjamin Herrenschmidt 
646b293258SBenjamin Herrenschmidt /* Retries */
656b293258SBenjamin Herrenschmidt #define SCOM_MAX_IND_RETRIES		10	/* Retries indirect not ready */
66680ca6dcSChristopher Bostic 
67680ca6dcSChristopher Bostic struct scom_device {
68680ca6dcSChristopher Bostic 	struct list_head link;
69680ca6dcSChristopher Bostic 	struct fsi_device *fsi_dev;
70d8f45876SBenjamin Herrenschmidt 	struct device dev;
71d8f45876SBenjamin Herrenschmidt 	struct cdev cdev;
72162c3946SBenjamin Herrenschmidt 	struct mutex lock;
73d8f45876SBenjamin Herrenschmidt 	bool dead;
74680ca6dcSChristopher Bostic };
75680ca6dcSChristopher Bostic 
__put_scom(struct scom_device * scom_dev,uint64_t value,uint32_t addr,uint32_t * status)766b293258SBenjamin Herrenschmidt static int __put_scom(struct scom_device *scom_dev, uint64_t value,
776b293258SBenjamin Herrenschmidt 		      uint32_t addr, uint32_t *status)
78680ca6dcSChristopher Bostic {
796b293258SBenjamin Herrenschmidt 	__be32 data, raw_status;
80680ca6dcSChristopher Bostic 	int rc;
81680ca6dcSChristopher Bostic 
82680ca6dcSChristopher Bostic 	data = cpu_to_be32((value >> 32) & 0xffffffff);
83680ca6dcSChristopher Bostic 	rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
84680ca6dcSChristopher Bostic 				sizeof(uint32_t));
85680ca6dcSChristopher Bostic 	if (rc)
866b293258SBenjamin Herrenschmidt 		return rc;
87680ca6dcSChristopher Bostic 
88680ca6dcSChristopher Bostic 	data = cpu_to_be32(value & 0xffffffff);
89680ca6dcSChristopher Bostic 	rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
90680ca6dcSChristopher Bostic 				sizeof(uint32_t));
91680ca6dcSChristopher Bostic 	if (rc)
926b293258SBenjamin Herrenschmidt 		return rc;
93680ca6dcSChristopher Bostic 
94680ca6dcSChristopher Bostic 	data = cpu_to_be32(SCOM_WRITE_CMD | addr);
95162c3946SBenjamin Herrenschmidt 	rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
96680ca6dcSChristopher Bostic 				sizeof(uint32_t));
976b293258SBenjamin Herrenschmidt 	if (rc)
98162c3946SBenjamin Herrenschmidt 		return rc;
996b293258SBenjamin Herrenschmidt 	rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
1006b293258SBenjamin Herrenschmidt 			     sizeof(uint32_t));
1016b293258SBenjamin Herrenschmidt 	if (rc)
1026b293258SBenjamin Herrenschmidt 		return rc;
1036b293258SBenjamin Herrenschmidt 	*status = be32_to_cpu(raw_status);
1046b293258SBenjamin Herrenschmidt 
1056b293258SBenjamin Herrenschmidt 	return 0;
106680ca6dcSChristopher Bostic }
107680ca6dcSChristopher Bostic 
__get_scom(struct scom_device * scom_dev,uint64_t * value,uint32_t addr,uint32_t * status)1086b293258SBenjamin Herrenschmidt static int __get_scom(struct scom_device *scom_dev, uint64_t *value,
1096b293258SBenjamin Herrenschmidt 		      uint32_t addr, uint32_t *status)
110680ca6dcSChristopher Bostic {
1116b293258SBenjamin Herrenschmidt 	__be32 data, raw_status;
112680ca6dcSChristopher Bostic 	int rc;
113680ca6dcSChristopher Bostic 
114162c3946SBenjamin Herrenschmidt 
115680ca6dcSChristopher Bostic 	*value = 0ULL;
116f1433044SBenjamin Herrenschmidt 	data = cpu_to_be32(SCOM_READ_CMD | addr);
117680ca6dcSChristopher Bostic 	rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
118680ca6dcSChristopher Bostic 				sizeof(uint32_t));
119680ca6dcSChristopher Bostic 	if (rc)
1206b293258SBenjamin Herrenschmidt 		return rc;
1216b293258SBenjamin Herrenschmidt 	rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
122680ca6dcSChristopher Bostic 			     sizeof(uint32_t));
123680ca6dcSChristopher Bostic 	if (rc)
1246b293258SBenjamin Herrenschmidt 		return rc;
125680ca6dcSChristopher Bostic 
1266b293258SBenjamin Herrenschmidt 	/*
1276b293258SBenjamin Herrenschmidt 	 * Read the data registers even on error, so we don't have
1286b293258SBenjamin Herrenschmidt 	 * to interpret the status register here.
1296b293258SBenjamin Herrenschmidt 	 */
1306b293258SBenjamin Herrenschmidt 	rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
131680ca6dcSChristopher Bostic 				sizeof(uint32_t));
132680ca6dcSChristopher Bostic 	if (rc)
1336b293258SBenjamin Herrenschmidt 		return rc;
1346b293258SBenjamin Herrenschmidt 	*value |= (uint64_t)be32_to_cpu(data) << 32;
1356b293258SBenjamin Herrenschmidt 	rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
1366b293258SBenjamin Herrenschmidt 				sizeof(uint32_t));
1376b293258SBenjamin Herrenschmidt 	if (rc)
1386b293258SBenjamin Herrenschmidt 		return rc;
1396b293258SBenjamin Herrenschmidt 	*value |= be32_to_cpu(data);
1406b293258SBenjamin Herrenschmidt 	*status = be32_to_cpu(raw_status);
141680ca6dcSChristopher Bostic 
1426b293258SBenjamin Herrenschmidt 	return rc;
1436b293258SBenjamin Herrenschmidt }
1446b293258SBenjamin Herrenschmidt 
put_indirect_scom_form0(struct scom_device * scom,uint64_t value,uint64_t addr,uint32_t * status)1456b293258SBenjamin Herrenschmidt static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
1466b293258SBenjamin Herrenschmidt 				   uint64_t addr, uint32_t *status)
1476b293258SBenjamin Herrenschmidt {
1486b293258SBenjamin Herrenschmidt 	uint64_t ind_data, ind_addr;
149ab1b7915SJoel Stanley 	int rc, err;
1506b293258SBenjamin Herrenschmidt 
1516b293258SBenjamin Herrenschmidt 	if (value & ~XSCOM_DATA_IND_DATA)
1526b293258SBenjamin Herrenschmidt 		return -EINVAL;
1536b293258SBenjamin Herrenschmidt 
1546b293258SBenjamin Herrenschmidt 	ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
1556b293258SBenjamin Herrenschmidt 	ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | value;
1566b293258SBenjamin Herrenschmidt 	rc = __put_scom(scom, ind_data, ind_addr, status);
1576b293258SBenjamin Herrenschmidt 	if (rc || (*status & SCOM_STATUS_ANY_ERR))
1586b293258SBenjamin Herrenschmidt 		return rc;
1596b293258SBenjamin Herrenschmidt 
1606b293258SBenjamin Herrenschmidt 	rc = __get_scom(scom, &ind_data, addr, status);
1616b293258SBenjamin Herrenschmidt 	if (rc || (*status & SCOM_STATUS_ANY_ERR))
1626b293258SBenjamin Herrenschmidt 		return rc;
1636b293258SBenjamin Herrenschmidt 
1646b293258SBenjamin Herrenschmidt 	err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
1656b293258SBenjamin Herrenschmidt 	*status = err << SCOM_STATUS_PIB_RESP_SHIFT;
1666b293258SBenjamin Herrenschmidt 
167ab1b7915SJoel Stanley 	return 0;
1686b293258SBenjamin Herrenschmidt }
1696b293258SBenjamin Herrenschmidt 
put_indirect_scom_form1(struct scom_device * scom,uint64_t value,uint64_t addr,uint32_t * status)1706b293258SBenjamin Herrenschmidt static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value,
1716b293258SBenjamin Herrenschmidt 				   uint64_t addr, uint32_t *status)
1726b293258SBenjamin Herrenschmidt {
1736b293258SBenjamin Herrenschmidt 	uint64_t ind_data, ind_addr;
1746b293258SBenjamin Herrenschmidt 
1756b293258SBenjamin Herrenschmidt 	if (value & ~XSCOM_DATA_IND_FORM1_DATA)
1766b293258SBenjamin Herrenschmidt 		return -EINVAL;
1776b293258SBenjamin Herrenschmidt 
1786b293258SBenjamin Herrenschmidt 	ind_addr = addr & XSCOM_ADDR_FORM1_LOW;
1796b293258SBenjamin Herrenschmidt 	ind_data = value | (addr & XSCOM_ADDR_FORM1_HI) << XSCOM_ADDR_FORM1_HI_SHIFT;
1806b293258SBenjamin Herrenschmidt 	return __put_scom(scom, ind_data, ind_addr, status);
1816b293258SBenjamin Herrenschmidt }
1826b293258SBenjamin Herrenschmidt 
get_indirect_scom_form0(struct scom_device * scom,uint64_t * value,uint64_t addr,uint32_t * status)1836b293258SBenjamin Herrenschmidt static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
1846b293258SBenjamin Herrenschmidt 				   uint64_t addr, uint32_t *status)
1856b293258SBenjamin Herrenschmidt {
1866b293258SBenjamin Herrenschmidt 	uint64_t ind_data, ind_addr;
187ab1b7915SJoel Stanley 	int rc, err;
1886b293258SBenjamin Herrenschmidt 
1896b293258SBenjamin Herrenschmidt 	ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
1906b293258SBenjamin Herrenschmidt 	ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ;
1916b293258SBenjamin Herrenschmidt 	rc = __put_scom(scom, ind_data, ind_addr, status);
1926b293258SBenjamin Herrenschmidt 	if (rc || (*status & SCOM_STATUS_ANY_ERR))
1936b293258SBenjamin Herrenschmidt 		return rc;
1946b293258SBenjamin Herrenschmidt 
1956b293258SBenjamin Herrenschmidt 	rc = __get_scom(scom, &ind_data, addr, status);
1966b293258SBenjamin Herrenschmidt 	if (rc || (*status & SCOM_STATUS_ANY_ERR))
1976b293258SBenjamin Herrenschmidt 		return rc;
1986b293258SBenjamin Herrenschmidt 
1996b293258SBenjamin Herrenschmidt 	err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
2006b293258SBenjamin Herrenschmidt 	*status = err << SCOM_STATUS_PIB_RESP_SHIFT;
2016b293258SBenjamin Herrenschmidt 	*value = ind_data & XSCOM_DATA_IND_DATA;
2026b293258SBenjamin Herrenschmidt 
2036b293258SBenjamin Herrenschmidt 	return 0;
2046b293258SBenjamin Herrenschmidt }
2056b293258SBenjamin Herrenschmidt 
raw_put_scom(struct scom_device * scom,uint64_t value,uint64_t addr,uint32_t * status)2066b293258SBenjamin Herrenschmidt static int raw_put_scom(struct scom_device *scom, uint64_t value,
2076b293258SBenjamin Herrenschmidt 			uint64_t addr, uint32_t *status)
2086b293258SBenjamin Herrenschmidt {
2096b293258SBenjamin Herrenschmidt 	if (addr & XSCOM_ADDR_IND_FLAG) {
2106b293258SBenjamin Herrenschmidt 		if (addr & XSCOM_ADDR_INF_FORM1)
2116b293258SBenjamin Herrenschmidt 			return put_indirect_scom_form1(scom, value, addr, status);
2126b293258SBenjamin Herrenschmidt 		else
2136b293258SBenjamin Herrenschmidt 			return put_indirect_scom_form0(scom, value, addr, status);
2146b293258SBenjamin Herrenschmidt 	} else
2156b293258SBenjamin Herrenschmidt 		return __put_scom(scom, value, addr, status);
2166b293258SBenjamin Herrenschmidt }
2176b293258SBenjamin Herrenschmidt 
raw_get_scom(struct scom_device * scom,uint64_t * value,uint64_t addr,uint32_t * status)2186b293258SBenjamin Herrenschmidt static int raw_get_scom(struct scom_device *scom, uint64_t *value,
2196b293258SBenjamin Herrenschmidt 			uint64_t addr, uint32_t *status)
2206b293258SBenjamin Herrenschmidt {
2216b293258SBenjamin Herrenschmidt 	if (addr & XSCOM_ADDR_IND_FLAG) {
2226b293258SBenjamin Herrenschmidt 		if (addr & XSCOM_ADDR_INF_FORM1)
2236b293258SBenjamin Herrenschmidt 			return -ENXIO;
2246b293258SBenjamin Herrenschmidt 		return get_indirect_scom_form0(scom, value, addr, status);
2256b293258SBenjamin Herrenschmidt 	} else
2266b293258SBenjamin Herrenschmidt 		return __get_scom(scom, value, addr, status);
2276b293258SBenjamin Herrenschmidt }
2286b293258SBenjamin Herrenschmidt 
handle_fsi2pib_status(struct scom_device * scom,uint32_t status)2296b293258SBenjamin Herrenschmidt static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
2306b293258SBenjamin Herrenschmidt {
2316b293258SBenjamin Herrenschmidt 	uint32_t dummy = -1;
2326b293258SBenjamin Herrenschmidt 
233a5c317daSEddie James 	if (status & SCOM_STATUS_FSI2PIB_ERROR)
2346b293258SBenjamin Herrenschmidt 		fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
2356b293258SBenjamin Herrenschmidt 				 sizeof(uint32_t));
236a5c317daSEddie James 
237a5c317daSEddie James 	if (status & SCOM_STATUS_PROTECTION)
238a5c317daSEddie James 		return -EPERM;
239a5c317daSEddie James 	if (status & SCOM_STATUS_PARITY)
2406b293258SBenjamin Herrenschmidt 		return -EIO;
241f72ddbe1SJoel Stanley 
2426b293258SBenjamin Herrenschmidt 	if (status & SCOM_STATUS_PIB_ABORT)
2436b293258SBenjamin Herrenschmidt 		return -EBUSY;
2446b293258SBenjamin Herrenschmidt 	return 0;
2456b293258SBenjamin Herrenschmidt }
2466b293258SBenjamin Herrenschmidt 
handle_pib_status(struct scom_device * scom,uint8_t status)2476b293258SBenjamin Herrenschmidt static int handle_pib_status(struct scom_device *scom, uint8_t status)
2486b293258SBenjamin Herrenschmidt {
2496b293258SBenjamin Herrenschmidt 	uint32_t dummy = -1;
2506b293258SBenjamin Herrenschmidt 
2516b293258SBenjamin Herrenschmidt 	if (status == SCOM_PIB_SUCCESS)
2526b293258SBenjamin Herrenschmidt 		return 0;
2536b293258SBenjamin Herrenschmidt 	if (status == SCOM_PIB_BLOCKED)
2546b293258SBenjamin Herrenschmidt 		return -EBUSY;
2556b293258SBenjamin Herrenschmidt 
2566b293258SBenjamin Herrenschmidt 	/* Reset the bridge */
2576b293258SBenjamin Herrenschmidt 	fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
2586b293258SBenjamin Herrenschmidt 			 sizeof(uint32_t));
2596b293258SBenjamin Herrenschmidt 
2606b293258SBenjamin Herrenschmidt 	switch(status) {
2616b293258SBenjamin Herrenschmidt 	case SCOM_PIB_OFFLINE:
2626b293258SBenjamin Herrenschmidt 		return -ENODEV;
2636b293258SBenjamin Herrenschmidt 	case SCOM_PIB_BAD_ADDR:
2646b293258SBenjamin Herrenschmidt 		return -ENXIO;
2656b293258SBenjamin Herrenschmidt 	case SCOM_PIB_TIMEOUT:
2666b293258SBenjamin Herrenschmidt 		return -ETIMEDOUT;
2676b293258SBenjamin Herrenschmidt 	case SCOM_PIB_PARTIAL:
2686b293258SBenjamin Herrenschmidt 	case SCOM_PIB_CLK_ERR:
2696b293258SBenjamin Herrenschmidt 	case SCOM_PIB_PARITY_ERR:
2706b293258SBenjamin Herrenschmidt 	default:
2716b293258SBenjamin Herrenschmidt 		return -EIO;
2726b293258SBenjamin Herrenschmidt 	}
2736b293258SBenjamin Herrenschmidt }
2746b293258SBenjamin Herrenschmidt 
put_scom(struct scom_device * scom,uint64_t value,uint64_t addr)2756b293258SBenjamin Herrenschmidt static int put_scom(struct scom_device *scom, uint64_t value,
2766b293258SBenjamin Herrenschmidt 		    uint64_t addr)
2776b293258SBenjamin Herrenschmidt {
278f72ddbe1SJoel Stanley 	uint32_t status;
279f72ddbe1SJoel Stanley 	int rc;
2806b293258SBenjamin Herrenschmidt 
2816b293258SBenjamin Herrenschmidt 	rc = raw_put_scom(scom, value, addr, &status);
282d46fddd5SJoel Stanley 	if (rc)
2836b293258SBenjamin Herrenschmidt 		return rc;
284f72ddbe1SJoel Stanley 
2856b293258SBenjamin Herrenschmidt 	rc = handle_fsi2pib_status(scom, status);
286f72ddbe1SJoel Stanley 	if (rc)
287f72ddbe1SJoel Stanley 		return rc;
288f72ddbe1SJoel Stanley 
289f72ddbe1SJoel Stanley 	return handle_pib_status(scom,
2906b293258SBenjamin Herrenschmidt 				 (status & SCOM_STATUS_PIB_RESP_MASK)
2916b293258SBenjamin Herrenschmidt 				 >> SCOM_STATUS_PIB_RESP_SHIFT);
2926b293258SBenjamin Herrenschmidt }
2936b293258SBenjamin Herrenschmidt 
get_scom(struct scom_device * scom,uint64_t * value,uint64_t addr)2946b293258SBenjamin Herrenschmidt static int get_scom(struct scom_device *scom, uint64_t *value,
2956b293258SBenjamin Herrenschmidt 		    uint64_t addr)
2966b293258SBenjamin Herrenschmidt {
297f72ddbe1SJoel Stanley 	uint32_t status;
298f72ddbe1SJoel Stanley 	int rc;
2996b293258SBenjamin Herrenschmidt 
3006b293258SBenjamin Herrenschmidt 	rc = raw_get_scom(scom, value, addr, &status);
301d46fddd5SJoel Stanley 	if (rc)
3026b293258SBenjamin Herrenschmidt 		return rc;
303f72ddbe1SJoel Stanley 
3046b293258SBenjamin Herrenschmidt 	rc = handle_fsi2pib_status(scom, status);
305f72ddbe1SJoel Stanley 	if (rc)
306f72ddbe1SJoel Stanley 		return rc;
307f72ddbe1SJoel Stanley 
308f72ddbe1SJoel Stanley 	return handle_pib_status(scom,
3096b293258SBenjamin Herrenschmidt 				 (status & SCOM_STATUS_PIB_RESP_MASK)
3106b293258SBenjamin Herrenschmidt 				 >> SCOM_STATUS_PIB_RESP_SHIFT);
311680ca6dcSChristopher Bostic }
312680ca6dcSChristopher Bostic 
scom_read(struct file * filep,char __user * buf,size_t len,loff_t * offset)313680ca6dcSChristopher Bostic static ssize_t scom_read(struct file *filep, char __user *buf, size_t len,
314680ca6dcSChristopher Bostic 			 loff_t *offset)
315680ca6dcSChristopher Bostic {
316d8f45876SBenjamin Herrenschmidt 	struct scom_device *scom = filep->private_data;
317680ca6dcSChristopher Bostic 	struct device *dev = &scom->fsi_dev->dev;
318680ca6dcSChristopher Bostic 	uint64_t val;
3196b293258SBenjamin Herrenschmidt 	int rc;
320680ca6dcSChristopher Bostic 
321680ca6dcSChristopher Bostic 	if (len != sizeof(uint64_t))
322680ca6dcSChristopher Bostic 		return -EINVAL;
323680ca6dcSChristopher Bostic 
3246b293258SBenjamin Herrenschmidt 	mutex_lock(&scom->lock);
325d8f45876SBenjamin Herrenschmidt 	if (scom->dead)
326d8f45876SBenjamin Herrenschmidt 		rc = -ENODEV;
327d8f45876SBenjamin Herrenschmidt 	else
328680ca6dcSChristopher Bostic 		rc = get_scom(scom, &val, *offset);
3296b293258SBenjamin Herrenschmidt 	mutex_unlock(&scom->lock);
330680ca6dcSChristopher Bostic 	if (rc) {
331680ca6dcSChristopher Bostic 		dev_dbg(dev, "get_scom fail:%d\n", rc);
332680ca6dcSChristopher Bostic 		return rc;
333680ca6dcSChristopher Bostic 	}
334680ca6dcSChristopher Bostic 
335680ca6dcSChristopher Bostic 	rc = copy_to_user(buf, &val, len);
336680ca6dcSChristopher Bostic 	if (rc)
337680ca6dcSChristopher Bostic 		dev_dbg(dev, "copy to user failed:%d\n", rc);
338680ca6dcSChristopher Bostic 
339680ca6dcSChristopher Bostic 	return rc ? rc : len;
340680ca6dcSChristopher Bostic }
341680ca6dcSChristopher Bostic 
scom_write(struct file * filep,const char __user * buf,size_t len,loff_t * offset)342680ca6dcSChristopher Bostic static ssize_t scom_write(struct file *filep, const char __user *buf,
343680ca6dcSChristopher Bostic 			  size_t len, loff_t *offset)
344680ca6dcSChristopher Bostic {
345680ca6dcSChristopher Bostic 	int rc;
346d8f45876SBenjamin Herrenschmidt 	struct scom_device *scom = filep->private_data;
347680ca6dcSChristopher Bostic 	struct device *dev = &scom->fsi_dev->dev;
348680ca6dcSChristopher Bostic 	uint64_t val;
349680ca6dcSChristopher Bostic 
350680ca6dcSChristopher Bostic 	if (len != sizeof(uint64_t))
351680ca6dcSChristopher Bostic 		return -EINVAL;
352680ca6dcSChristopher Bostic 
353680ca6dcSChristopher Bostic 	rc = copy_from_user(&val, buf, len);
354680ca6dcSChristopher Bostic 	if (rc) {
355680ca6dcSChristopher Bostic 		dev_dbg(dev, "copy from user failed:%d\n", rc);
356680ca6dcSChristopher Bostic 		return -EINVAL;
357680ca6dcSChristopher Bostic 	}
358680ca6dcSChristopher Bostic 
3596b293258SBenjamin Herrenschmidt 	mutex_lock(&scom->lock);
360d8f45876SBenjamin Herrenschmidt 	if (scom->dead)
361d8f45876SBenjamin Herrenschmidt 		rc = -ENODEV;
362d8f45876SBenjamin Herrenschmidt 	else
363680ca6dcSChristopher Bostic 		rc = put_scom(scom, val, *offset);
3646b293258SBenjamin Herrenschmidt 	mutex_unlock(&scom->lock);
365680ca6dcSChristopher Bostic 	if (rc) {
366680ca6dcSChristopher Bostic 		dev_dbg(dev, "put_scom failed with:%d\n", rc);
367680ca6dcSChristopher Bostic 		return rc;
368680ca6dcSChristopher Bostic 	}
369680ca6dcSChristopher Bostic 
370680ca6dcSChristopher Bostic 	return len;
371680ca6dcSChristopher Bostic }
372680ca6dcSChristopher Bostic 
scom_llseek(struct file * file,loff_t offset,int whence)373680ca6dcSChristopher Bostic static loff_t scom_llseek(struct file *file, loff_t offset, int whence)
374680ca6dcSChristopher Bostic {
375680ca6dcSChristopher Bostic 	switch (whence) {
376680ca6dcSChristopher Bostic 	case SEEK_CUR:
377680ca6dcSChristopher Bostic 		break;
378680ca6dcSChristopher Bostic 	case SEEK_SET:
379680ca6dcSChristopher Bostic 		file->f_pos = offset;
380680ca6dcSChristopher Bostic 		break;
381680ca6dcSChristopher Bostic 	default:
382680ca6dcSChristopher Bostic 		return -EINVAL;
383680ca6dcSChristopher Bostic 	}
384680ca6dcSChristopher Bostic 
385680ca6dcSChristopher Bostic 	return offset;
386680ca6dcSChristopher Bostic }
387680ca6dcSChristopher Bostic 
raw_convert_status(struct scom_access * acc,uint32_t status)3886b293258SBenjamin Herrenschmidt static void raw_convert_status(struct scom_access *acc, uint32_t status)
3896b293258SBenjamin Herrenschmidt {
3906b293258SBenjamin Herrenschmidt 	acc->pib_status = (status & SCOM_STATUS_PIB_RESP_MASK) >>
3916b293258SBenjamin Herrenschmidt 		SCOM_STATUS_PIB_RESP_SHIFT;
3926b293258SBenjamin Herrenschmidt 	acc->intf_errors = 0;
3936b293258SBenjamin Herrenschmidt 
3946b293258SBenjamin Herrenschmidt 	if (status & SCOM_STATUS_PROTECTION)
3956b293258SBenjamin Herrenschmidt 		acc->intf_errors |= SCOM_INTF_ERR_PROTECTION;
3966b293258SBenjamin Herrenschmidt 	else if (status & SCOM_STATUS_PARITY)
3976b293258SBenjamin Herrenschmidt 		acc->intf_errors |= SCOM_INTF_ERR_PARITY;
3986b293258SBenjamin Herrenschmidt 	else if (status & SCOM_STATUS_PIB_ABORT)
3996b293258SBenjamin Herrenschmidt 		acc->intf_errors |= SCOM_INTF_ERR_ABORT;
4006b293258SBenjamin Herrenschmidt 	else if (status & SCOM_STATUS_ERR_SUMMARY)
4016b293258SBenjamin Herrenschmidt 		acc->intf_errors |= SCOM_INTF_ERR_UNKNOWN;
4026b293258SBenjamin Herrenschmidt }
4036b293258SBenjamin Herrenschmidt 
scom_raw_read(struct scom_device * scom,void __user * argp)4046b293258SBenjamin Herrenschmidt static int scom_raw_read(struct scom_device *scom, void __user *argp)
4056b293258SBenjamin Herrenschmidt {
4066b293258SBenjamin Herrenschmidt 	struct scom_access acc;
4076b293258SBenjamin Herrenschmidt 	uint32_t status;
4086b293258SBenjamin Herrenschmidt 	int rc;
4096b293258SBenjamin Herrenschmidt 
4106b293258SBenjamin Herrenschmidt 	if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
4116b293258SBenjamin Herrenschmidt 		return -EFAULT;
4126b293258SBenjamin Herrenschmidt 
4136b293258SBenjamin Herrenschmidt 	rc = raw_get_scom(scom, &acc.data, acc.addr, &status);
4146b293258SBenjamin Herrenschmidt 	if (rc)
4156b293258SBenjamin Herrenschmidt 		return rc;
4166b293258SBenjamin Herrenschmidt 	raw_convert_status(&acc, status);
4176b293258SBenjamin Herrenschmidt 	if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
4186b293258SBenjamin Herrenschmidt 		return -EFAULT;
4196b293258SBenjamin Herrenschmidt 	return 0;
4206b293258SBenjamin Herrenschmidt }
4216b293258SBenjamin Herrenschmidt 
scom_raw_write(struct scom_device * scom,void __user * argp)4226b293258SBenjamin Herrenschmidt static int scom_raw_write(struct scom_device *scom, void __user *argp)
4236b293258SBenjamin Herrenschmidt {
4246b293258SBenjamin Herrenschmidt 	u64 prev_data, mask, data;
4256b293258SBenjamin Herrenschmidt 	struct scom_access acc;
4266b293258SBenjamin Herrenschmidt 	uint32_t status;
4276b293258SBenjamin Herrenschmidt 	int rc;
4286b293258SBenjamin Herrenschmidt 
4296b293258SBenjamin Herrenschmidt 	if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
4306b293258SBenjamin Herrenschmidt 		return -EFAULT;
4316b293258SBenjamin Herrenschmidt 
4326b293258SBenjamin Herrenschmidt 	if (acc.mask) {
4336b293258SBenjamin Herrenschmidt 		rc = raw_get_scom(scom, &prev_data, acc.addr, &status);
4346b293258SBenjamin Herrenschmidt 		if (rc)
4356b293258SBenjamin Herrenschmidt 			return rc;
4366b293258SBenjamin Herrenschmidt 		if (status & SCOM_STATUS_ANY_ERR)
4376b293258SBenjamin Herrenschmidt 			goto fail;
4386b293258SBenjamin Herrenschmidt 		mask = acc.mask;
4396b293258SBenjamin Herrenschmidt 	} else {
4406b293258SBenjamin Herrenschmidt 		prev_data = mask = -1ull;
4416b293258SBenjamin Herrenschmidt 	}
4426b293258SBenjamin Herrenschmidt 	data = (prev_data & ~mask) | (acc.data & mask);
4436b293258SBenjamin Herrenschmidt 	rc = raw_put_scom(scom, data, acc.addr, &status);
4446b293258SBenjamin Herrenschmidt 	if (rc)
4456b293258SBenjamin Herrenschmidt 		return rc;
4466b293258SBenjamin Herrenschmidt  fail:
4476b293258SBenjamin Herrenschmidt 	raw_convert_status(&acc, status);
4486b293258SBenjamin Herrenschmidt 	if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
4496b293258SBenjamin Herrenschmidt 		return -EFAULT;
4506b293258SBenjamin Herrenschmidt 	return 0;
4516b293258SBenjamin Herrenschmidt }
4526b293258SBenjamin Herrenschmidt 
scom_reset(struct scom_device * scom,void __user * argp)4536b293258SBenjamin Herrenschmidt static int scom_reset(struct scom_device *scom, void __user *argp)
4546b293258SBenjamin Herrenschmidt {
4556b293258SBenjamin Herrenschmidt 	uint32_t flags, dummy = -1;
4566b293258SBenjamin Herrenschmidt 	int rc = 0;
4576b293258SBenjamin Herrenschmidt 
4586b293258SBenjamin Herrenschmidt 	if (get_user(flags, (__u32 __user *)argp))
4596b293258SBenjamin Herrenschmidt 		return -EFAULT;
4606b293258SBenjamin Herrenschmidt 	if (flags & SCOM_RESET_PIB)
4616b293258SBenjamin Herrenschmidt 		rc = fsi_device_write(scom->fsi_dev, SCOM_PIB_RESET_REG, &dummy,
4626b293258SBenjamin Herrenschmidt 				      sizeof(uint32_t));
4636b293258SBenjamin Herrenschmidt 	if (!rc && (flags & (SCOM_RESET_PIB | SCOM_RESET_INTF)))
4646b293258SBenjamin Herrenschmidt 		rc = fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
4656b293258SBenjamin Herrenschmidt 				      sizeof(uint32_t));
4666b293258SBenjamin Herrenschmidt 	return rc;
4676b293258SBenjamin Herrenschmidt }
4686b293258SBenjamin Herrenschmidt 
scom_check(struct scom_device * scom,void __user * argp)4696b293258SBenjamin Herrenschmidt static int scom_check(struct scom_device *scom, void __user *argp)
4706b293258SBenjamin Herrenschmidt {
4716b293258SBenjamin Herrenschmidt 	/* Still need to find out how to get "protected" */
4726b293258SBenjamin Herrenschmidt 	return put_user(SCOM_CHECK_SUPPORTED, (__u32 __user *)argp);
4736b293258SBenjamin Herrenschmidt }
4746b293258SBenjamin Herrenschmidt 
scom_ioctl(struct file * file,unsigned int cmd,unsigned long arg)4756b293258SBenjamin Herrenschmidt static long scom_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4766b293258SBenjamin Herrenschmidt {
477d8f45876SBenjamin Herrenschmidt 	struct scom_device *scom = file->private_data;
4786b293258SBenjamin Herrenschmidt 	void __user *argp = (void __user *)arg;
4796b293258SBenjamin Herrenschmidt 	int rc = -ENOTTY;
4806b293258SBenjamin Herrenschmidt 
4816b293258SBenjamin Herrenschmidt 	mutex_lock(&scom->lock);
482d8f45876SBenjamin Herrenschmidt 	if (scom->dead) {
483d8f45876SBenjamin Herrenschmidt 		mutex_unlock(&scom->lock);
484d8f45876SBenjamin Herrenschmidt 		return -ENODEV;
485d8f45876SBenjamin Herrenschmidt 	}
4866b293258SBenjamin Herrenschmidt 	switch(cmd) {
4876b293258SBenjamin Herrenschmidt 	case FSI_SCOM_CHECK:
4886b293258SBenjamin Herrenschmidt 		rc = scom_check(scom, argp);
4896b293258SBenjamin Herrenschmidt 		break;
4906b293258SBenjamin Herrenschmidt 	case FSI_SCOM_READ:
4916b293258SBenjamin Herrenschmidt 		rc = scom_raw_read(scom, argp);
4926b293258SBenjamin Herrenschmidt 		break;
4936b293258SBenjamin Herrenschmidt 	case FSI_SCOM_WRITE:
4946b293258SBenjamin Herrenschmidt 		rc = scom_raw_write(scom, argp);
4956b293258SBenjamin Herrenschmidt 		break;
4966b293258SBenjamin Herrenschmidt 	case FSI_SCOM_RESET:
4976b293258SBenjamin Herrenschmidt 		rc = scom_reset(scom, argp);
4986b293258SBenjamin Herrenschmidt 		break;
4996b293258SBenjamin Herrenschmidt 	}
5006b293258SBenjamin Herrenschmidt 	mutex_unlock(&scom->lock);
5016b293258SBenjamin Herrenschmidt 	return rc;
5026b293258SBenjamin Herrenschmidt }
5036b293258SBenjamin Herrenschmidt 
scom_open(struct inode * inode,struct file * file)504d8f45876SBenjamin Herrenschmidt static int scom_open(struct inode *inode, struct file *file)
505d8f45876SBenjamin Herrenschmidt {
506d8f45876SBenjamin Herrenschmidt 	struct scom_device *scom = container_of(inode->i_cdev, struct scom_device, cdev);
507d8f45876SBenjamin Herrenschmidt 
508d8f45876SBenjamin Herrenschmidt 	file->private_data = scom;
509d8f45876SBenjamin Herrenschmidt 
510d8f45876SBenjamin Herrenschmidt 	return 0;
511d8f45876SBenjamin Herrenschmidt }
512d8f45876SBenjamin Herrenschmidt 
513680ca6dcSChristopher Bostic static const struct file_operations scom_fops = {
514680ca6dcSChristopher Bostic 	.owner		= THIS_MODULE,
515d8f45876SBenjamin Herrenschmidt 	.open		= scom_open,
516680ca6dcSChristopher Bostic 	.llseek		= scom_llseek,
517680ca6dcSChristopher Bostic 	.read		= scom_read,
518680ca6dcSChristopher Bostic 	.write		= scom_write,
5196b293258SBenjamin Herrenschmidt 	.unlocked_ioctl	= scom_ioctl,
520680ca6dcSChristopher Bostic };
521680ca6dcSChristopher Bostic 
scom_free(struct device * dev)522d8f45876SBenjamin Herrenschmidt static void scom_free(struct device *dev)
523d8f45876SBenjamin Herrenschmidt {
524d8f45876SBenjamin Herrenschmidt 	struct scom_device *scom = container_of(dev, struct scom_device, dev);
525d8f45876SBenjamin Herrenschmidt 
526d8f45876SBenjamin Herrenschmidt 	put_device(&scom->fsi_dev->dev);
527d8f45876SBenjamin Herrenschmidt 	kfree(scom);
528d8f45876SBenjamin Herrenschmidt }
529d8f45876SBenjamin Herrenschmidt 
scom_probe(struct device * dev)530680ca6dcSChristopher Bostic static int scom_probe(struct device *dev)
531680ca6dcSChristopher Bostic {
532680ca6dcSChristopher Bostic 	struct fsi_device *fsi_dev = to_fsi_dev(dev);
533680ca6dcSChristopher Bostic 	struct scom_device *scom;
534d8f45876SBenjamin Herrenschmidt 	int rc, didx;
535680ca6dcSChristopher Bostic 
536d8f45876SBenjamin Herrenschmidt 	scom = kzalloc(sizeof(*scom), GFP_KERNEL);
537680ca6dcSChristopher Bostic 	if (!scom)
538680ca6dcSChristopher Bostic 		return -ENOMEM;
539d8f45876SBenjamin Herrenschmidt 	dev_set_drvdata(dev, scom);
540162c3946SBenjamin Herrenschmidt 	mutex_init(&scom->lock);
541680ca6dcSChristopher Bostic 
542d8f45876SBenjamin Herrenschmidt 	/* Grab a reference to the device (parent of our cdev), we'll drop it later */
543d8f45876SBenjamin Herrenschmidt 	if (!get_device(dev)) {
544d8f45876SBenjamin Herrenschmidt 		kfree(scom);
545d8f45876SBenjamin Herrenschmidt 		return -ENODEV;
546d8f45876SBenjamin Herrenschmidt 	}
547aa1221b2SBenjamin Herrenschmidt 	scom->fsi_dev = fsi_dev;
548d8f45876SBenjamin Herrenschmidt 
549d8f45876SBenjamin Herrenschmidt 	/* Create chardev for userspace access */
550d8f45876SBenjamin Herrenschmidt 	scom->dev.type = &fsi_cdev_type;
551d8f45876SBenjamin Herrenschmidt 	scom->dev.parent = dev;
552d8f45876SBenjamin Herrenschmidt 	scom->dev.release = scom_free;
553d8f45876SBenjamin Herrenschmidt 	device_initialize(&scom->dev);
554d8f45876SBenjamin Herrenschmidt 
555d8f45876SBenjamin Herrenschmidt 	/* Allocate a minor in the FSI space */
556d8f45876SBenjamin Herrenschmidt 	rc = fsi_get_new_minor(fsi_dev, fsi_dev_scom, &scom->dev.devt, &didx);
557d8f45876SBenjamin Herrenschmidt 	if (rc)
558d8f45876SBenjamin Herrenschmidt 		goto err;
559d8f45876SBenjamin Herrenschmidt 
560d8f45876SBenjamin Herrenschmidt 	dev_set_name(&scom->dev, "scom%d", didx);
561d8f45876SBenjamin Herrenschmidt 	cdev_init(&scom->cdev, &scom_fops);
562d8f45876SBenjamin Herrenschmidt 	rc = cdev_device_add(&scom->cdev, &scom->dev);
563d8f45876SBenjamin Herrenschmidt 	if (rc) {
564d8f45876SBenjamin Herrenschmidt 		dev_err(dev, "Error %d creating char device %s\n",
565d8f45876SBenjamin Herrenschmidt 			rc, dev_name(&scom->dev));
566d8f45876SBenjamin Herrenschmidt 		goto err_free_minor;
567d8f45876SBenjamin Herrenschmidt 	}
568d8f45876SBenjamin Herrenschmidt 
569d8f45876SBenjamin Herrenschmidt 	return 0;
570d8f45876SBenjamin Herrenschmidt  err_free_minor:
571d8f45876SBenjamin Herrenschmidt 	fsi_free_minor(scom->dev.devt);
572d8f45876SBenjamin Herrenschmidt  err:
573d8f45876SBenjamin Herrenschmidt 	put_device(&scom->dev);
574d8f45876SBenjamin Herrenschmidt 	return rc;
575680ca6dcSChristopher Bostic }
576680ca6dcSChristopher Bostic 
scom_remove(struct device * dev)577680ca6dcSChristopher Bostic static int scom_remove(struct device *dev)
578680ca6dcSChristopher Bostic {
579d8f45876SBenjamin Herrenschmidt 	struct scom_device *scom = dev_get_drvdata(dev);
580680ca6dcSChristopher Bostic 
581d8f45876SBenjamin Herrenschmidt 	mutex_lock(&scom->lock);
582d8f45876SBenjamin Herrenschmidt 	scom->dead = true;
583d8f45876SBenjamin Herrenschmidt 	mutex_unlock(&scom->lock);
584d8f45876SBenjamin Herrenschmidt 	cdev_device_del(&scom->cdev, &scom->dev);
585d8f45876SBenjamin Herrenschmidt 	fsi_free_minor(scom->dev.devt);
586d8f45876SBenjamin Herrenschmidt 	put_device(&scom->dev);
587680ca6dcSChristopher Bostic 
588680ca6dcSChristopher Bostic 	return 0;
589680ca6dcSChristopher Bostic }
590680ca6dcSChristopher Bostic 
591c21d322eSEddie James static const struct of_device_id scom_of_ids[] = {
592c21d322eSEddie James 	{ .compatible = "ibm,fsi2pib" },
593c21d322eSEddie James 	{ }
594c21d322eSEddie James };
595c21d322eSEddie James MODULE_DEVICE_TABLE(of, scom_of_ids);
596c21d322eSEddie James 
59759165631SRikard Falkeborn static const struct fsi_device_id scom_ids[] = {
598680ca6dcSChristopher Bostic 	{
599680ca6dcSChristopher Bostic 		.engine_type = FSI_ENGID_SCOM,
600680ca6dcSChristopher Bostic 		.version = FSI_VERSION_ANY,
601680ca6dcSChristopher Bostic 	},
602680ca6dcSChristopher Bostic 	{ 0 }
603680ca6dcSChristopher Bostic };
604680ca6dcSChristopher Bostic 
605680ca6dcSChristopher Bostic static struct fsi_driver scom_drv = {
606680ca6dcSChristopher Bostic 	.id_table = scom_ids,
607680ca6dcSChristopher Bostic 	.drv = {
608680ca6dcSChristopher Bostic 		.name = "scom",
609680ca6dcSChristopher Bostic 		.bus = &fsi_bus_type,
610c21d322eSEddie James 		.of_match_table = scom_of_ids,
611680ca6dcSChristopher Bostic 		.probe = scom_probe,
612680ca6dcSChristopher Bostic 		.remove = scom_remove,
613680ca6dcSChristopher Bostic 	}
614680ca6dcSChristopher Bostic };
615680ca6dcSChristopher Bostic 
scom_init(void)616680ca6dcSChristopher Bostic static int scom_init(void)
617680ca6dcSChristopher Bostic {
618680ca6dcSChristopher Bostic 	return fsi_driver_register(&scom_drv);
619680ca6dcSChristopher Bostic }
620680ca6dcSChristopher Bostic 
scom_exit(void)621680ca6dcSChristopher Bostic static void scom_exit(void)
622680ca6dcSChristopher Bostic {
623680ca6dcSChristopher Bostic 	fsi_driver_unregister(&scom_drv);
624680ca6dcSChristopher Bostic }
625680ca6dcSChristopher Bostic 
626680ca6dcSChristopher Bostic module_init(scom_init);
627680ca6dcSChristopher Bostic module_exit(scom_exit);
628*be62f128SJeff Johnson MODULE_DESCRIPTION("SCOM FSI Client device driver");
629680ca6dcSChristopher Bostic MODULE_LICENSE("GPL");
630