diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-09-30 14:02:47 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-09-30 14:02:47 +0200 |
commit | f5e536af4860a7d07b769d0388a68e74fe453c9b (patch) | |
tree | 84c0c72180e986d0f6e8210549ef5b5bd39ba36c /drivers | |
parent | Merge tag 'icc-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/djak... (diff) | |
parent | fsi: core: Check error number after calling ida_simple_get (diff) | |
download | linux-f5e536af4860a7d07b769d0388a68e74fe453c9b.tar.xz linux-f5e536af4860a7d07b769d0388a68e74fe453c9b.zip |
Merge tag 'fsi-for-v6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi into char-misc-next
Joel writes:
"FSI changes for v6.1
* Fix a OCC hwmon userspace compatibility regression that was
introduced in v5.19
* Device tree bindings for the OCC
* A bunch of janitor type fixes"
* tag 'fsi-for-v6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi:
fsi: core: Check error number after calling ida_simple_get
hwmon: (occ) Check for device property for setting OCC active during probe
fsi: occ: Support probing the hwmon child device from dts node
dt-bindings: hwmon: Add IBM OCC bindings
fsi: master-ast-cf: Fix missing of_node_put in fsi_master_acf_probe
fsi: sbefifo: Add detailed debugging information
fsi: cleanup extern usage in function definition
fsi: occ: Prevent use after free
hwmon (occ): Retry for checksum failure
fsi: occ: Fix checksum failure mode
fsi: Fix typo in comment
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/fsi/fsi-core.c | 11 | ||||
-rw-r--r-- | drivers/fsi/fsi-master-ast-cf.c | 2 | ||||
-rw-r--r-- | drivers/fsi/fsi-master.h | 2 | ||||
-rw-r--r-- | drivers/fsi/fsi-occ.c | 66 | ||||
-rw-r--r-- | drivers/fsi/fsi-sbefifo.c | 15 | ||||
-rw-r--r-- | drivers/hwmon/occ/common.c | 11 | ||||
-rw-r--r-- | drivers/hwmon/occ/p9_sbe.c | 26 |
7 files changed, 104 insertions, 29 deletions
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index 3a7b78e36701..694e80c06665 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -392,8 +392,8 @@ int fsi_slave_write(struct fsi_slave *slave, uint32_t addr, } EXPORT_SYMBOL_GPL(fsi_slave_write); -extern int fsi_slave_claim_range(struct fsi_slave *slave, - uint32_t addr, uint32_t size) +int fsi_slave_claim_range(struct fsi_slave *slave, + uint32_t addr, uint32_t size) { if (addr + size < addr) return -EINVAL; @@ -406,8 +406,8 @@ extern int fsi_slave_claim_range(struct fsi_slave *slave, } EXPORT_SYMBOL_GPL(fsi_slave_claim_range); -extern void fsi_slave_release_range(struct fsi_slave *slave, - uint32_t addr, uint32_t size) +void fsi_slave_release_range(struct fsi_slave *slave, + uint32_t addr, uint32_t size) { } EXPORT_SYMBOL_GPL(fsi_slave_release_range); @@ -1314,6 +1314,9 @@ int fsi_master_register(struct fsi_master *master) mutex_init(&master->scan_lock); master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL); + if (master->idx < 0) + return master->idx; + dev_set_name(&master->dev, "fsi%d", master->idx); master->dev.class = &fsi_master_class; diff --git a/drivers/fsi/fsi-master-ast-cf.c b/drivers/fsi/fsi-master-ast-cf.c index 24292acdbaf8..5f608ef8b53c 100644 --- a/drivers/fsi/fsi-master-ast-cf.c +++ b/drivers/fsi/fsi-master-ast-cf.c @@ -1324,12 +1324,14 @@ static int fsi_master_acf_probe(struct platform_device *pdev) } master->cvic = devm_of_iomap(&pdev->dev, np, 0, NULL); if (IS_ERR(master->cvic)) { + of_node_put(np); rc = PTR_ERR(master->cvic); dev_err(&pdev->dev, "Error %d mapping CVIC\n", rc); goto err_free; } rc = of_property_read_u32(np, "copro-sw-interrupts", &master->cvic_sw_irq); + of_node_put(np); if (rc) { dev_err(&pdev->dev, "Can't find coprocessor SW interrupt\n"); goto err_free; diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h index cd6bee5e12a7..4762315a46ba 100644 --- a/drivers/fsi/fsi-master.h +++ b/drivers/fsi/fsi-master.h @@ -51,7 +51,7 @@ #define FSI_MMODE_CRS1SHFT 8 /* Clk rate selection 1 shift */ #define FSI_MMODE_CRS1MASK 0x3ff /* Clk rate selection 1 mask */ -/* MRESB: Reset brindge */ +/* MRESB: Reset bridge */ #define FSI_MRESB_RST_GEN 0x80000000 /* General reset */ #define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset */ diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index c9cc75fbdfb9..abdd37d5507f 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -44,6 +44,7 @@ struct occ { struct device *sbefifo; char name[32]; int idx; + bool platform_hwmon; u8 sequence_number; void *buffer; void *client_buffer; @@ -94,6 +95,7 @@ static int occ_open(struct inode *inode, struct file *file) client->occ = occ; mutex_init(&client->lock); file->private_data = client; + get_device(occ->dev); /* We allocate a 1-page buffer, make sure it all fits */ BUILD_BUG_ON((OCC_CMD_DATA_BYTES + 3) > PAGE_SIZE); @@ -197,6 +199,7 @@ static int occ_release(struct inode *inode, struct file *file) { struct occ_client *client = file->private_data; + put_device(client->occ->dev); free_page((unsigned long)client->buffer); kfree(client); @@ -246,7 +249,7 @@ static int occ_verify_checksum(struct occ *occ, struct occ_response *resp, if (checksum != checksum_resp) { dev_err(occ->dev, "Bad checksum: %04x!=%04x\n", checksum, checksum_resp); - return -EBADMSG; + return -EBADE; } return 0; @@ -493,12 +496,19 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len, for (i = 1; i < req_len - 2; ++i) checksum += byte_request[i]; - mutex_lock(&occ->occ_lock); + rc = mutex_lock_interruptible(&occ->occ_lock); + if (rc) + return rc; occ->client_buffer = response; occ->client_buffer_size = user_resp_len; occ->client_response_size = 0; + if (!occ->buffer) { + rc = -ENOENT; + goto done; + } + /* * Get a sequence number and update the counter. Avoid a sequence * number of 0 which would pass the response check below even if the @@ -575,8 +585,11 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len, dev_dbg(dev, "resp_status=%02x resp_data_len=%d\n", resp->return_status, resp_data_length); - occ->client_response_size = resp_data_length + 7; rc = occ_verify_checksum(occ, resp, resp_data_length); + if (rc) + goto done; + + occ->client_response_size = resp_data_length + 7; done: *resp_len = occ->client_response_size; @@ -586,7 +599,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len, } EXPORT_SYMBOL_GPL(fsi_occ_submit); -static int occ_unregister_child(struct device *dev, void *data) +static int occ_unregister_platform_child(struct device *dev, void *data) { struct platform_device *hwmon_dev = to_platform_device(dev); @@ -595,12 +608,25 @@ static int occ_unregister_child(struct device *dev, void *data) return 0; } +static int occ_unregister_of_child(struct device *dev, void *data) +{ + struct platform_device *hwmon_dev = to_platform_device(dev); + + of_device_unregister(hwmon_dev); + if (dev->of_node) + of_node_clear_flag(dev->of_node, OF_POPULATED); + + return 0; +} + static int occ_probe(struct platform_device *pdev) { int rc; u32 reg; + char child_name[32]; struct occ *occ; - struct platform_device *hwmon_dev; + struct platform_device *hwmon_dev = NULL; + struct device_node *hwmon_node; struct device *dev = &pdev->dev; struct platform_device_info hwmon_dev_info = { .parent = dev, @@ -659,10 +685,20 @@ static int occ_probe(struct platform_device *pdev) return rc; } - hwmon_dev_info.id = occ->idx; - hwmon_dev = platform_device_register_full(&hwmon_dev_info); - if (IS_ERR(hwmon_dev)) - dev_warn(dev, "failed to create hwmon device\n"); + hwmon_node = of_get_child_by_name(dev->of_node, hwmon_dev_info.name); + if (hwmon_node) { + snprintf(child_name, sizeof(child_name), "%s.%d", hwmon_dev_info.name, occ->idx); + hwmon_dev = of_platform_device_create(hwmon_node, child_name, dev); + of_node_put(hwmon_node); + } + + if (!hwmon_dev) { + occ->platform_hwmon = true; + hwmon_dev_info.id = occ->idx; + hwmon_dev = platform_device_register_full(&hwmon_dev_info); + if (IS_ERR(hwmon_dev)) + dev_warn(dev, "failed to create hwmon device\n"); + } return 0; } @@ -671,11 +707,17 @@ static int occ_remove(struct platform_device *pdev) { struct occ *occ = platform_get_drvdata(pdev); - kvfree(occ->buffer); - misc_deregister(&occ->mdev); - device_for_each_child(&pdev->dev, NULL, occ_unregister_child); + mutex_lock(&occ->occ_lock); + kvfree(occ->buffer); + occ->buffer = NULL; + mutex_unlock(&occ->occ_lock); + + if (occ->platform_hwmon) + device_for_each_child(&pdev->dev, NULL, occ_unregister_platform_child); + else + device_for_each_child(&pdev->dev, NULL, occ_unregister_of_child); ida_simple_remove(&occ_ida, occ->idx); diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c index f52a912cdf16..5f93a53846aa 100644 --- a/drivers/fsi/fsi-sbefifo.c +++ b/drivers/fsi/fsi-sbefifo.c @@ -477,7 +477,8 @@ static int sbefifo_wait(struct sbefifo *sbefifo, bool up, if (!ready) { sysfs_notify(&sbefifo->dev.kobj, NULL, dev_attr_timeout.attr.name); sbefifo->timed_out = true; - dev_err(dev, "%s FIFO Timeout ! status=%08x\n", up ? "UP" : "DOWN", sts); + dev_err(dev, "%s FIFO Timeout (%u ms)! status=%08x\n", + up ? "UP" : "DOWN", jiffies_to_msecs(timeout), sts); return -ETIMEDOUT; } dev_vdbg(dev, "End of wait status: %08x\n", sts); @@ -497,8 +498,8 @@ static int sbefifo_send_command(struct sbefifo *sbefifo, u32 status; int rc; - dev_vdbg(dev, "sending command (%zd words, cmd=%04x)\n", - cmd_len, be32_to_cpu(command[1])); + dev_dbg(dev, "sending command (%zd words, cmd=%04x)\n", + cmd_len, be32_to_cpu(command[1])); /* As long as there's something to send */ timeout = msecs_to_jiffies(SBEFIFO_TIMEOUT_START_CMD); @@ -551,21 +552,23 @@ static int sbefifo_read_response(struct sbefifo *sbefifo, struct iov_iter *respo size_t len; int rc; - dev_vdbg(dev, "reading response, buflen = %zd\n", iov_iter_count(response)); + dev_dbg(dev, "reading response, buflen = %zd\n", iov_iter_count(response)); timeout = msecs_to_jiffies(sbefifo->timeout_start_rsp_ms); for (;;) { /* Grab FIFO status (this will handle parity errors) */ rc = sbefifo_wait(sbefifo, false, &status, timeout); - if (rc < 0) + if (rc < 0) { + dev_dbg(dev, "timeout waiting (%u ms)\n", jiffies_to_msecs(timeout)); return rc; + } timeout = msecs_to_jiffies(SBEFIFO_TIMEOUT_IN_RSP); /* Decode status */ len = sbefifo_populated(status); eot_set = sbefifo_eot_set(status); - dev_vdbg(dev, " chunk size %zd eot_set=0x%x\n", len, eot_set); + dev_dbg(dev, " chunk size %zd eot_set=0x%x\n", len, eot_set); /* Go through the chunk */ while(len--) { diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 45407b12db4b..dd690f700d49 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -10,6 +10,7 @@ #include <linux/math64.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> #include <linux/sysfs.h> #include <asm/unaligned.h> @@ -1216,8 +1217,16 @@ int occ_setup(struct occ *occ) occ->groups[0] = &occ->group; rc = occ_setup_sysfs(occ); - if (rc) + if (rc) { dev_err(occ->bus_dev, "failed to setup sysfs: %d\n", rc); + return rc; + } + + if (!device_property_read_bool(occ->bus_dev, "ibm,no-poll-on-init")) { + rc = occ_active(occ, true); + if (rc) + occ_shutdown_sysfs(occ); + } return rc; } diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index c1e0a1d96cd4..96521363b696 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -7,6 +7,7 @@ #include <linux/fsi-occ.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/string.h> @@ -14,6 +15,8 @@ #include "common.h" +#define OCC_CHECKSUM_RETRIES 3 + struct p9_sbe_occ { struct occ occ; bool sbe_error; @@ -80,18 +83,23 @@ done: static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len, void *resp, size_t resp_len) { + size_t original_resp_len = resp_len; struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ); - int rc; + int rc, i; - rc = fsi_occ_submit(ctx->sbe, cmd, len, resp, &resp_len); - if (rc < 0) { + for (i = 0; i < OCC_CHECKSUM_RETRIES; ++i) { + rc = fsi_occ_submit(ctx->sbe, cmd, len, resp, &resp_len); + if (rc >= 0) + break; if (resp_len) { if (p9_sbe_occ_save_ffdc(ctx, resp, resp_len)) sysfs_notify(&occ->bus_dev->kobj, NULL, bin_attr_ffdc.attr.name); + return rc; } - - return rc; + if (rc != -EBADE) + return rc; + resp_len = original_resp_len; } switch (((struct occ_response *)resp)->return_status) { @@ -174,9 +182,17 @@ static int p9_sbe_occ_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id p9_sbe_occ_of_match[] = { + { .compatible = "ibm,p9-occ-hwmon" }, + { .compatible = "ibm,p10-occ-hwmon" }, + {} +}; +MODULE_DEVICE_TABLE(of, p9_sbe_occ_of_match); + static struct platform_driver p9_sbe_occ_driver = { .driver = { .name = "occ-hwmon", + .of_match_table = p9_sbe_occ_of_match, }, .probe = p9_sbe_occ_probe, .remove = p9_sbe_occ_remove, |