From: John Garry <john.garry@huawei.com>
To: mika.westerberg@linux.intel.com, rafael@kernel.org,
lorenzo.pieralisi@arm.com, rjw@rjwysocki.net,
hanjun.guo@linaro.org, robh+dt@kernel.org, bhelgaas@google.com,
arnd@arndb.de, mark.rutland@arm.com, olof@lixom.net,
dann.frazier@canonical.com, andy.shevchenko@gmail.com,
robh@kernel.org
Cc: joe@perches.com, benh@kernel.crashing.org,
linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-acpi@vger.kernel.org, linuxarm@huawei.com, minyard@acm.org,
devicetree@vger.kernel.org, linux-arch@vger.kernel.org,
rdunlap@infradead.org
Subject: [PATCH v13 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning
Date: Wed, 14 Feb 2018 01:45:31 +0800 [thread overview]
Message-ID: <1518543933-22456-8-git-send-email-john.garry@huawei.com> (raw)
In-Reply-To: <1518543933-22456-1-git-send-email-john.garry@huawei.com>
On some platforms (such as arm64-based hip06/hip07), access to legacy
ISA/LPC devices through access IO space is required, similar to x86
platforms. As the I/O for these devices are not memory mapped like
PCI/PCIE MMIO host bridges, they require special low-level device
operations through some host to generate IO accesses, i.e. a non-
transparent bridge.
Through the logical PIO framework, hosts are able to register address
ranges in the logical PIO space for IO accesses. For hosts which require
a LLDD to generate the IO accesses, through the logical PIO framework
the host also registers accessors as a backend to generate the physical
bus transactions for IO space accesses (called indirect IO).
When describing the indirect IO child device in APCI tables, the IO
resource is the host-specific address for the child (generally a
bus address).
An example is as follows:
Device (LPC0) {
Name (_HID, "HISI0191") // HiSi LPC
Name (_CRS, ResourceTemplate () {
Memory32Fixed (ReadWrite, 0xa01b0000, 0x1000)
})
}
Device (LPC0.IPMI) {
Name (_HID, "IPI0001")
Name (LORS, ResourceTemplate() {
QWordIO (
ResourceConsumer,
MinNotFixed, // _MIF
MaxNotFixed, // _MAF
PosDecode,
EntireRange,
0x0, // _GRA
0xe4, // _MIN
0x3fff, // _MAX
0x0, // _TRA
0x04, // _LEN
, ,
BTIO
)
})
Since the IO resource for the child is a host-specific address,
special translation are required to retrieve the logical PIO address
for that child.
To overcome the problem of associating this logical PIO address
with the child device, a scan handler is added to scan the ACPI
namespace for known indirect IO hosts. This scan handler creates an
MFD per child with the translated logical PIO address as it's IO
resource, as a substitute for the normal platform device which ACPI
would create during device enumeration.
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/acpi_indirectio.c | 250 +++++++++++++++++++++++++++++++++++
drivers/acpi/internal.h | 5 +
drivers/acpi/scan.c | 1 +
4 files changed, 257 insertions(+)
create mode 100644 drivers/acpi/arm64/acpi_indirectio.c
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 1017def..f4a7f46 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_ACPI_IORT) += iort.o
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
+obj-$(CONFIG_INDIRECT_PIO) += acpi_indirectio.o
diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
new file mode 100644
index 0000000..51a1b92
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 HiSilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: John Garry <john.garry@huawei.com>
+ *
+ * This file implements functunality to scan the ACPI namespace and config
+ * devices under "indirect IO" hosts. An "indirect IO" host allows child
+ * devices to use logical IO accesses when the host, itself, does not provide
+ * a transparent bridge. The device setup creates a per-child MFD with a
+ * logical port IO resource.
+ */
+
+#include <linux/acpi.h>
+#include <linux/logic_pio.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define ACPI_INDIRECT_IO_NAME_LEN 255
+
+struct acpi_indirect_io_mfd_cell {
+ struct mfd_cell_acpi_match acpi_match;
+ char name[ACPI_INDIRECT_IO_NAME_LEN];
+ char pnpid[ACPI_INDIRECT_IO_NAME_LEN];
+};
+
+static int acpi_indirect_io_xlat_res(struct acpi_device *adev,
+ struct acpi_device *host,
+ struct resource *res)
+{
+ unsigned long sys_port;
+ resource_size_t len = res->end - res->start;
+
+ sys_port = logic_pio_trans_hwaddr(&host->fwnode, res->start, len);
+ if (sys_port == -1UL)
+ return -EFAULT;
+
+ res->start = sys_port;
+ res->end = sys_port + len;
+
+ return 0;
+}
+
+/*
+ * acpi_indirect_io_set_res - set the resources for a child device
+ * (MFD) of an "indirect IO" host.
+ * @child: the device node to be updated the I/O resource
+ * @hostdev: the device node associated with the "indirect IO" host
+ * @res: double pointer to be set to the address of translated resources
+ * @num_res: pointer to variable to hold the number of translated resources
+ *
+ * Returns 0 when successful, and a negative value for failure.
+ *
+ * For a given "indirect IO" host, each child device will have associated
+ * host-relevative address resource. This function will return the translated
+ * logical PIO addresses for each child devices resources.
+ */
+static int acpi_indirect_io_set_res(struct device *child,
+ struct device *hostdev,
+ const struct resource **res,
+ int *num_res)
+{
+ struct acpi_device *adev;
+ struct acpi_device *host;
+ struct resource_entry *rentry;
+ LIST_HEAD(resource_list);
+ struct resource *resources;
+ int count;
+ int i;
+ int ret = -EIO;
+
+ if (!child || !hostdev)
+ return -EINVAL;
+
+ host = to_acpi_device(hostdev);
+ adev = to_acpi_device(child);
+
+ /* check the device state */
+ if (!adev->status.present) {
+ dev_info(child, "device is not present\n");
+ return 0;
+ }
+ /* whether the child had been enumerated? */
+ if (acpi_device_enumerated(adev)) {
+ dev_info(child, "had been enumerated\n");
+ return 0;
+ }
+
+ count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+ if (count <= 0) {
+ dev_err(child, "failed to get resources\n");
+ return count ? count : -EIO;
+ }
+
+ resources = kcalloc(count, sizeof(*resources), GFP_KERNEL);
+ if (!resources) {
+ acpi_dev_free_resource_list(&resource_list);
+ return -ENOMEM;
+ }
+ count = 0;
+ list_for_each_entry(rentry, &resource_list, node)
+ resources[count++] = *rentry->res;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ /* translate the I/O resources */
+ for (i = 0; i < count; i++) {
+ if (!(resources[i].flags & IORESOURCE_IO))
+ continue;
+ ret = acpi_indirect_io_xlat_res(adev, host, &resources[i]);
+ if (ret) {
+ kfree(resources);
+ dev_err(child, "translate IO range failed(%d)\n", ret);
+ return ret;
+ }
+ }
+ *res = resources;
+ *num_res = count;
+
+ return ret;
+}
+
+/*
+ * acpi_indirect_io_setup - scan handler for "indirect IO" host.
+ * @adev: "indirect IO" host ACPI device pointer
+ * Returns 0 when successful, and a negative value for failure.
+ *
+ * Setup an "indirect IO" host by scanning all child devices, and
+ * create a per-device MFD with logical PIO translated IO resources.
+ */
+static int acpi_indirect_io_setup(struct acpi_device *adev)
+{
+ struct platform_device *pdev;
+ struct mfd_cell *mfd_cells;
+ struct logic_pio_hwaddr *range;
+ struct acpi_device *child;
+ struct acpi_indirect_io_mfd_cell *acpi_indirect_io_mfd_cells;
+ int size, ret, count = 0, cell_num = 0;
+
+ range = kzalloc(sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return -ENOMEM;
+ range->fwnode = &adev->fwnode;
+ range->flags = PIO_INDIRECT;
+ range->size = PIO_INDIRECT_SIZE;
+
+ ret = logic_pio_register_range(range);
+ if (ret)
+ goto free_range;
+
+ list_for_each_entry(child, &adev->children, node)
+ cell_num++;
+
+ /* allocate the mfd cell and companion acpi info, one per child */
+ size = sizeof(*mfd_cells) + sizeof(*acpi_indirect_io_mfd_cells);
+ mfd_cells = kcalloc(cell_num, size, GFP_KERNEL);
+ if (!mfd_cells) {
+ ret = -ENOMEM;
+ goto free_range;
+ }
+
+ acpi_indirect_io_mfd_cells = (struct acpi_indirect_io_mfd_cell *)
+ &mfd_cells[cell_num];
+ /* Only consider the children of the host */
+ list_for_each_entry(child, &adev->children, node) {
+ struct mfd_cell *mfd_cell = &mfd_cells[count];
+ struct acpi_indirect_io_mfd_cell *acpi_indirect_io_mfd_cell =
+ &acpi_indirect_io_mfd_cells[count];
+ const struct mfd_cell_acpi_match *acpi_match =
+ &acpi_indirect_io_mfd_cell->acpi_match;
+ char *name = &acpi_indirect_io_mfd_cell[count].name[0];
+ char *pnpid = &acpi_indirect_io_mfd_cell[count].pnpid[0];
+ struct mfd_cell_acpi_match match = {
+ .pnpid = pnpid,
+ };
+
+ snprintf(name, ACPI_INDIRECT_IO_NAME_LEN, "indirect-io-%s",
+ acpi_device_hid(child));
+ snprintf(pnpid, ACPI_INDIRECT_IO_NAME_LEN, "%s",
+ acpi_device_hid(child));
+
+ memcpy((void *)acpi_match, (void *)&match, sizeof(*acpi_match));
+ mfd_cell->name = name;
+ mfd_cell->acpi_match = acpi_match;
+
+ ret = acpi_indirect_io_set_res(&child->dev, &adev->dev,
+ &mfd_cell->resources,
+ &mfd_cell->num_resources);
+ if (ret) {
+ dev_err(&child->dev, "set resource failed (%d)\n", ret);
+ goto free_mfd_resources;
+ }
+ count++;
+ }
+
+ pdev = acpi_create_platform_device(adev, NULL);
+ if (IS_ERR_OR_NULL(pdev)) {
+ dev_err(&adev->dev, "create platform device for host failed\n");
+ ret = PTR_ERR(pdev);
+ goto free_mfd_resources;
+ }
+ acpi_device_set_enumerated(adev);
+
+ ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+ mfd_cells, cell_num, NULL, 0, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add mfd cells (%d)\n", ret);
+ goto free_mfd_resources;
+ }
+
+ return ret;
+
+free_mfd_resources:
+ while (cell_num--)
+ kfree(mfd_cells[cell_num].resources);
+ kfree(mfd_cells);
+free_range:
+ kfree(range);
+
+ return ret;
+}
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_io_host_id[] = {
+ {}
+};
+
+static int acpi_indirect_io_attach(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+ int ret = acpi_indirect_io_setup(adev);
+
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
+static struct acpi_scan_handler acpi_indirect_io_handler = {
+ .ids = acpi_indirect_io_host_id,
+ .attach = acpi_indirect_io_attach,
+};
+
+void __init acpi_indirect_io_scan_init(void)
+{
+ acpi_scan_add_handler(&acpi_indirect_io_handler);
+}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 1d0a501..680f3cf 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@
void acpi_platform_init(void);
void acpi_pnp_init(void);
void acpi_int340x_thermal_init(void);
+#ifdef CONFIG_INDIRECT_PIO
+void acpi_indirect_io_scan_init(void);
+#else
+static inline void acpi_indirect_io_scan_init(void) {}
+#endif
#ifdef CONFIG_ARM_AMBA
void acpi_amba_init(void);
#else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8e63d93..204da8a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2155,6 +2155,7 @@ int __init acpi_scan_init(void)
acpi_amba_init();
acpi_watchdog_init();
acpi_init_lpit();
+ acpi_indirect_io_scan_init();
acpi_scan_add_handler(&generic_device_handler);
--
1.9.1
next prev parent reply other threads:[~2018-02-13 17:45 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-13 17:45 [PATCH v13 0/9] LPC: legacy ISA I/O support John Garry
2018-02-13 17:45 ` [PATCH v13 1/9] LIB: Introduce a generic PIO mapping method John Garry
[not found] ` <1518543933-22456-2-git-send-email-john.garry-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
2018-02-13 23:05 ` dann frazier
2018-02-14 16:13 ` John Garry
2018-02-13 17:45 ` [PATCH v13 2/9] PCI: Remove unused __weak attribute in pci_register_io_range() John Garry
2018-02-13 17:45 ` [PATCH v13 3/9] PCI: Add fwnode handler as input param of pci_register_io_range() John Garry
2018-02-13 17:45 ` [PATCH v13 4/9] PCI: Apply the new generic I/O management on PCI IO hosts John Garry
2018-02-13 22:57 ` dann frazier
2018-02-14 15:42 ` John Garry
2018-02-14 16:05 ` dann frazier
2018-02-13 17:45 ` [PATCH v13 5/9] OF: Add missing I/O range exception for indirect-IO devices John Garry
[not found] ` <1518543933-22456-1-git-send-email-john.garry-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
2018-02-13 17:45 ` [PATCH v13 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings John Garry
2018-02-13 17:45 ` John Garry [this message]
2018-02-14 9:21 ` [PATCH v13 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning Rafael J. Wysocki
2018-02-14 12:48 ` John Garry
2018-02-14 13:53 ` Andy Shevchenko
2018-02-14 15:33 ` John Garry
2018-02-14 16:16 ` Andy Shevchenko
2018-02-15 17:07 ` John Garry
[not found] ` <59e5293f-0ea5-12f4-27db-b13bbcf0918b-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
2018-02-16 14:42 ` Andy Shevchenko
[not found] ` <CAHp75VeTQg+A9o5Ox-k_9Qx8=JPEnqg1taVjcd8Zd2rfj_TMog-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-02-16 14:48 ` John Garry
2018-02-14 16:16 ` Lorenzo Pieralisi
2018-02-14 16:52 ` John Garry
2018-02-15 11:19 ` John Garry
2018-02-15 11:47 ` Rafael J. Wysocki
[not found] ` <CAJZ5v0jGvo+cutmvi3WSe1JNvQ1UvZhJr1mQ76=8=1E5Gq+iRg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-02-15 12:36 ` Lorenzo Pieralisi
2018-02-15 12:59 ` John Garry
2018-02-15 12:22 ` Andy Shevchenko
[not found] ` <CAHp75VfFKcnUVQwPUxynzp88RXWdV8VEqtXxd0=_Q_GJKO6UpQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-02-15 12:52 ` John Garry
[not found] ` <f7b3de31-46fb-f80e-511e-651fa815bddf-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
2018-02-15 12:55 ` Andy Shevchenko
2018-02-13 17:45 ` [PATCH v13 8/9] LPC, ACPI: Add the HISI LPC ACPI support John Garry
2018-02-13 17:45 ` [PATCH v13 9/9] MAINTAINERS: Add maintainer for HiSilicon LPC driver John Garry
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1518543933-22456-8-git-send-email-john.garry@huawei.com \
--to=john.garry@huawei.com \
--cc=andy.shevchenko@gmail.com \
--cc=arnd@arndb.de \
--cc=benh@kernel.crashing.org \
--cc=bhelgaas@google.com \
--cc=dann.frazier@canonical.com \
--cc=devicetree@vger.kernel.org \
--cc=hanjun.guo@linaro.org \
--cc=joe@perches.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linuxarm@huawei.com \
--cc=lorenzo.pieralisi@arm.com \
--cc=mark.rutland@arm.com \
--cc=mika.westerberg@linux.intel.com \
--cc=minyard@acm.org \
--cc=olof@lixom.net \
--cc=rafael@kernel.org \
--cc=rdunlap@infradead.org \
--cc=rjw@rjwysocki.net \
--cc=robh+dt@kernel.org \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).