Re: [PATCH V5 5/5] LPC: Add the ACPI LPC support

2017-02-04 Thread John Garry

+ linux-acpi

Adding linux-acpi list, which should have been originally included.

The patchset threads have had much discussion, here is a pointer: 
http://www.spinics.net/lists/devicetree/msg160611.html


John

On 24/01/2017 07:05, zhichang.yuan wrote:

The patch update the _CRS of LPC children with the system logical I/O resource
after the translation from LPC-local I/O. Then the ACPI platform device
enumeration for LPC can apply the right I/O resource to request the system I/O
space.

Signed-off-by: zhichang.yuan 
---
 drivers/bus/hisi_lpc.c |  26 ++
 include/linux/extio.h  |   4 +
 lib/extio.c| 228 +
 3 files changed, 258 insertions(+)

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index a96e384..8d52666 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -583,6 +583,32 @@ static int hisilpc_bus_platform_notify(struct 
notifier_block *nb,
/* register the linux virtual IO range node to list. */
register_extio(io_node);

+   /*
+* For ACPI children, translate the bus-local I/O range to logical
+* I/O range and set it as the current resource before the children
+* are enumerated.
+*/
+   if (has_acpi_companion(dev)) {
+   struct acpi_device *root, *child;
+
+   root = to_acpi_device_node(dev->fwnode);
+   /* For hisilpc, only care about the sons of host. */
+   list_for_each_entry(child, &root->children, node) {
+   ret = acpi_set_extio_resource(child, root);
+   if (ret) {
+   dev_err(dev, "set resource failed..\n");
+   break;
+   }
+   }
+
+   if (ret) {
+   list_del(&io_node->list);
+   kfree(io_node);
+   dev_err(dev, "notify handling failed..\n");
+   return NOTIFY_DONE;
+   }
+   }
+
return NOTIFY_OK;
 }

diff --git a/include/linux/extio.h b/include/linux/extio.h
index 2ca7eab..c07607e 100644
--- a/include/linux/extio.h
+++ b/include/linux/extio.h
@@ -20,6 +20,7 @@

 #ifdef __KERNEL__

+#include 
 #include 

 struct extio_ops {
@@ -81,5 +82,8 @@ static inline struct extio_node *extio_find_node(struct 
fwnode_handle *node)
 #endif
 extern void register_extio(struct extio_node *node);

+extern int acpi_set_extio_resource(struct acpi_device *adev,
+   struct acpi_device *host);
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_EXTIO_H */
diff --git a/lib/extio.c b/lib/extio.c
index 46228de..47f5913 100644
--- a/lib/extio.c
+++ b/lib/extio.c
@@ -75,6 +75,234 @@ unsigned long extio_translate(struct fwnode_handle *node,
return port_id;
 }

+static inline bool acpi_extio_supported_resource(struct acpi_resource *res)
+{
+   switch (res->type) {
+   case ACPI_RESOURCE_TYPE_ADDRESS16:
+   case ACPI_RESOURCE_TYPE_ADDRESS32:
+   case ACPI_RESOURCE_TYPE_ADDRESS64:
+   return true;
+   }
+   return false;
+}
+
+static acpi_status acpi_count_extiores(struct acpi_resource *res,
+  void *data)
+{
+   int *res_cnt = data;
+
+   if (acpi_extio_supported_resource(res) &&
+   !acpi_dev_filter_resource_type(res, IORESOURCE_IO))
+   (*res_cnt)++;
+
+   return AE_OK;
+}
+
+static acpi_status acpi_read_one_extiores(struct acpi_resource *res,
+   void *data)
+{
+   struct acpi_resource **resource = data;
+
+   if (acpi_extio_supported_resource(res) &&
+   !acpi_dev_filter_resource_type(res, IORESOURCE_IO)) {
+   memcpy((*resource), res, sizeof(struct acpi_resource));
+   (*resource)->length = sizeof(struct acpi_resource);
+   (*resource)->type = res->type;
+   (*resource)++;
+   }
+
+   return AE_OK;
+}
+
+static acpi_status
+acpi_build_extiores_template(struct acpi_device *adev,
+   struct acpi_buffer *buffer)
+{
+   acpi_handle handle = adev->handle;
+   struct acpi_resource *resource;
+   acpi_status status;
+   int res_cnt = 0;
+
+   status = acpi_walk_resources(handle, METHOD_NAME__PRS,
+acpi_count_extiores, &res_cnt);
+   if (ACPI_FAILURE(status) || !res_cnt) {
+   dev_err(&adev->dev, "can't evaluate _CRS: %d\n", status);
+   return -EINVAL;
+   }
+
+   buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
+   buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
+   if (!buffer->pointer)
+   return -ENOMEM;
+
+   resource = (struct acpi_resource *)buffer->pointer;
+   status = acpi_walk_resources(handle, METHOD_NAME__PRS,
+acpi_read_one_extiores, &resource);
+   if (ACPI_FAI

[PATCH V5 5/5] LPC: Add the ACPI LPC support

2017-01-23 Thread zhichang.yuan
The patch update the _CRS of LPC children with the system logical I/O resource
after the translation from LPC-local I/O. Then the ACPI platform device
enumeration for LPC can apply the right I/O resource to request the system I/O
space.

Signed-off-by: zhichang.yuan 
---
 drivers/bus/hisi_lpc.c |  26 ++
 include/linux/extio.h  |   4 +
 lib/extio.c| 228 +
 3 files changed, 258 insertions(+)

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index a96e384..8d52666 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -583,6 +583,32 @@ static int hisilpc_bus_platform_notify(struct 
notifier_block *nb,
/* register the linux virtual IO range node to list. */
register_extio(io_node);
 
+   /*
+* For ACPI children, translate the bus-local I/O range to logical
+* I/O range and set it as the current resource before the children
+* are enumerated.
+*/
+   if (has_acpi_companion(dev)) {
+   struct acpi_device *root, *child;
+
+   root = to_acpi_device_node(dev->fwnode);
+   /* For hisilpc, only care about the sons of host. */
+   list_for_each_entry(child, &root->children, node) {
+   ret = acpi_set_extio_resource(child, root);
+   if (ret) {
+   dev_err(dev, "set resource failed..\n");
+   break;
+   }
+   }
+
+   if (ret) {
+   list_del(&io_node->list);
+   kfree(io_node);
+   dev_err(dev, "notify handling failed..\n");
+   return NOTIFY_DONE;
+   }
+   }
+
return NOTIFY_OK;
 }
 
diff --git a/include/linux/extio.h b/include/linux/extio.h
index 2ca7eab..c07607e 100644
--- a/include/linux/extio.h
+++ b/include/linux/extio.h
@@ -20,6 +20,7 @@
 
 #ifdef __KERNEL__
 
+#include 
 #include 
 
 struct extio_ops {
@@ -81,5 +82,8 @@ static inline struct extio_node *extio_find_node(struct 
fwnode_handle *node)
 #endif
 extern void register_extio(struct extio_node *node);
 
+extern int acpi_set_extio_resource(struct acpi_device *adev,
+   struct acpi_device *host);
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_EXTIO_H */
diff --git a/lib/extio.c b/lib/extio.c
index 46228de..47f5913 100644
--- a/lib/extio.c
+++ b/lib/extio.c
@@ -75,6 +75,234 @@ unsigned long extio_translate(struct fwnode_handle *node,
return port_id;
 }
 
+static inline bool acpi_extio_supported_resource(struct acpi_resource *res)
+{
+   switch (res->type) {
+   case ACPI_RESOURCE_TYPE_ADDRESS16:
+   case ACPI_RESOURCE_TYPE_ADDRESS32:
+   case ACPI_RESOURCE_TYPE_ADDRESS64:
+   return true;
+   }
+   return false;
+}
+
+static acpi_status acpi_count_extiores(struct acpi_resource *res,
+  void *data)
+{
+   int *res_cnt = data;
+
+   if (acpi_extio_supported_resource(res) &&
+   !acpi_dev_filter_resource_type(res, IORESOURCE_IO))
+   (*res_cnt)++;
+
+   return AE_OK;
+}
+
+static acpi_status acpi_read_one_extiores(struct acpi_resource *res,
+   void *data)
+{
+   struct acpi_resource **resource = data;
+
+   if (acpi_extio_supported_resource(res) &&
+   !acpi_dev_filter_resource_type(res, IORESOURCE_IO)) {
+   memcpy((*resource), res, sizeof(struct acpi_resource));
+   (*resource)->length = sizeof(struct acpi_resource);
+   (*resource)->type = res->type;
+   (*resource)++;
+   }
+
+   return AE_OK;
+}
+
+static acpi_status
+acpi_build_extiores_template(struct acpi_device *adev,
+   struct acpi_buffer *buffer)
+{
+   acpi_handle handle = adev->handle;
+   struct acpi_resource *resource;
+   acpi_status status;
+   int res_cnt = 0;
+
+   status = acpi_walk_resources(handle, METHOD_NAME__PRS,
+acpi_count_extiores, &res_cnt);
+   if (ACPI_FAILURE(status) || !res_cnt) {
+   dev_err(&adev->dev, "can't evaluate _CRS: %d\n", status);
+   return -EINVAL;
+   }
+
+   buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
+   buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
+   if (!buffer->pointer)
+   return -ENOMEM;
+
+   resource = (struct acpi_resource *)buffer->pointer;
+   status = acpi_walk_resources(handle, METHOD_NAME__PRS,
+acpi_read_one_extiores, &resource);
+   if (ACPI_FAILURE(status)) {
+   kfree(buffer->pointer);
+   dev_err(&adev->dev, "can't evaluate _PRS: %d\n", status);
+   return -EINVAL;
+   }
+
+   resource->type = ACPI_RESOURCE_TYPE_END_TAG;
+   resource->lengt