Commit f5e536af authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'fsi-for-v6.1-2' of...

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
parents 3aa12610 35af9fb4
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ibm,occ-hwmon.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: IBM On-Chip Controller (OCC) accessed from a service processor

maintainers:
  - Eddie James <eajames@linux.ibm.com>

description: |
  The POWER processor On-Chip Controller (OCC) helps manage power and
  thermals for the system. A service processor or baseboard management
  controller can query the OCC for it's power and thermal data to report
  through hwmon.

properties:
  compatible:
    enum:
      - ibm,p9-occ-hwmon
      - ibm,p10-occ-hwmon

  ibm,no-poll-on-init:
    description: This property describes whether or not the OCC should
      be polled during driver initialization.
    type: boolean

required:
  - compatible

additionalProperties: false

examples:
  - |
    hwmon {
        compatible = "ibm,p10-occ-hwmon";
        ibm,no-poll-on-init;
    };
+7 −4
Original line number Diff line number Diff line
@@ -392,7 +392,7 @@ 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,
int fsi_slave_claim_range(struct fsi_slave *slave,
			  uint32_t addr, uint32_t size)
{
	if (addr + size < addr)
@@ -406,7 +406,7 @@ 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,
void fsi_slave_release_range(struct fsi_slave *slave,
			     uint32_t addr, uint32_t size)
{
}
@@ -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;

+2 −0
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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 */

+54 −12
Original line number Diff line number Diff line
@@ -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_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);

Loading