summaryrefslogtreecommitdiff
path: root/drivers/fsi/fsi-scom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/fsi/fsi-scom.c')
-rw-r--r--drivers/fsi/fsi-scom.c173
1 files changed, 64 insertions, 109 deletions
diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c
index 81dc01ac2351..411ddc018cd8 100644
--- a/drivers/fsi/fsi-scom.c
+++ b/drivers/fsi/fsi-scom.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCOM FSI Client device driver
*
* Copyright (C) IBM Corporation 2016
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/fsi.h>
@@ -18,6 +10,7 @@
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/mod_devicetable.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/list.h>
@@ -46,10 +39,10 @@
#define SCOM_STATUS_PIB_RESP_MASK 0x00007000
#define SCOM_STATUS_PIB_RESP_SHIFT 12
-#define SCOM_STATUS_ANY_ERR (SCOM_STATUS_ERR_SUMMARY | \
- SCOM_STATUS_PROTECTION | \
- SCOM_STATUS_PARITY | \
- SCOM_STATUS_PIB_ABORT | \
+#define SCOM_STATUS_FSI2PIB_ERROR (SCOM_STATUS_PROTECTION | \
+ SCOM_STATUS_PARITY | \
+ SCOM_STATUS_PIB_ABORT)
+#define SCOM_STATUS_ANY_ERR (SCOM_STATUS_FSI2PIB_ERROR | \
SCOM_STATUS_PIB_RESP_MASK)
/* SCOM address encodings */
#define XSCOM_ADDR_IND_FLAG BIT_ULL(63)
@@ -69,7 +62,6 @@
#define XSCOM_ADDR_FORM1_HI_SHIFT 20
/* Retries */
-#define SCOM_MAX_RETRIES 100 /* Retries on busy */
#define SCOM_MAX_IND_RETRIES 10 /* Retries indirect not ready */
struct scom_device {
@@ -154,7 +146,7 @@ static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
uint64_t addr, uint32_t *status)
{
uint64_t ind_data, ind_addr;
- int rc, retries, err = 0;
+ int rc, err;
if (value & ~XSCOM_DATA_IND_DATA)
return -EINVAL;
@@ -165,19 +157,14 @@ static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
if (rc || (*status & SCOM_STATUS_ANY_ERR))
return rc;
- for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
- rc = __get_scom(scom, &ind_data, addr, status);
- if (rc || (*status & SCOM_STATUS_ANY_ERR))
- return rc;
+ rc = __get_scom(scom, &ind_data, addr, status);
+ if (rc || (*status & SCOM_STATUS_ANY_ERR))
+ return rc;
- err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
- *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
- if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
- return 0;
+ err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
+ *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
- msleep(1);
- }
- return rc;
+ return 0;
}
static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value,
@@ -197,7 +184,7 @@ static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
uint64_t addr, uint32_t *status)
{
uint64_t ind_data, ind_addr;
- int rc, retries, err = 0;
+ int rc, err;
ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ;
@@ -205,21 +192,15 @@ static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
if (rc || (*status & SCOM_STATUS_ANY_ERR))
return rc;
- for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
- rc = __get_scom(scom, &ind_data, addr, status);
- if (rc || (*status & SCOM_STATUS_ANY_ERR))
- return rc;
-
- err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
- *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
- *value = ind_data & XSCOM_DATA_IND_DATA;
+ rc = __get_scom(scom, &ind_data, addr, status);
+ if (rc || (*status & SCOM_STATUS_ANY_ERR))
+ return rc;
- if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
- return 0;
+ err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
+ *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
+ *value = ind_data & XSCOM_DATA_IND_DATA;
- msleep(1);
- }
- return rc;
+ return 0;
}
static int raw_put_scom(struct scom_device *scom, uint64_t value,
@@ -249,21 +230,17 @@ static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
{
uint32_t dummy = -1;
- if (status & SCOM_STATUS_PROTECTION)
- return -EPERM;
- if (status & SCOM_STATUS_PARITY) {
+ if (status & SCOM_STATUS_FSI2PIB_ERROR)
fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
sizeof(uint32_t));
+
+ if (status & SCOM_STATUS_PROTECTION)
+ return -EPERM;
+ if (status & SCOM_STATUS_PARITY)
return -EIO;
- }
- /* Return -EBUSY on PIB abort to force a retry */
+
if (status & SCOM_STATUS_PIB_ABORT)
return -EBUSY;
- if (status & SCOM_STATUS_ERR_SUMMARY) {
- fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
- sizeof(uint32_t));
- return -EIO;
- }
return 0;
}
@@ -298,69 +275,39 @@ static int handle_pib_status(struct scom_device *scom, uint8_t status)
static int put_scom(struct scom_device *scom, uint64_t value,
uint64_t addr)
{
- uint32_t status, dummy = -1;
- int rc, retries;
-
- for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
- rc = raw_put_scom(scom, value, addr, &status);
- if (rc) {
- /* Try resetting the bridge if FSI fails */
- if (rc != -ENODEV && retries == 0) {
- fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
- &dummy, sizeof(uint32_t));
- rc = -EBUSY;
- } else
- return rc;
- } else
- rc = handle_fsi2pib_status(scom, status);
- if (rc && rc != -EBUSY)
- break;
- if (rc == 0) {
- rc = handle_pib_status(scom,
- (status & SCOM_STATUS_PIB_RESP_MASK)
- >> SCOM_STATUS_PIB_RESP_SHIFT);
- if (rc && rc != -EBUSY)
- break;
- }
- if (rc == 0)
- break;
- msleep(1);
- }
- return rc;
+ uint32_t status;
+ int rc;
+
+ rc = raw_put_scom(scom, value, addr, &status);
+ if (rc)
+ return rc;
+
+ rc = handle_fsi2pib_status(scom, status);
+ if (rc)
+ return rc;
+
+ return handle_pib_status(scom,
+ (status & SCOM_STATUS_PIB_RESP_MASK)
+ >> SCOM_STATUS_PIB_RESP_SHIFT);
}
static int get_scom(struct scom_device *scom, uint64_t *value,
uint64_t addr)
{
- uint32_t status, dummy = -1;
- int rc, retries;
-
- for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
- rc = raw_get_scom(scom, value, addr, &status);
- if (rc) {
- /* Try resetting the bridge if FSI fails */
- if (rc != -ENODEV && retries == 0) {
- fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
- &dummy, sizeof(uint32_t));
- rc = -EBUSY;
- } else
- return rc;
- } else
- rc = handle_fsi2pib_status(scom, status);
- if (rc && rc != -EBUSY)
- break;
- if (rc == 0) {
- rc = handle_pib_status(scom,
- (status & SCOM_STATUS_PIB_RESP_MASK)
- >> SCOM_STATUS_PIB_RESP_SHIFT);
- if (rc && rc != -EBUSY)
- break;
- }
- if (rc == 0)
- break;
- msleep(1);
- }
- return rc;
+ uint32_t status;
+ int rc;
+
+ rc = raw_get_scom(scom, value, addr, &status);
+ if (rc)
+ return rc;
+
+ rc = handle_fsi2pib_status(scom, status);
+ if (rc)
+ return rc;
+
+ return handle_pib_status(scom,
+ (status & SCOM_STATUS_PIB_RESP_MASK)
+ >> SCOM_STATUS_PIB_RESP_SHIFT);
}
static ssize_t scom_read(struct file *filep, char __user *buf, size_t len,
@@ -641,7 +588,13 @@ static int scom_remove(struct device *dev)
return 0;
}
-static struct fsi_device_id scom_ids[] = {
+static const struct of_device_id scom_of_ids[] = {
+ { .compatible = "ibm,fsi2pib" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, scom_of_ids);
+
+static const struct fsi_device_id scom_ids[] = {
{
.engine_type = FSI_ENGID_SCOM,
.version = FSI_VERSION_ANY,
@@ -654,6 +607,7 @@ static struct fsi_driver scom_drv = {
.drv = {
.name = "scom",
.bus = &fsi_bus_type,
+ .of_match_table = scom_of_ids,
.probe = scom_probe,
.remove = scom_remove,
}
@@ -671,4 +625,5 @@ static void scom_exit(void)
module_init(scom_init);
module_exit(scom_exit);
+MODULE_DESCRIPTION("SCOM FSI Client device driver");
MODULE_LICENSE("GPL");