linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V7 0/7] LPC: legacy ISA I/O support
@ 2017-03-13  2:42 zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 1/7] LIBIO: Introduce a generic PIO mapping method zhichang.yuan
                   ` (7 more replies)
  0 siblings, 8 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

This patchset supports the IPMI-bt device attached to the Low-Pin-Count
interface implemented on Hisilicon Hip06/Hip07 SoC.
	                -----------
			| LPC host|
	                |         |
	                -----------
	                     |
 	        _____________V_______________LPC
                  |			  |
                  V	                  V
			             ------------
			             |  BT(ipmi)|
			             ------------

When master accesses those peripherals beneath the Hip06/Hip07 LPC, a specific
LPC driver is needed to make LPC host generate the standard LPC I/O cycles with
the target peripherals'I/O port addresses. But on curent arm64 world, there is
no real I/O accesses. All the I/O operations through in/out pair are based on
MMIO which is not satisfied the I/O mechanism on Hip06/Hip07 LPC.
To solve this issue and keep the relevant existing peripherals' driver
untouched, this patchset implements:
  - introduces a generic I/O space management framwork, LIBIO, to support I/O
    operations of both MMIO buses and the host controllers which access their
    peripherals with host local I/O addresses;
  - redefines the in/out accessors to provide unified interfaces for MMIO and
    legacy I/O. Based on the LIBIO, the calling of in/out() from upper-layer
    drivers, such as ipmi-si, will be redirected to the corresponding
    device-specific I/O hooks to perfrom the I/O accesses.
Based on this patch-set, all the I/O accesses to Hip06/Hip07 LPC peripherals
can be supported without any changes on the existing ipmi-si driver.

Changes from V6:
  - According to the comments from Bjorn and Alex, merge PCI IO and indirect-IO
    into a generic I/O space management, LIBIO;
  - Adopted the '_DEP' to replace the platform bus notifier. In this way, we
    can ensure the LPC peripherals' I/O resources had been translated to
    logical IO before the LPC peripheral enumeration;
  - Replaced the rwlock with rcu list based on Alex's suggestion;
  - Applied relaxed write/read to LPC driver;
  - Some bugs fixing and some optimazations based on the comments of V6;

Changes from V5:
  - Made the extio driver more generic and locate in lib/;
  - Supported multiple indirect-IO bus instances;
  - Extended the pci_register_io_range() to support indirect-IO, then dropped
  the I/O reservation used in previous patchset;
  - Reimplemented the ACPI LPC support;
  - Fixed some bugs, including the compile error on other archs, the module
  building failure found by Ming Lei, etc;

Changes from V4:
  - Some revises based on the comments from Bjorn, Rob on V4;
  - Fixed the compile error on some platforms, such as openrisc;

Changes from V3:
  - UART support deferred to a separate patchset; This patchset only support
  ipmi device under LPC;
  - LPC bus I/O range is fixed to 0 ~ (PCIBIOS_MIN_IO - 1), which is separeted
  from PCI/PCIE PIO space;
  - Based on Arnd's remarks, removed the ranges property from Hip06 lpc dts and
  added a new fixup function, of_isa_indirect_io(), to get the I/O address
  directly from LPC dts configurations;
  - Support in(w,l)/out(w,l) for Hip06 lpc I/O;
  - Decouple the header file dependency on the gerenic io.h by defining in/out
  as normal functions in c file;
  - removed unused macro definitions in the LPC driver;

Changes from V2:
  - Support the PIO retrieval from the linux PIO generated by
  pci_address_to_pio. This method replace the 4K PIO reservation in V2;
  - Support the flat-tree earlycon;
  - Some revises based on Arnd's remarks;
  - Make sure the linux PIO range allocated to Hip06 LPC peripherals starts
  from non-ZERO;

Changes from V1:
  - Support the ACPI LPC device;
  - Optimize the dts LPC driver in ISA compatible mode;
  - Reserve the IO range below 4K in avoid the possible conflict with PCI host
  IO ranges;
  - Support the LPC uart and relevant earlycon;

v6 thread here: https://lkml.org/lkml/2017/1/24/25
v5 thread here: https://lkml.org/lkml/2016/11/7/955
v4 thread here: https://lkml.org/lkml/2016/10/20/149
v3 thread here: https://lkml.org/lkml/2016/9/14/326
v2 thread here: https://lkml.org/lkml/2016/9/7/356
v1 thread here: https://lkml.org/lkml/2015/12/29/154


Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
zhichang.yuan (7):
  LIBIO: Introduce a generic PIO mapping method
  PCI: Apply the new generic I/O management on PCI IO hosts
  OF: Add missing I/O range exception for indirect-IO  devices
  LPC: Support the device-tree LPC host on Hip06/Hip07
  ACPI: Delay the enumeration on the devices whose dependency has not
    met
  LIBIO: Support the dynamically logical PIO registration of ACPI host
    I/O
  LPC: Add the ACPI LPC support

 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  33 ++
 MAINTAINERS                                        |   8 +
 arch/arm64/boot/dts/hisilicon/hip06-d03.dts        |   4 +
 arch/arm64/boot/dts/hisilicon/hip06.dtsi           |  14 +
 arch/arm64/boot/dts/hisilicon/hip07-d05.dts        |   4 +
 arch/arm64/boot/dts/hisilicon/hip07.dtsi           |  14 +
 drivers/acpi/battery.c                             |   3 -
 drivers/acpi/pci_root.c                            |   8 +-
 drivers/acpi/scan.c                                |   3 +
 drivers/bus/Kconfig                                |   8 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 608 +++++++++++++++++++++
 drivers/of/address.c                               |  94 +++-
 drivers/pci/pci.c                                  |  96 +---
 include/asm-generic/io.h                           |  50 ++
 include/linux/io.h                                 |   1 +
 include/linux/libio.h                              |  98 ++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  14 +
 lib/Makefile                                       |   2 +
 lib/libio.c                                        | 548 +++++++++++++++++++
 21 files changed, 1514 insertions(+), 100 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/libio.h
 create mode 100644 lib/libio.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH V7 1/7] LIBIO: Introduce a generic PIO mapping method
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 2/7] PCI: Apply the new generic I/O management on PCI IO hosts zhichang.yuan
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

In commit 41f8bba7f55(of/pci: Add pci_register_io_range() and
pci_pio_to_address()), a new I/O space management was supported. With that
driver, the I/O ranges configured for PCI/PCIE hosts on some architectures can
be mapped to logical PIO, converted easily between CPU address and the
corresponding logicial PIO. Based on this, PCI I/O devices can be accessed in a
memory read/write way through the unified in/out accessors.

But on some archs/platforms, there are bus hosts which access I/O peripherals
with host-local I/O port addresses rather than memory addresses after
memory-mapped.
To support those devices, a more generic I/O mapping method is introduced here.
Through this patch, both the CPU addresses and the host-local port can be
mapped into logical PIO, then all the I/O accesses to either PCI MMIO devices or
host-local I/O peripherals can be unified into the existing I/O accessors
defined asm-generic/io.h and be redirected to the right device-specific hooks
based on the input logical PIO.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 include/asm-generic/io.h |  50 ++++++++
 include/linux/io.h       |   1 +
 include/linux/libio.h    |  94 ++++++++++++++
 lib/Kconfig              |  14 ++
 lib/Makefile             |   2 +
 lib/libio.c              | 324 +++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 485 insertions(+)
 create mode 100644 include/linux/libio.h
 create mode 100644 lib/libio.c

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ef015e..91a7ed4 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -21,6 +21,8 @@
 
 #include <asm-generic/pci_iomap.h>
 
+#include <linux/libio.h>
+
 #ifndef mmiowb
 #define mmiowb() do {} while (0)
 #endif
@@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
  */
 
 #ifndef inb
+#ifdef CONFIG_LIBIO
+#define inb libio_inb
+#else
 #define inb inb
 static inline u8 inb(unsigned long addr)
 {
 	return readb(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef inw
+#ifdef CONFIG_LIBIO
+#define inw libio_inw
+#else
 #define inw inw
 static inline u16 inw(unsigned long addr)
 {
 	return readw(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef inl
+#ifdef CONFIG_LIBIO
+#define inl libio_inl
+#else
 #define inl inl
 static inline u32 inl(unsigned long addr)
 {
 	return readl(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef outb
+#ifdef CONFIG_LIBIO
+#define outb libio_outb
+#else
 #define outb outb
 static inline void outb(u8 value, unsigned long addr)
 {
 	writeb(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef outw
+#ifdef CONFIG_LIBIO
+#define outw libio_outw
+#else
 #define outw outw
 static inline void outw(u16 value, unsigned long addr)
 {
 	writew(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef outl
+#ifdef CONFIG_LIBIO
+#define outl libio_outl
+#else
 #define outl outl
 static inline void outl(u32 value, unsigned long addr)
 {
 	writel(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
  */
 
 #ifndef insb
+#ifdef CONFIG_LIBIO
+#define insb libio_insb
+#else
 #define insb insb
 static inline void insb(unsigned long addr, void *buffer, unsigned int count)
 {
 	readsb(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef insw
+#ifdef CONFIG_LIBIO
+#define insw libio_insw
+#else
 #define insw insw
 static inline void insw(unsigned long addr, void *buffer, unsigned int count)
 {
 	readsw(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef insl
+#ifdef CONFIG_LIBIO
+#define insl libio_insl
+#else
 #define insl insl
 static inline void insl(unsigned long addr, void *buffer, unsigned int count)
 {
 	readsl(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef outsb
+#ifdef CONFIG_LIBIO
+#define outsb libio_outsb
+#else
 #define outsb outsb
 static inline void outsb(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
 	writesb(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef outsw
+#ifdef CONFIG_LIBIO
+#define outsw libio_outsw
+#else
 #define outsw outsw
 static inline void outsw(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
 	writesw(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef outsl
+#ifdef CONFIG_LIBIO
+#define outsl libio_outsl
+#else
 #define outsl outsl
 static inline void outsl(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
 	writesl(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_LIBIO */
 #endif
 
 #ifndef insb_p
diff --git a/include/linux/io.h b/include/linux/io.h
index 82ef36e..51ec1aa 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <asm/io.h>
 #include <asm/page.h>
+#include <linux/libio.h>
 
 struct device;
 struct resource;
diff --git a/include/linux/libio.h b/include/linux/libio.h
new file mode 100644
index 0000000..91038aa
--- /dev/null
+++ b/include/linux/libio.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_LIBIO_H
+#define __LINUX_LIBIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/fwnode.h>
+
+/* This is compatible to PCI MMIO. */
+#define IO_CPU_MMIO		0x01
+/* All hosts where there are no CPU addr */
+#define IO_HOST_INDIRECT	0x02
+
+struct libio_range {
+	struct list_head list;
+	struct fwnode_handle *node;
+	resource_size_t size; /* range size populated */
+	resource_size_t io_start;	/* logical pio start. inclusive */
+	resource_size_t hw_start;
+	unsigned long flags;
+	void *devpara;	/* private parameter of the host device */
+	struct libio_ops *ops;	/* ops operating on this node */
+};
+
+struct libio_ops {
+	u32 (*pfin)(void *devobj, unsigned long ptaddr,	size_t dlen);
+	void (*pfout)(void *devobj, unsigned long ptaddr, u32 outval,
+			size_t dlen);
+	u32 (*pfins)(void *devobj, unsigned long ptaddr, void *inbuf,
+			size_t dlen, unsigned int count);
+	void (*pfouts)(void *devobj, unsigned long ptaddr,
+			const void *outbuf, size_t dlen, unsigned int count);
+};
+
+extern u8 libio_inb(unsigned long addr);
+extern void libio_outb(u8 value, unsigned long addr);
+extern void libio_outw(u16 value, unsigned long addr);
+extern void libio_outl(u32 value, unsigned long addr);
+extern u16 libio_inw(unsigned long addr);
+extern u32 libio_inl(unsigned long addr);
+extern void libio_outb(u8 value, unsigned long addr);
+extern void libio_outw(u16 value, unsigned long addr);
+extern void libio_outl(u32 value, unsigned long addr);
+extern void libio_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void libio_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void libio_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void libio_outsb(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void libio_outsw(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void libio_outsl(unsigned long addr, const void *buffer,
+			unsigned int count);
+#ifdef CONFIG_LIBIO
+extern struct libio_range
+*find_io_range_from_fwnode(struct fwnode_handle *fwnode);
+extern unsigned long libio_translate_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr);
+#else
+static inline struct libio_range
+*find_io_range_from_fwnode(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
+static inline unsigned long libio_translate_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr)
+{
+	return -1;
+}
+#endif
+
+extern struct libio_range *register_libio_range(struct libio_range *newrange);
+extern resource_size_t libio_to_hwaddr(unsigned long pio);
+
+extern unsigned long libio_translate_cpuaddr(resource_size_t hw_addr);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LIBIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a..ba9787d5 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,20 @@ config ARCH_USE_CMPXCHG_LOCKREF
 config ARCH_HAS_FAST_MULTIPLIER
 	bool
 
+config LIBIO
+	bool "Generic logical IO management"
+	def_bool y if PCI && (ARM || ARC || UNICORE32 || SPARC || S390 || CRIS || BLACKFIN || XTENSA || ARM64)
+	help
+	  For some architectures, there are no IO space. To support the
+	  accesses to legacy I/O devices on those architectures, kernel
+	  implemented the memory mapped I/O mechanism based on bridge bus
+	  supports. But for some buses which do not support MMIO, the
+	  peripherals there should be accessed with device-specific way.
+	  To abstract those different I/O accesses into unified I/O accessors,
+	  this option provide a generic I/O space management way after mapping
+	  the device I/O to system logical/fake I/O and help to hide all the
+	  hardware detail.
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 320ac46a..9c4cd24 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -77,6 +77,8 @@ obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
 
+obj-$(CONFIG_LIBIO) += libio.o
+
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/libio.c b/lib/libio.c
new file mode 100644
index 0000000..e42f50b
--- /dev/null
+++ b/lib/libio.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/rculist.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+/* A list of all the IO hosts registered. ONLY THE HOST nodes. */
+static LIST_HEAD(io_range_list);
+static DEFINE_MUTEX(io_range_mutex);
+
+/*
+ * allocate a free range for this registration.
+ *
+ * @new_range: point to the node awaiting this registration.
+ *		part of the fields are as input parameters. This node
+ *		is allocated and initialized by caller;
+ * @prev: points to the last node before the return;
+ *
+ * return 0 for success, other are fail.
+ */
+static int libio_alloc_range(struct libio_range *new_range,
+		struct list_head **prev)
+{
+	struct libio_range *entry;
+	unsigned long align = 1;
+	unsigned long tmp_start;
+	unsigned long idle_start, idle_end;
+
+	if (new_range->flags & IO_CPU_MMIO)
+		align = PAGE_SIZE;
+	idle_start = 0;
+	*prev = &io_range_list;
+	list_for_each_entry_rcu(entry, &io_range_list, list) {
+		if (idle_start > entry->io_start) {
+			WARN(1, "skip an invalid io range during traversal!\n");
+			goto nextentry;
+		}
+		/* set the end edge. */
+		if (idle_start == entry->io_start) {
+			struct libio_range *next;
+
+			idle_start = entry->io_start + entry->size;
+			next = list_next_or_null_rcu(&io_range_list,
+				&entry->list, struct libio_range, list);
+			if (next) {
+				entry = next;
+			} else {
+				*prev = &entry->list;
+				break;
+			}
+		}
+		idle_end = entry->io_start - 1;
+
+		/* contiguous range... */
+		if (idle_start > idle_end)
+			goto nextentry;
+
+		tmp_start = idle_start;
+		idle_start = ALIGN(idle_start, align);
+		if (idle_start >= tmp_start &&
+			idle_start + new_range->size <= idle_end) {
+			new_range->io_start = idle_start;
+			*prev = &entry->list;
+			return 0;
+		}
+
+nextentry:
+		idle_start = entry->io_start + entry->size;
+		*prev = &entry->list;
+	}
+	/* check the last free gap... */
+	idle_end = IO_SPACE_LIMIT;
+
+	tmp_start = idle_start;
+	idle_start = ALIGN(idle_start, align);
+	if (idle_start >= tmp_start &&
+		idle_start + new_range->size <= idle_end) {
+		new_range->io_start = idle_start;
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*
+ * traverse the io_range_list to find the registered node whose device node
+ * and/or physical IO address match to.
+ */
+struct libio_range *find_io_range_from_fwnode(struct fwnode_handle *fwnode)
+{
+	struct libio_range *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->node == fwnode)
+			return range;
+	}
+	return NULL;
+}
+
+/*
+ * Search a io_range registered which match the fwnode and addr.
+ *
+ * @fwnode: the host fwnode which must be valid;
+ * @start: the start hardware address of this search;
+ * @end: the end hardware address of this search. can be equal to @start;
+ *
+ * return NULL when there is no matched node; IS_ERR() means ERROR;
+ * valid virtual address represent a matched node was found.
+ */
+static struct libio_range *
+libio_find_range_byaddr(struct fwnode_handle *fwnode,
+			resource_size_t start, resource_size_t end)
+{
+	struct libio_range *entry;
+
+	list_for_each_entry_rcu(entry, &io_range_list, list) {
+		if (entry->node != fwnode)
+			continue;
+		/* without any overlap with current range */
+		if (start >= entry->hw_start + entry->size ||
+			end < entry->hw_start)
+			continue;
+		/* overlap is not supported now. */
+		if (start < entry->hw_start ||
+			end >= entry->hw_start + entry->size)
+			return ERR_PTR(-EBUSY);
+		/* had been registered. */
+		return entry;
+	}
+
+	return NULL;
+}
+
+/*
+ * register a io range node in the io range list.
+ *
+ * @newrange: pointer to the io range to be registered.
+ *
+ * return 'newrange' when success, ERR_VALUE() is for failures.
+ * specially, return a valid pointer which is not equal to 'newrange' when
+ * the io range had been registered before.
+ */
+struct libio_range *register_libio_range(struct libio_range *newrange)
+{
+	int err;
+	struct libio_range *range;
+	struct list_head *prev;
+
+	if (!newrange || !newrange->node || !newrange->size)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&io_range_mutex);
+	range = libio_find_range_byaddr(newrange->node, newrange->hw_start,
+			newrange->hw_start + newrange->size - 1);
+	if (range) {
+		if (!IS_ERR(range))
+			pr_info("the request IO range had been registered!\n");
+		else
+			pr_err("registering IO[%pa - sz%pa) got failed!\n",
+				&newrange->hw_start, &newrange->size);
+		return range;
+	}
+
+	err = libio_alloc_range(newrange, &prev);
+	if (!err)
+		/* the bus IO range list is ordered by pio. */
+		list_add_rcu(&newrange->list, prev);
+	else
+		pr_err("can't find free %pa logical IO range!\n",
+			&newrange->size);
+
+	mutex_unlock(&io_range_mutex);
+	return err ? ERR_PTR(err) : newrange;
+}
+
+/*
+ * Translate the input logical pio to the corresponding hardware address.
+ * The input pio should be unique in the whole logical PIO space.
+ */
+resource_size_t libio_to_hwaddr(unsigned long pio)
+{
+	struct libio_range *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (pio < range->io_start)
+			break;
+
+		if (pio < range->io_start + range->size)
+			return pio - range->io_start + range->hw_start;
+	}
+
+	return -1;
+}
+
+/*
+ * This function is generic for translating a hardware address to logical PIO.
+ * @hw_addr: the hardware address of host, can be CPU address or host-local
+ *		address;
+ */
+unsigned long
+libio_translate_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr)
+{
+	struct libio_range *range;
+
+	range = libio_find_range_byaddr(fwnode, addr, addr);
+	if (!range)
+		return -1;
+
+	return addr - range->hw_start + range->io_start;
+}
+
+unsigned long
+libio_translate_cpuaddr(resource_size_t addr)
+{
+	struct libio_range *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!(range->flags & IO_CPU_MMIO))
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start + range->io_start;
+	}
+	return -1;
+}
+
+#ifdef PCI_IOBASE
+static struct libio_range *find_io_range(unsigned long pio)
+{
+	struct libio_range *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->io_start > pio)
+			return NULL;
+		if (pio < range->io_start + range->size)
+			return range;
+	}
+	return NULL;
+}
+
+#define BUILD_IO(bw, type)						\
+type libio_in##bw(unsigned long addr)					\
+{									\
+	struct libio_range *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		return entry->ops->pfin(entry->devpara,			\
+					addr, sizeof(type));		\
+	return read##bw(PCI_IOBASE + addr);				\
+}									\
+									\
+void libio_out##bw(type value, unsigned long addr)			\
+{									\
+	struct libio_range *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		entry->ops->pfout(entry->devpara,			\
+					addr, value, sizeof(type));	\
+	else								\
+		write##bw(value, PCI_IOBASE + addr);			\
+}									\
+									\
+void libio_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	struct libio_range *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		entry->ops->pfins(entry->devpara,			\
+				addr, buffer, sizeof(type), count);	\
+	else								\
+		reads##bw(PCI_IOBASE + addr, buffer, count);		\
+}									\
+									\
+void libio_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	struct libio_range *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		entry->ops->pfouts(entry->devpara,			\
+				addr, buffer, sizeof(type), count);	\
+	else								\
+		writes##bw(PCI_IOBASE + addr, buffer, count);	\
+}
+
+BUILD_IO(b, u8)
+
+EXPORT_SYMBOL(libio_inb);
+EXPORT_SYMBOL(libio_outb);
+EXPORT_SYMBOL(libio_insb);
+EXPORT_SYMBOL(libio_outsb);
+
+BUILD_IO(w, u16)
+
+EXPORT_SYMBOL(libio_inw);
+EXPORT_SYMBOL(libio_outw);
+EXPORT_SYMBOL(libio_insw);
+EXPORT_SYMBOL(libio_outsw);
+
+BUILD_IO(l, u32)
+
+EXPORT_SYMBOL(libio_inl);
+EXPORT_SYMBOL(libio_outl);
+EXPORT_SYMBOL(libio_insl);
+EXPORT_SYMBOL(libio_outsl);
+#endif /* PCI_IOBASE */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH V7 2/7] PCI: Apply the new generic I/O management on PCI IO hosts
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 1/7] LIBIO: Introduce a generic PIO mapping method zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-27 19:46   ` dann frazier
  2017-03-13  2:42 ` [PATCH V7 3/7] OF: Add missing I/O range exception for indirect-IO devices zhichang.yuan
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

After introducing the new generic I/O space management(LIBIO), the original PCI
MMIO relevant helpers need to be updated based on the new interfaces defined in
LIBIO.
This patch adapts the corresponding code to match the changes introduced by
LIBIO.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>        #earlier draft
Acked-by: Bjorn Helgaas <bhelgaas@google.com>       #drivers/pci parts
---
 drivers/acpi/pci_root.c |  8 +++--
 drivers/of/address.c    |  4 ++-
 drivers/pci/pci.c       | 96 +++++++++++--------------------------------------
 include/linux/pci.h     |  3 +-
 4 files changed, 30 insertions(+), 81 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 919be0a..4d8cc24 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -730,7 +730,8 @@ static void acpi_pci_root_validate_resources(struct device *dev,
 	}
 }
 
-static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
+static void acpi_pci_root_remap_iospace(struct fwnode_handle *fwnode,
+			struct resource_entry *entry)
 {
 #ifdef PCI_IOBASE
 	struct resource *res = entry->res;
@@ -739,7 +740,7 @@ static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
 	resource_size_t length = resource_size(res);
 	unsigned long port;
 
-	if (pci_register_io_range(cpu_addr, length))
+	if (pci_register_io_range(fwnode, cpu_addr, length))
 		goto err;
 
 	port = pci_address_to_pio(cpu_addr);
@@ -781,7 +782,8 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 	else {
 		resource_list_for_each_entry_safe(entry, tmp, list) {
 			if (entry->res->flags & IORESOURCE_IO)
-				acpi_pci_root_remap_iospace(entry);
+				acpi_pci_root_remap_iospace(&device->fwnode,
+						entry);
 
 			if (entry->res->flags & IORESOURCE_DISABLED)
 				resource_list_destroy_entry(entry);
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 02b2903..fb5d16a 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,6 +2,7 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
@@ -323,7 +324,8 @@ int of_pci_range_to_resource(struct of_pci_range *range,
 
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long port;
-		err = pci_register_io_range(range->cpu_addr, range->size);
+		err = pci_register_io_range(&np->fwnode, range->cpu_addr,
+				range->size);
 		if (err)
 			goto invalid_range;
 		port = pci_address_to_pio(range->cpu_addr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 7904d02..079319f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3238,65 +3238,37 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
 }
 EXPORT_SYMBOL(pci_request_regions_exclusive);
 
-#ifdef PCI_IOBASE
-struct io_range {
-	struct list_head list;
-	phys_addr_t start;
-	resource_size_t size;
-};
-
-static LIST_HEAD(io_range_list);
-static DEFINE_SPINLOCK(io_range_lock);
-#endif
-
 /*
  * Record the PCI IO range (expressed as CPU physical address + size).
  * Return a negative value if an error has occured, zero otherwise
  */
-int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
+int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
+			resource_size_t	size)
 {
 	int err = 0;
 
 #ifdef PCI_IOBASE
-	struct io_range *range;
-	resource_size_t allocated_size = 0;
-
-	/* check if the range hasn't been previously recorded */
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (addr >= range->start && addr + size <= range->start + size) {
-			/* range already registered, bail out */
-			goto end_register;
-		}
-		allocated_size += range->size;
-	}
-
-	/* range not registed yet, check for available space */
-	if (allocated_size + size - 1 > IO_SPACE_LIMIT) {
-		/* if it's too big check if 64K space can be reserved */
-		if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) {
-			err = -E2BIG;
-			goto end_register;
-		}
+	struct libio_range *range, *tmprange;
 
-		size = SZ_64K;
-		pr_warn("Requested IO range too big, new size set to 64K\n");
-	}
+	if (!size || addr + size < addr)
+		return -EINVAL;
 
-	/* add the range to the list */
-	range = kzalloc(sizeof(*range), GFP_ATOMIC);
-	if (!range) {
-		err = -ENOMEM;
-		goto end_register;
-	}
+	WARN_ON(!PAGE_ALIGNED(addr) || !PAGE_ALIGNED(size));
 
-	range->start = addr;
+	range = kzalloc(sizeof(*range), GFP_KERNEL);
+	if (!range)
+		return -ENOMEM;
+	range->node = fwnode;
+	range->flags = IO_CPU_MMIO;
 	range->size = size;
+	range->hw_start = addr;
 
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	tmprange = register_libio_range(range);
+	if (tmprange != range) {
+		kfree(range);
+		if (!IS_ERR(tmprange))
+			err = 0;
+	}
 #endif
 
 	return err;
@@ -3307,21 +3279,10 @@ phys_addr_t pci_pio_to_address(unsigned long pio)
 	phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
 
 #ifdef PCI_IOBASE
-	struct io_range *range;
-	resource_size_t allocated_size = 0;
-
 	if (pio > IO_SPACE_LIMIT)
 		return address;
 
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (pio >= allocated_size && pio < allocated_size + range->size) {
-			address = range->start + pio - allocated_size;
-			break;
-		}
-		allocated_size += range->size;
-	}
-	spin_unlock(&io_range_lock);
+	address = libio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3330,25 +3291,8 @@ phys_addr_t pci_pio_to_address(unsigned long pio)
 unsigned long __weak pci_address_to_pio(phys_addr_t address)
 {
 #ifdef PCI_IOBASE
-	struct io_range *res;
-	resource_size_t offset = 0;
-	unsigned long addr = -1;
-
-	spin_lock(&io_range_lock);
-	list_for_each_entry(res, &io_range_list, list) {
-		if (address >= res->start && address < res->start + res->size) {
-			addr = address - res->start + offset;
-			break;
-		}
-		offset += res->size;
-	}
-	spin_unlock(&io_range_lock);
-
-	return addr;
+	return libio_translate_cpuaddr(address);
 #else
-	if (address > IO_SPACE_LIMIT)
-		return (unsigned long)-1;
-
 	return (unsigned long) address;
 #endif
 }
diff --git a/include/linux/pci.h b/include/linux/pci.h
index eb3da1a..6401327 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1194,7 +1194,8 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
 			void *alignf_data);
 
 
-int pci_register_io_range(phys_addr_t addr, resource_size_t size);
+int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
+			resource_size_t size);
 unsigned long pci_address_to_pio(phys_addr_t addr);
 phys_addr_t pci_pio_to_address(unsigned long pio);
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH V7 3/7] OF: Add missing I/O range exception for indirect-IO   devices
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 1/7] LIBIO: Introduce a generic PIO mapping method zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 2/7] PCI: Apply the new generic I/O management on PCI IO hosts zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 4/7] LPC: Support the device-tree LPC host on Hip06/Hip07 zhichang.yuan
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

There are some special ISA/LPC devices that work on a specific I/O range where
it is not correct to specify a 'ranges' property in DTS parent node as cpu
addresses translated from DTS node are only for memory space on some
architectures, such as Arm64. Without the parent 'ranges' property, current
of_translate_address() return an error.
Here we add special handlings for this case.
During the OF address translation, some checkings will be perfromed to
identify whether the device node is registered as indirect-IO. If yes, the I/O
translation will be done in a different way from that one of PCI MMIO.
In this way, the I/O 'reg' property of the special ISA/LPC devices will be
parsed correctly.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>    #earlier draft
Acked-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c | 90 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 74 insertions(+), 16 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index fb5d16a..676e474 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -551,9 +551,14 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
  * that translation is impossible (that is we are not dealing with a value
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
+ *
+ * Whenever the translation fails, the *host pointer will be set to the
+ * device that had registered logical PIO mapping, and the return code is relative to
+ * that node.
  */
 static u64 __of_translate_address(struct device_node *dev,
-				  const __be32 *in_addr, const char *rprop)
+				  const __be32 *in_addr, const char *rprop,
+				  struct device_node **host)
 {
 	struct device_node *parent = NULL;
 	struct of_bus *bus, *pbus;
@@ -566,6 +571,7 @@ static u64 __of_translate_address(struct device_node *dev,
 	/* Increase refcount at current level */
 	of_node_get(dev);
 
+	*host = NULL;
 	/* Get parent & match bus type */
 	parent = of_get_parent(dev);
 	if (parent == NULL)
@@ -586,6 +592,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct libio_range *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -598,6 +606,19 @@ static u64 __of_translate_address(struct device_node *dev,
 			break;
 		}
 
+		/*
+		 * For indirectIO device which has no ranges property, get
+		 * the address from reg directly.
+		 */
+		iorange = find_io_range_from_fwnode(&dev->fwnode);
+		if (iorange && !(iorange->flags & IO_CPU_MMIO)) {
+			result = of_read_number(addr + 1, na - 1);
+			pr_debug("indirectIO matched(%s) 0x%llx\n",
+					of_node_full_name(dev), result);
+			*host = of_node_get(dev);
+			break;
+		}
+
 		/* Get new parent bus and counts */
 		pbus = of_match_bus(parent);
 		pbus->count_cells(dev, &pna, &pns);
@@ -630,13 +651,32 @@ static u64 __of_translate_address(struct device_node *dev,
 
 u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret =  __of_translate_address(dev, in_addr, "ranges", &host);
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_address);
 
 u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "dma-ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "dma-ranges", &host);
+
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_dma_address);
 
@@ -678,29 +718,47 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
 }
 EXPORT_SYMBOL(of_get_address);
 
+static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr)
+{
+	u64 taddr;
+	unsigned long port;
+	struct device_node *host;
+
+	taddr = __of_translate_address(dev, in_addr, "ranges", &host);
+	if (host) {
+		/* host specific port access */
+		port = libio_translate_hwaddr(&host->fwnode, taddr);
+		of_node_put(host);
+	} else {
+		/* memory mapped I/O range */
+		port = pci_address_to_pio(taddr);
+	}
+
+	if (port == (unsigned long)-1)
+		return OF_BAD_ADDR;
+
+	return port;
+}
+
 static int __of_address_to_resource(struct device_node *dev,
 		const __be32 *addrp, u64 size, unsigned int flags,
 		const char *name, struct resource *r)
 {
 	u64 taddr;
 
-	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+	if (flags & IORESOURCE_MEM)
+		taddr = of_translate_address(dev, addrp);
+	else if (flags & IORESOURCE_IO)
+		taddr = of_translate_ioport(dev, addrp);
+	else
 		return -EINVAL;
-	taddr = of_translate_address(dev, addrp);
+
 	if (taddr == OF_BAD_ADDR)
 		return -EINVAL;
 	memset(r, 0, sizeof(struct resource));
-	if (flags & IORESOURCE_IO) {
-		unsigned long port;
-		port = pci_address_to_pio(taddr);
-		if (port == (unsigned long)-1)
-			return -EINVAL;
-		r->start = port;
-		r->end = port + size - 1;
-	} else {
-		r->start = taddr;
-		r->end = taddr + size - 1;
-	}
+
+	r->start = taddr;
+	r->end = taddr + size - 1;
 	r->flags = flags;
 	r->name = name ? name : dev->full_name;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH V7 4/7] LPC: Support the device-tree LPC host on Hip06/Hip07
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
                   ` (2 preceding siblings ...)
  2017-03-13  2:42 ` [PATCH V7 3/7] OF: Add missing I/O range exception for indirect-IO devices zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-13  2:42 ` [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met zhichang.yuan
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

The low-pin-count(LPC) interface of Hip06/Hip07 accesses the peripherals in
I/O port addresses. This patch implements the LPC host controller driver which
perform the I/O operations on the underlying hardware.
We don't want to touch those existing peripherals' driver, such as ipmi-bt. So
this driver applies the indirect-IO introduced in the previous patch after
registering an indirect-IO node to the indirect-IO devices list which will be
searched in the I/O accessors.
As the I/O translations for LPC children depend on the host I/O registration,
we should ensure the host I/O registration is finished before all the LPC
children scanning. That is why an arch_init() hook was added in this patch.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Rob Herring <robh@kernel.org> #dts part
---
 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  33 ++
 MAINTAINERS                                        |   8 +
 arch/arm64/boot/dts/hisilicon/hip06-d03.dts        |   4 +
 arch/arm64/boot/dts/hisilicon/hip06.dtsi           |  14 +
 arch/arm64/boot/dts/hisilicon/hip07-d05.dts        |   4 +
 arch/arm64/boot/dts/hisilicon/hip07.dtsi           |  14 +
 drivers/bus/Kconfig                                |   8 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 569 +++++++++++++++++++++
 9 files changed, 655 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/bus/hisi_lpc.c

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
new file mode 100644
index 0000000..213181f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
@@ -0,0 +1,33 @@
+Hisilicon Hip06 low-pin-count device
+  Hisilicon Hip06 SoCs implement a Low Pin Count (LPC) controller, which
+  provides I/O access to some legacy ISA devices.
+  Hip06 is based on arm64 architecture where there is no I/O space. So, the
+  I/O ports here are not cpu addresses, and there is no 'ranges' property in
+  LPC device node.
+
+Required properties:
+- compatible:  value should be as follows:
+	(a) "hisilicon,hip06-lpc"
+	(b) "hisilicon,hip07-lpc"
+- #address-cells: must be 2 which stick to the ISA/EISA binding doc.
+- #size-cells: must be 1 which stick to the ISA/EISA binding doc.
+- reg: base memory range where the LPC register set is mapped.
+
+Note:
+  The node name before '@' must be "isa" to represent the binding stick to the
+  ISA/EISA binding specification.
+
+Example:
+
+isa@a01b0000 {
+	compatible = "hisilicon,hip06-lpc";
+	#address-cells = <2>;
+	#size-cells = <1>;
+	reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+	ipmi0: bt@e4 {
+		compatible = "ipmi-bt";
+		device_type = "ipmi";
+		reg = <0x01 0xe4 0x04>;
+	};
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index c265a5f..b6b86f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5940,6 +5940,14 @@ F:	include/uapi/linux/if_hippi.h
 F:	net/802/hippi.c
 F:	drivers/net/hippi/
 
+HISILICON LPC BUS DRIVER
+M:	Zhichang Yuan <yuanzhichang@hisilicon.com>
+L:	linux-arm-kernel@lists.infradead.org
+W:	http://www.hisilicon.com
+S:	Maintained
+F:	drivers/bus/hisi_lpc.c
+F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
+
 HISILICON NETWORK SUBSYSTEM DRIVER
 M:	Yisen Zhuang <yisen.zhuang@huawei.com>
 M:	Salil Mehta <salil.mehta@huawei.com>
diff --git a/arch/arm64/boot/dts/hisilicon/hip06-d03.dts b/arch/arm64/boot/dts/hisilicon/hip06-d03.dts
index 7c4114a..75b2b5c 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06-d03.dts
+++ b/arch/arm64/boot/dts/hisilicon/hip06-d03.dts
@@ -52,3 +52,7 @@
 &usb_ehci {
 	status = "ok";
 };
+
+&ipmi0 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
index a049b64..c450f8d 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
@@ -318,6 +318,20 @@
 		#size-cells = <2>;
 		ranges;
 
+		isa@a01b0000 {
+			compatible = "hisilicon,hip06-lpc";
+			#size-cells = <1>;
+			#address-cells = <2>;
+			reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+			ipmi0: bt@e4 {
+				compatible = "ipmi-bt";
+				device_type = "ipmi";
+				reg = <0x01 0xe4 0x04>;
+				status = "disabled";
+			};
+		};
+
 		refclk: refclk {
 			compatible = "fixed-clock";
 			clock-frequency = <50000000>;
diff --git a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts
index e058442..8574522 100644
--- a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts
+++ b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts
@@ -64,3 +64,7 @@
 &usb_ehci {
 	status = "ok";
 };
+
+&ipmi0 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
index 5144eb1..c53c8a8 100644
--- a/arch/arm64/boot/dts/hisilicon/hip07.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
@@ -1028,6 +1028,20 @@
 		#size-cells = <2>;
 		ranges;
 
+		isa@a01b0000 {
+			compatible = "hisilicon,hip07-lpc";
+			#size-cells = <1>;
+			#address-cells = <2>;
+			reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+			ipmi0: bt@e4 {
+				compatible = "ipmi-bt";
+				device_type = "ipmi";
+				reg = <0x01 0xe4 0x04>;
+				status = "disabled";
+			};
+		};
+
 		uart0: uart@602b0000 {
 			compatible = "arm,sbsa-uart";
 			reg = <0x0 0x602b0000 0x0 0x1000>;
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 0a52da4..feb5114 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -64,6 +64,14 @@ config BRCMSTB_GISB_ARB
 	  arbiter. This driver provides timeout and target abort error handling
 	  and internal bus master decoding.
 
+config HISILICON_LPC
+	bool "Support for ISA I/O space on Hisilicon Hip0X"
+	depends on (ARM64 && ARCH_HISI) || COMPILE_TEST
+	depends on LIBIO
+	help
+	  Driver needed for some legacy ISA devices attached to Low-Pin-Count
+	  on Hisilicon Hip0X SoC.
+
 config IMX_WEIM
 	bool "Freescale EIM DRIVER"
 	depends on ARCH_MXC
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index cc6364b..28e3862 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARM_CCI)		+= arm-cci.o
 obj-$(CONFIG_ARM_CCN)		+= arm-ccn.o
 
 obj-$(CONFIG_BRCMSTB_GISB_ARB)	+= brcmstb_gisb.o
+obj-$(CONFIG_HISILICON_LPC)	+= hisi_lpc.o
 obj-$(CONFIG_IMX_WEIM)		+= imx-weim.o
 obj-$(CONFIG_MIPS_CDMM)		+= mips_cdmm.o
 obj-$(CONFIG_MVEBU_MBUS) 	+= mvebu-mbus.o
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
new file mode 100644
index 0000000..03cf19a
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: Zou Rongrong <zourongrong@huawei.com>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/acpi.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <linux/slab.h>
+
+/*
+ * Setting this bit means each IO operation will target to a
+ * different port address:
+ * 0 means repeatedly IO operations will stick on the same port,
+ * such as BT;
+ */
+#define FG_INCRADDR_LPC		0x02
+
+struct lpc_cycle_para {
+	unsigned int opflags;
+	unsigned int csize; /* the data length of each operation */
+};
+
+struct hisilpc_dev {
+	spinlock_t cycle_lock;
+	void __iomem  *membase;
+	struct libio_range *io_host;
+};
+
+/* bounds of the LPC bus address range */
+#define LPC_MIN_BUS_RANGE	0x0
+
+/*
+ * The default maximal IO size for Hip06/Hip07 LPC bus.
+ * Defining the I/O range size as 0x400 here should be sufficient for
+ * all peripherals under the bus.
+ */
+#define LPC_BUS_IO_SIZE		0x400
+
+/* The maximum continuous cycles per burst */
+#define LPC_MAX_BURST	16
+/* The IO cycle counts supported is four per operation at maximum */
+#define LPC_MAX_DULEN	4
+#if LPC_MAX_DULEN > LPC_MAX_BURST
+#error "LPC.. MAX_DULEN must be not bigger than MAX_OPCNT!"
+#endif
+
+#if LPC_MAX_BURST % LPC_MAX_DULEN
+#error "LPC.. LPC_MAX_BURST must be multiple of LPC_MAX_DULEN!"
+#endif
+
+#define LPC_REG_START		0x00 /* start a new LPC cycle */
+#define LPC_REG_OP_STATUS	0x04 /* the current LPC status */
+#define LPC_REG_IRQ_ST		0x08 /* interrupt enable&status */
+#define LPC_REG_OP_LEN		0x10 /* how many LPC cycles each start */
+#define LPC_REG_CMD		0x14 /* command for the required LPC cycle */
+#define LPC_REG_ADDR		0x20 /* LPC target address */
+#define LPC_REG_WDATA		0x24 /* data to be written */
+#define LPC_REG_RDATA		0x28 /* data coming from peer */
+
+
+/* The command register fields */
+#define LPC_CMD_SAMEADDR	0x08
+#define LPC_CMD_TYPE_IO		0x00
+#define LPC_CMD_WRITE		0x01
+#define LPC_CMD_READ		0x00
+/* the bit attribute is W1C. 1 represents OK. */
+#define LPC_STAT_BYIRQ		0x02
+
+#define LPC_STATUS_IDLE		0x01
+#define LPC_OP_FINISHED		0x02
+
+#define START_WORK		0x01
+
+/*
+ * The minimal nanosecond interval for each query on LPC cycle status.
+ */
+#define LPC_NSEC_PERWAIT	100
+/*
+ * The maximum waiting time is about 128us.
+ * It is specific for stream I/O, such as ins.
+ * The fastest IO cycle time is about 390ns, but the worst case will wait
+ * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum
+ * burst cycles is 16. So, the maximum waiting time is about 128us under
+ * worst case.
+ * choose 1300 as the maximum.
+ */
+#define LPC_MAX_WAITCNT		1300
+/* About 10us. This is specific for single IO operation, such as inb. */
+#define LPC_PEROP_WAITCNT	100
+
+
+static inline int wait_lpc_idle(unsigned char *mbase,
+				unsigned int waitcnt) {
+	u32 opstatus;
+
+	while (waitcnt--) {
+		ndelay(LPC_NSEC_PERWAIT);
+		opstatus = readl(mbase + LPC_REG_OP_STATUS);
+		if (opstatus & LPC_STATUS_IDLE)
+			return (opstatus & LPC_OP_FINISHED) ? 0 : (-EIO);
+	}
+	return -ETIME;
+}
+
+/*
+ * hisilpc_target_in - trigger a series of lpc cycles to read required data
+ *		       from target peripheral.
+ * @pdev: pointer to hisi lpc device
+ * @para: some parameters used to control the lpc I/O operations
+ * @ptaddr: the lpc I/O target port address
+ * @buf: where the read back data is stored
+ * @opcnt: how many I/O operations required in this calling
+ *
+ * Only one byte data is read each I/O operation.
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int
+hisilpc_target_in(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
+		  unsigned long ptaddr, unsigned char *buf,
+		  unsigned long opcnt)
+{
+	unsigned long cnt_per_trans;
+	unsigned int cmd_word;
+	unsigned int waitcnt;
+	int ret;
+
+	if (!buf || !opcnt || !para || !para->csize || !lpcdev)
+		return -EINVAL;
+
+	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
+	waitcnt = LPC_PEROP_WAITCNT;
+	if (!(para->opflags & FG_INCRADDR_LPC)) {
+		cmd_word |= LPC_CMD_SAMEADDR;
+		waitcnt = LPC_MAX_WAITCNT;
+	}
+
+	ret = 0;
+	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
+	for (; opcnt && !ret; cnt_per_trans = para->csize) {
+		unsigned long flags;
+
+		/* whole operation must be atomic */
+		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
+
+		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
+
+		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
+
+		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
+
+		writel(START_WORK, lpcdev->membase + LPC_REG_START);
+
+		/* whether the operation is finished */
+		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
+		if (!ret) {
+			opcnt -= cnt_per_trans;
+			for (cnt_per_trans--; cnt_per_trans--; buf++)
+				*buf = readb_relaxed(lpcdev->membase +
+					LPC_REG_RDATA);
+			*buf = readb(lpcdev->membase + LPC_REG_RDATA);
+		}
+
+		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
+	}
+
+	return ret;
+}
+
+/*
+ * hisilpc_target_out - trigger a series of lpc cycles to write required
+ *			data to target peripheral.
+ * @pdev: pointer to hisi lpc device
+ * @para: some parameters used to control the lpc I/O operations
+ * @ptaddr: the lpc I/O target port address
+ * @buf: where the data to be written is stored
+ * @opcnt: how many I/O operations required
+ *
+ * Only one byte data is read each I/O operation.
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int
+hisilpc_target_out(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
+		   unsigned long ptaddr, const unsigned char *buf,
+		   unsigned long opcnt)
+{
+	unsigned long cnt_per_trans;
+	unsigned int cmd_word;
+	unsigned int waitcnt;
+	int ret;
+
+	if (!buf || !opcnt || !para || !lpcdev)
+		return -EINVAL;
+
+	/* default is increasing address */
+	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
+	waitcnt = LPC_PEROP_WAITCNT;
+	if (!(para->opflags & FG_INCRADDR_LPC)) {
+		cmd_word |= LPC_CMD_SAMEADDR;
+		waitcnt = LPC_MAX_WAITCNT;
+	}
+
+	ret = 0;
+	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
+	for (; opcnt && !ret; cnt_per_trans = para->csize) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
+
+		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
+		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
+		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
+
+		opcnt -= cnt_per_trans;
+		for (; cnt_per_trans--; buf++)
+			writeb_relaxed(*buf, lpcdev->membase + LPC_REG_WDATA);
+
+		writel(START_WORK, lpcdev->membase + LPC_REG_START);
+
+		/* whether the operation is finished */
+		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
+
+		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
+	}
+
+	return ret;
+}
+
+static inline unsigned long
+hisi_lpc_pio_to_addr(struct hisilpc_dev *lpcdev, unsigned long pio)
+{
+	return pio - lpcdev->io_host->io_start + lpcdev->io_host->hw_start;
+}
+
+
+/**
+ * hisilpc_comm_in - read/input the data from the I/O peripheral
+ *		     through LPC.
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @pio: the target I/O port address.
+ * @dlen: the data length required to read from the target I/O port.
+ *
+ * when succeed, the data read back is stored in buffer pointed by inbuf.
+ * For inb, return the data read from I/O or -1 when error occur.
+ */
+static u32 hisilpc_comm_in(void *devobj, unsigned long pio, size_t dlen)
+{
+	int ret = 0;
+	u32 rd_data;
+	unsigned long ptaddr;
+	unsigned char *newbuf;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN ||	(dlen & (dlen - 1)))
+		return -1;
+
+	/* the local buffer must be enough for one data unit */
+	if (sizeof(rd_data) < dlen)
+		return -1;
+
+	newbuf = (unsigned char *)&rd_data;
+
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, newbuf, dlen);
+	if (ret)
+		return -1;
+
+	return le32_to_cpu(rd_data);
+}
+
+/**
+ * hisilpc_comm_out - output the data whose maximum length is four bytes
+		      to the I/O peripheral through the LPC host.
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @outval: a value to be outputted from caller, maximum is four bytes.
+ * @pio: the target I/O port address.
+ * @dlen: the data length required writing to the target I/O port.
+ *
+ * This function is corresponding to out(b,w,l) only
+ *
+ */
+static void hisilpc_comm_out(void *devobj, unsigned long pio,
+			     u32 outval, size_t dlen)
+{
+	unsigned long ptaddr;
+	struct hisilpc_dev *lpcdev = devobj;
+	struct lpc_cycle_para iopara;
+	const unsigned char *newbuf;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		return;
+
+	if (sizeof(outval) < dlen)
+		return;
+
+	outval = cpu_to_le32(outval);
+
+	newbuf = (const unsigned char *)&outval;
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	hisilpc_target_out(lpcdev, &iopara, ptaddr, newbuf, dlen);
+}
+
+/*
+ * hisilpc_comm_ins - read/input the data in buffer to the I/O
+ *		peripheral through LPC, it corresponds to ins(b,w,l)
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @pio: the target I/O port address.
+ * @inbuf: a buffer where read/input data bytes are stored.
+ * @dlen: the data length required writing to the target I/O port.
+ * @count: how many data units whose length is dlen will be read.
+ *
+ */
+static u32
+hisilpc_comm_ins(void *devobj, unsigned long pio, void *inbuf,
+		 size_t dlen, unsigned int count)
+{
+	struct hisilpc_dev *lpcdev = devobj;
+	struct lpc_cycle_para iopara;
+	unsigned char *newbuf;
+	unsigned int loopcnt, cntleft;
+	unsigned long ptaddr;
+
+	if (!lpcdev || !inbuf || !count || !dlen ||
+		dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)) || count % dlen)
+		return -EINVAL;
+
+	iopara.opflags = 0;
+	if (dlen > 1)
+		iopara.opflags |= FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+	newbuf = (unsigned char *)inbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		int ret;
+
+		loopcnt = (cntleft >= LPC_MAX_BURST) ? LPC_MAX_BURST : cntleft;
+		ret = hisilpc_target_in(lpcdev, &iopara, ptaddr,
+					newbuf, loopcnt);
+		if (ret)
+			return ret;
+		newbuf += loopcnt;
+		cntleft -= loopcnt;
+	} while (cntleft);
+
+	return 0;
+}
+
+/*
+ * hisilpc_comm_outs - write/output the data in buffer to the I/O
+ *		peripheral through LPC, it corresponds to outs(b,w,l)
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @pio: the target I/O port address.
+ * @outbuf: a buffer where write/output data bytes are stored.
+ * @dlen: the data length required writing to the target I/O port .
+ * @count: how many data units whose length is dlen will be written.
+ *
+ */
+static void
+hisilpc_comm_outs(void *devobj, unsigned long pio, const void *outbuf,
+		  size_t dlen, unsigned int count)
+{
+	struct hisilpc_dev *lpcdev = devobj;
+	struct lpc_cycle_para iopara;
+	const unsigned char *newbuf;
+	unsigned int loopcnt, cntleft;
+	unsigned long ptaddr;
+
+	if (!lpcdev || !outbuf || !count || !dlen ||
+		dlen > LPC_MAX_DULEN || (dlen & (dlen - 1)) || count % dlen)
+		return;
+
+	iopara.opflags = 0;
+	if (dlen > 1)
+		iopara.opflags |= FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+	newbuf = (unsigned char *)outbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		loopcnt = (cntleft >= LPC_MAX_BURST) ? LPC_MAX_BURST : cntleft;
+		if (hisilpc_target_out(lpcdev, &iopara, ptaddr, newbuf,
+						loopcnt))
+			break;
+		newbuf += loopcnt;
+		cntleft -= loopcnt;
+	} while (cntleft);
+}
+
+static struct libio_ops hisi_lpc_ops = {
+	.pfin = hisilpc_comm_in,
+	.pfout = hisilpc_comm_out,
+	.pfins = hisilpc_comm_ins,
+	.pfouts = hisilpc_comm_outs,
+};
+
+
+static int hisilpc_host_io_register(struct device *dev,
+			struct hisilpc_dev *lpcdev)
+{
+	struct libio_range *range, *tmprange;
+
+	/*
+	 * indirectIO bus was detected, time to request the linux virtual
+	 * IO.
+	 */
+	range = kzalloc(sizeof(*range), GFP_KERNEL);
+	if (!range)
+		return -ENOMEM;
+	range->node = dev->fwnode;
+	range->flags = IO_HOST_INDIRECT;
+	range->size = LPC_BUS_IO_SIZE;
+	range->hw_start = LPC_MIN_BUS_RANGE;
+
+	tmprange = register_libio_range(range);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
+
+	lpcdev->io_host = range;
+
+	return 0;
+}
+
+/**
+ * hisilpc_probe - the probe callback function for hisi lpc device,
+ *		   will finish all the initialization.
+ * @pdev: the platform device corresponding to hisi lpc
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct hisilpc_dev *lpcdev;
+	int ret = 0;
+
+	dev_info(dev, "probing...\n");
+
+	lpcdev = devm_kzalloc(dev, sizeof(struct hisilpc_dev), GFP_KERNEL);
+	if (!lpcdev)
+		return -ENOMEM;
+
+	spin_lock_init(&lpcdev->cycle_lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no MEM resource\n");
+		return -ENODEV;
+	}
+
+	lpcdev->membase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(lpcdev->membase)) {
+		dev_err(dev, "remap failed\n");
+		return PTR_ERR(lpcdev->membase);
+	}
+
+	/* register the LPC host PIO resources */
+	ret = hisilpc_host_io_register(dev, lpcdev);
+	if (ret) {
+		dev_err(dev, "host PIO registration failed!\n");
+		return ret;
+	}
+
+	lpcdev->io_host->devpara = lpcdev;
+	lpcdev->io_host->ops = &hisi_lpc_ops;
+
+	platform_set_drvdata(pdev, lpcdev);
+
+	/*
+	 * It is time to start the children scannings....
+	 */
+	if (!has_acpi_companion(dev)) {
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+		if (ret)
+			dev_err(dev, "OF: enumerate LPC bus fail(%d)\n", ret);
+	}
+
+	if (!ret) {
+		dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+			 &lpcdev->io_host->io_start,
+			 &lpcdev->io_host->size);
+	} else {
+		dev_info(dev, "hslpc probing is fail(%d)\n", ret);
+		/*
+		 * When LPC probing is not completely successful, set 'devpara'
+		 * as NULL. This will make all the LPC I/O return failure
+		 * directly without any hardware operations. It will block
+		 * some peripherals which had not finished the initialization
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id hisilpc_of_match[] = {
+	{ .compatible = "hisilicon,hip06-lpc", },
+	{ .compatible = "hisilicon,hip07-lpc", },
+	{},
+};
+
+static struct platform_driver hisilpc_driver = {
+	.driver = {
+		.name           = "hisi_lpc",
+		.of_match_table = hisilpc_of_match,
+	},
+	.probe = hisilpc_probe,
+};
+
+/*
+ * must be called before fs_initcall(pnpacpi_init) and after
+ * subsys_initcall(acpi_init);
+ * As the LPC uart(PNP0503) depends on this driver.
+ */
+static int __init hisilpc_init(void)
+{
+	return platform_driver_register(&hisilpc_driver);
+}
+
+subsys_initcall_sync(hisilpc_init);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose  dependency has not met
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
                   ` (3 preceding siblings ...)
  2017-03-13  2:42 ` [PATCH V7 4/7] LPC: Support the device-tree LPC host on Hip06/Hip07 zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-13 21:24   ` Rafael J. Wysocki
                     ` (2 more replies)
  2017-03-13  2:42 ` [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O zhichang.yuan
                   ` (2 subsequent siblings)
  7 siblings, 3 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue on Asus
T100TA), the '_DEP' was supported to solve the dependency of Asus battery. But
this patch is specific to Asus battery device.
In the real world, there are other devices which need the dependency to play the
role on the enumeration order. For example, all the Hip06 LPC
periperals(IPMI-BT, uart, etc) must be scanned after the LPC host driver
finished the probing. So, it makes sense to add a checking whether the ACPI
device meet all the dependencies during its enumeration slot, if not, the
enumeration will be delayed till all dependency master finish their work.

This patch adds the dependency checking in ACPI enumeration, also the
corresponding handling to retrigger the Hip06 LPC peripherals' scanning.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
---
 drivers/acpi/battery.c |  3 ---
 drivers/acpi/scan.c    |  3 +++
 drivers/bus/hisi_lpc.c | 12 +++++++++++-
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 4ef1e46..e8d1af1 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1210,9 +1210,6 @@ static int acpi_battery_add(struct acpi_device *device)
 	if (!device)
 		return -EINVAL;
 
-	if (device->dep_unmet)
-		return -EPROBE_DEFER;
-
 	battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
 	if (!battery)
 		return -ENOMEM;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1926918..97721b1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1843,6 +1843,9 @@ static void acpi_bus_attach(struct acpi_device *device)
 	if (device->handler)
 		goto ok;
 
+	if (device->dep_unmet)
+		return;
+
 	if (!device->flags.initialized) {
 		device->flags.power_manageable =
 			device->power.states[ACPI_STATE_D0].flags.valid;
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index 03cf19a..345ea12 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -516,8 +516,18 @@ static int hisilpc_probe(struct platform_device *pdev)
 
 	/*
 	 * It is time to start the children scannings....
+	 * For ACPI children, the corresponding devices will be created after
+	 * retriggering the ACPI scanning by removing the dependency blocking.
 	 */
-	if (!has_acpi_companion(dev)) {
+	if (has_acpi_companion(dev)) {
+		struct acpi_device *adev;
+
+		adev = to_acpi_device_node(dev->fwnode);
+		if (!adev)
+			ret = -ENODEV;
+		else
+			acpi_walk_dep_device_list(adev->handle);
+	} else {
 		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 		if (ret)
 			dev_err(dev, "OF: enumerate LPC bus fail(%d)\n", ret);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration  of ACPI host I/O
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
                   ` (4 preceding siblings ...)
  2017-03-13  2:42 ` [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-14  4:27   ` kbuild test robot
  2017-03-14  5:10   ` kbuild test robot
  2017-03-13  2:42 ` [PATCH V7 7/7] LPC: Add the ACPI LPC support zhichang.yuan
  2017-03-14  8:39 ` [PATCH V7 0/7] LPC: legacy ISA I/O support Arnd Bergmann
  7 siblings, 2 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

For those hosts which access I/O based on the host/bus local I/O addresses,
their I/O range must be registered and translated as unique logical PIO before
the ACPI enumeration on the devices under the hosts. Otherwise, there is no
available I/O resources allocated for those devices.
This patch implements the interfaces in LIBIO to perform the host local I/O
translation and set the logical IO mapped as ACPI I/O resources.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 include/linux/libio.h |   4 +
 lib/libio.c           | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 228 insertions(+)

diff --git a/include/linux/libio.h b/include/linux/libio.h
index 91038aa..95c5f3e 100644
--- a/include/linux/libio.h
+++ b/include/linux/libio.h
@@ -20,6 +20,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/acpi.h>
 #include <linux/fwnode.h>
 
 /* This is compatible to PCI MMIO. */
@@ -90,5 +91,8 @@ static inline unsigned long libio_translate_hwaddr(struct fwnode_handle *fwnode,
 
 extern unsigned long libio_translate_cpuaddr(resource_size_t hw_addr);
 
+extern int acpi_set_libio_resource(struct acpi_device *adev,
+			struct acpi_device *host);
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_LIBIO_H */
diff --git a/lib/libio.c b/lib/libio.c
index e42f50b..b60ec9c 100644
--- a/lib/libio.c
+++ b/lib/libio.c
@@ -242,6 +242,230 @@ resource_size_t libio_to_hwaddr(unsigned long pio)
 	return -1;
 }
 
+#ifdef	CONFIG_ACPI
+static inline bool acpi_libio_supported_resource(struct acpi_resource *res)
+{
+	switch (res->type) {
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+		return true;
+	}
+	return false;
+}
+
+static acpi_status acpi_count_libiores(struct acpi_resource *res,
+					   void *data)
+{
+	int *res_cnt = data;
+
+	if (acpi_libio_supported_resource(res) &&
+		!acpi_dev_filter_resource_type(res, IORESOURCE_IO))
+		(*res_cnt)++;
+
+	return AE_OK;
+}
+
+static acpi_status acpi_read_one_libiores(struct acpi_resource *res,
+		void *data)
+{
+	struct acpi_resource **resource = data;
+
+	if (acpi_libio_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_libiores_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__CRS,
+				     acpi_count_libiores, &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__CRS,
+				     acpi_read_one_libiores, &resource);
+	if (ACPI_FAILURE(status)) {
+		kfree(buffer->pointer);
+		dev_err(&adev->dev, "can't evaluate _CRS: %d\n", status);
+		return -EINVAL;
+	}
+
+	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
+	resource->length = sizeof(struct acpi_resource);
+
+	return 0;
+}
+
+static int acpi_translate_libiores(struct acpi_device *adev,
+		struct acpi_device *host, struct acpi_buffer *buffer)
+{
+	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
+	struct acpi_resource *resource = buffer->pointer;
+	struct acpi_resource_address64 addr;
+	unsigned long sys_port;
+	struct device *dev = &adev->dev;
+
+	/* only one I/O resource now */
+	if (res_cnt != 1) {
+		dev_err(dev, "encode %d resources whose type is(%d)!\n",
+			res_cnt, resource->type);
+		return -EINVAL;
+	}
+
+	if (ACPI_FAILURE(acpi_resource_to_address64(resource, &addr))) {
+		dev_err(dev, "convert acpi resource(%d) as addr64 FAIL!\n",
+			resource->type);
+		return -EFAULT;
+	}
+
+	/* For indirect-IO, addr length must be fixed. (>0, 0/1, 0/1)(0,0,0) */
+	if (addr.min_address_fixed != addr.max_address_fixed) {
+		dev_warn(dev, "variable I/O resource is invalid!\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "CRS IO: len=0x%llx [0x%llx - 0x%llx]\n",
+			addr.address.address_length, addr.address.minimum,
+			addr.address.maximum);
+	sys_port = libio_translate_hwaddr(&host->fwnode, addr.address.minimum);
+	if (sys_port == -1) {
+		dev_err(dev, "translate bus-addr(0x%llx) fail!\n",
+			addr.address.minimum);
+		return -EFAULT;
+	}
+
+	switch (resource->type) {
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	{
+		struct acpi_resource_address32 *out_res;
+
+		out_res = &resource->data.address32;
+		if (!addr.address.address_length)
+			addr.address.address_length = out_res->address.maximum -
+				out_res->address.minimum + 1;
+		out_res->address.minimum = sys_port;
+		out_res->address.maximum = sys_port +
+				addr.address.address_length - 1;
+		out_res->address.address_length = addr.address.address_length;
+
+		dev_info(dev, "_SRS 32IO: [0x%x - 0x%x] len = 0x%x\n",
+			out_res->address.minimum,
+			out_res->address.maximum,
+			out_res->address.address_length);
+
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+	{
+		struct acpi_resource_address64 *out_res;
+
+		out_res = &resource->data.address64;
+		if (!addr.address.address_length)
+			addr.address.address_length = out_res->address.maximum -
+				out_res->address.minimum + 1;
+		out_res->address.minimum = sys_port;
+		out_res->address.maximum = sys_port +
+				addr.address.address_length - 1;
+		out_res->address.address_length = addr.address.address_length;
+
+		dev_info(dev, "_SRS 64IO: [0x%llx - 0x%llx] len = 0x%llx\n",
+			out_res->address.minimum,
+			out_res->address.maximum,
+			out_res->address.address_length);
+
+		break;
+	}
+
+	default:
+		return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+/*
+ * update/set the current I/O resource of the designated device node.
+ * after this calling, the enumeration can be started as the I/O resource
+ * had been translated to logicial I/O from bus-local I/O.
+ *
+ * @adev: the device node to be updated the I/O resource;
+ * @host: the device node where 'adev' is attached, which can be not
+ *	the parent of 'adev';
+ *
+ * return 0 when successful, negative is for failure.
+ */
+int acpi_set_libio_resource(struct acpi_device *adev,
+		struct acpi_device *host)
+{
+	struct device *dev = &adev->dev;
+	struct acpi_buffer buffer;
+	acpi_status status;
+	int ret;
+
+	if (!host)
+		return -EINVAL;
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(dev, "ACPI: device is not present!\n");
+		return 0;
+	}
+	/* whether the child had been enumerated? */
+	if (acpi_device_enumerated(adev)) {
+		dev_info(dev, "ACPI: had been enumerated!\n");
+		return 0;
+	}
+
+	/* read the _CRS and convert as acpi_buffer */
+	status = acpi_build_libiores_template(adev, &buffer);
+	if (ACPI_FAILURE(status)) {
+		dev_warn(dev, "Failure evaluating %s\n", METHOD_NAME__CRS);
+		return -ENODEV;
+	}
+
+	/* translate the I/O resources */
+	ret = acpi_translate_libiores(adev, host, &buffer);
+	if (ret) {
+		kfree(buffer.pointer);
+		dev_err(dev, "Translate I/O range FAIL!\n");
+		return ret;
+	}
+
+	/* set current resource... */
+	status = acpi_set_current_resources(adev->handle, &buffer);
+	kfree(buffer.pointer);
+	if (ACPI_FAILURE(status)) {
+		dev_err(dev, "Error evaluating _SRS (0x%x)\n", status);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+#endif
+
 #ifdef PCI_IOBASE
 static struct libio_range *find_io_range(unsigned long pio)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH V7 7/7] LPC: Add the ACPI LPC support
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
                   ` (5 preceding siblings ...)
  2017-03-13  2:42 ` [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O zhichang.yuan
@ 2017-03-13  2:42 ` zhichang.yuan
  2017-03-14  5:25   ` kbuild test robot
  2017-03-14  8:39 ` [PATCH V7 0/7] LPC: legacy ISA I/O support Arnd Bergmann
  7 siblings, 1 reply; 24+ messages in thread
From: zhichang.yuan @ 2017-03-13  2:42 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, rjw, arnd, linux-arm-kernel
  Cc: linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

The patch update the _CRS of LPC children based on the relevant LIBIO
interfaces. Then the ACPI platform device enumeration for LPC can apply the
right I/O resource to request the system I/O space from ioport_resource and
ensure the LPC peripherals work well.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/bus/hisi_lpc.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index 345ea12..3796b1f 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -464,6 +464,27 @@ static int hisilpc_host_io_register(struct device *dev,
 
 	lpcdev->io_host = range;
 
+	/*
+	 * 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) {
+			int ret;
+
+			ret = acpi_set_libio_resource(child, root);
+			if (ret) {
+				dev_err(&child->dev, "set resource failed..\n");
+				return ret;
+			}
+		}
+	}
+
 	return 0;
 }
 
@@ -558,10 +579,18 @@ static int hisilpc_probe(struct platform_device *pdev)
 	{},
 };
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+	{"HISI0191", },
+	{},
+};
+#endif
+
 static struct platform_driver hisilpc_driver = {
 	.driver = {
 		.name           = "hisi_lpc",
 		.of_match_table = hisilpc_of_match,
+		.acpi_match_table = ACPI_PTR(hisilpc_acpi_match),
 	},
 	.probe = hisilpc_probe,
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose  dependency has not met
  2017-03-13  2:42 ` [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met zhichang.yuan
@ 2017-03-13 21:24   ` Rafael J. Wysocki
  2017-03-14  8:14     ` Gabriele Paoloni
  2017-03-16  2:21     ` zhichang.yuan
  2017-03-14  5:11   ` kbuild test robot
  2017-03-14  6:10   ` kbuild test robot
  2 siblings, 2 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2017-03-13 21:24 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, arnd, linux-arm-kernel, linux-acpi,
	lorenzo.pieralisi, benh, linux-kernel, linuxarm, devicetree,
	linux-pci, linux-serial, minyard, liviu.dudau, zourongrong,
	john.garry, gabriele.paoloni, zhichang.yuan02, kantyzc, xuwei5

On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
> In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue on Asus
> T100TA), the '_DEP' was supported to solve the dependency of Asus battery. But
> this patch is specific to Asus battery device.
> In the real world, there are other devices which need the dependency to play the
> role on the enumeration order. For example, all the Hip06 LPC
> periperals(IPMI-BT, uart, etc) must be scanned after the LPC host driver
> finished the probing. So, it makes sense to add a checking whether the ACPI
> device meet all the dependencies during its enumeration slot, if not, the
> enumeration will be delayed till all dependency master finish their work.
> 
> This patch adds the dependency checking in ACPI enumeration, also the
> corresponding handling to retrigger the Hip06 LPC peripherals' scanning.

AFAICS, _DEP is generally abused in the wild and cannot be made generic.  Sorry.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O
  2017-03-13  2:42 ` [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O zhichang.yuan
@ 2017-03-14  4:27   ` kbuild test robot
  2017-03-14  5:10   ` kbuild test robot
  1 sibling, 0 replies; 24+ messages in thread
From: kbuild test robot @ 2017-03-14  4:27 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, mark.rutland, rjw, arnd, linux-arm-kernel,
	linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

[-- Attachment #1: Type: text/plain, Size: 4192 bytes --]

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc2 next-20170310]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/zhichang-yuan/LPC-legacy-ISA-I-O-support/20170314-114635
config: i386-tinyconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   In file included from arch/x86/boot/compressed/misc.h:24:0,
                    from arch/x86/boot/compressed/cmdline.c:1:
>> arch/x86/boot/compressed/../ctype.h:4:19: error: redefinition of 'isdigit'
    static inline int isdigit(int ch)
                      ^~~~~~~
   In file included from include/acpi/platform/aclinux.h:82:0,
                    from include/acpi/platform/acenv.h:186,
                    from include/acpi/acpi.h:56,
                    from include/linux/acpi.h:33,
                    from include/linux/libio.h:23,
                    from include/linux/io.h:27,
                    from arch/x86/boot/compressed/misc.h:17,
                    from arch/x86/boot/compressed/cmdline.c:1:
   include/linux/ctype.h:25:19: note: previous definition of 'isdigit' was here
    static inline int isdigit(int c)
                      ^~~~~~~
>> arch/x86/boot/compressed/../ctype.h:9:32: error: expected ')' before 'ch'
    static inline int isxdigit(int ch)
                                   ^
   include/linux/ctype.h:20:50: note: in definition of macro '__ismask'
    #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
                                                     ^
   arch/x86/boot/compressed/../ctype.h:9:19: note: in expansion of macro 'isxdigit'
    static inline int isxdigit(int ch)
                      ^~~~~~~~
   include/linux/ctype.h:20:52: error: expected expression before ']' token
    #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
                                                       ^
   include/linux/ctype.h:36:23: note: in expansion of macro '__ismask'
    #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
                          ^~~~~~~~
   arch/x86/boot/compressed/../ctype.h:9:19: note: in expansion of macro 'isxdigit'
    static inline int isxdigit(int ch)
                      ^~~~~~~~
   include/linux/ctype.h:36:44: error: expected ')' before '!=' token
    #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
                                               ^
   arch/x86/boot/compressed/../ctype.h:9:19: note: in expansion of macro 'isxdigit'
    static inline int isxdigit(int ch)
                      ^~~~~~~~

vim +/isdigit +4 arch/x86/boot/compressed/../ctype.h

60b217a0 arch/x86/boot/ctype.h   Alexander Kuleshov 2015-01-03   1  #ifndef BOOT_CTYPE_H
60b217a0 arch/x86/boot/ctype.h   Alexander Kuleshov 2015-01-03   2  #define BOOT_CTYPE_H
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02   3  
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02  @4  static inline int isdigit(int ch)
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02   5  {
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02   6  	return (ch >= '0') && (ch <= '9');
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02   7  }
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02   8  
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02  @9  static inline int isxdigit(int ch)
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02  10  {
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02  11  	if (isdigit(ch))
f4ed2877 arch/x86/boot/isdigit.h Yinghai Lu         2010-08-02  12  		return true;

:::::: The code at line 4 was first introduced by commit
:::::: f4ed2877b16e8146427306aea8819adac5c88374 x86, setup: reorganize the early console setup

:::::: TO: Yinghai Lu <yinghai@kernel.org>
:::::: CC: H. Peter Anvin <hpa@linux.intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6522 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O
  2017-03-13  2:42 ` [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O zhichang.yuan
  2017-03-14  4:27   ` kbuild test robot
@ 2017-03-14  5:10   ` kbuild test robot
  1 sibling, 0 replies; 24+ messages in thread
From: kbuild test robot @ 2017-03-14  5:10 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, mark.rutland, rjw, arnd, linux-arm-kernel,
	linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

[-- Attachment #1: Type: text/plain, Size: 3405 bytes --]

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc2 next-20170310]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/zhichang-yuan/LPC-legacy-ISA-I-O-support/20170314-114635
config: blackfin-allmodconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=blackfin 

All error/warnings (new ones prefixed by >>):

   include/linux/ratelimit.h: In function 'ratelimit_state_exit':
>> arch/blackfin/kernel/module.c:7:40: error: 'mod' undeclared (first use in this function)
    #define pr_fmt(fmt) "module %s: " fmt, mod->name
                                           ^
   include/linux/printk.h:303:22: note: in expansion of macro 'pr_fmt'
     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
                         ^~~~~~
   include/linux/printk.h:304:17: note: in expansion of macro 'pr_warning'
    #define pr_warn pr_warning
                    ^~~~~~~~~~
>> include/linux/ratelimit.h:61:3: note: in expansion of macro 'pr_warn'
      pr_warn("%s: %d output lines suppressed due to ratelimiting\n",
      ^~~~~~~
   arch/blackfin/kernel/module.c:7:40: note: each undeclared identifier is reported only once for each function it appears in
    #define pr_fmt(fmt) "module %s: " fmt, mod->name
                                           ^
   include/linux/printk.h:303:22: note: in expansion of macro 'pr_fmt'
     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
                         ^~~~~~
   include/linux/printk.h:304:17: note: in expansion of macro 'pr_warning'
    #define pr_warn pr_warning
                    ^~~~~~~~~~
>> include/linux/ratelimit.h:61:3: note: in expansion of macro 'pr_warn'
      pr_warn("%s: %d output lines suppressed due to ratelimiting\n",
      ^~~~~~~

vim +/mod +7 arch/blackfin/kernel/module.c

1394f032 Bryan Wu    2007-05-06   1  /*
96f1050d Robin Getz  2009-09-24   2   * Copyright 2004-2009 Analog Devices Inc.
1394f032 Bryan Wu    2007-05-06   3   *
96f1050d Robin Getz  2009-09-24   4   * Licensed under the GPL-2 or later
1394f032 Bryan Wu    2007-05-06   5   */
1394f032 Bryan Wu    2007-05-06   6  
b75a9e6b Joe Perches 2010-10-20  @7  #define pr_fmt(fmt) "module %s: " fmt, mod->name
1394f032 Bryan Wu    2007-05-06   8  
1394f032 Bryan Wu    2007-05-06   9  #include <linux/moduleloader.h>
1394f032 Bryan Wu    2007-05-06  10  #include <linux/elf.h>
1394f032 Bryan Wu    2007-05-06  11  #include <linux/vmalloc.h>
1394f032 Bryan Wu    2007-05-06  12  #include <linux/fs.h>
1394f032 Bryan Wu    2007-05-06  13  #include <linux/string.h>
1394f032 Bryan Wu    2007-05-06  14  #include <linux/kernel.h>
1394f032 Bryan Wu    2007-05-06  15  #include <asm/dma.h>

:::::: The code at line 7 was first introduced by commit
:::::: b75a9e6bfba5c7343391ac1bacd44d6652dde8da Blackfin: use more standard pr_fmt in the module loader

:::::: TO: Joe Perches <joe@perches.com>
:::::: CC: Mike Frysinger <vapier@gentoo.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 43892 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-13  2:42 ` [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met zhichang.yuan
  2017-03-13 21:24   ` Rafael J. Wysocki
@ 2017-03-14  5:11   ` kbuild test robot
  2017-03-14  6:10   ` kbuild test robot
  2 siblings, 0 replies; 24+ messages in thread
From: kbuild test robot @ 2017-03-14  5:11 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, mark.rutland, rjw, arnd, linux-arm-kernel,
	linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

[-- Attachment #1: Type: text/plain, Size: 1749 bytes --]

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc2 next-20170310]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/zhichang-yuan/LPC-legacy-ISA-I-O-support/20170314-114635
config: alpha-allyesconfig (attached as .config)
compiler: alpha-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=alpha 

All errors (new ones prefixed by >>):

   drivers/bus/hisi_lpc.c: In function 'hisilpc_probe':
>> drivers/bus/hisi_lpc.c:529:4: error: implicit declaration of function 'acpi_walk_dep_device_list' [-Werror=implicit-function-declaration]
       acpi_walk_dep_device_list(adev->handle);
       ^~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/bus/hisi_lpc.c:529:34: error: dereferencing pointer to incomplete type 'struct acpi_device'
       acpi_walk_dep_device_list(adev->handle);
                                     ^~
   cc1: some warnings being treated as errors

vim +/acpi_walk_dep_device_list +529 drivers/bus/hisi_lpc.c

   523			struct acpi_device *adev;
   524	
   525			adev = to_acpi_device_node(dev->fwnode);
   526			if (!adev)
   527				ret = -ENODEV;
   528			else
 > 529				acpi_walk_dep_device_list(adev->handle);
   530		} else {
   531			ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
   532			if (ret)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 49586 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 7/7] LPC: Add the ACPI LPC support
  2017-03-13  2:42 ` [PATCH V7 7/7] LPC: Add the ACPI LPC support zhichang.yuan
@ 2017-03-14  5:25   ` kbuild test robot
  0 siblings, 0 replies; 24+ messages in thread
From: kbuild test robot @ 2017-03-14  5:25 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, mark.rutland, rjw, arnd, linux-arm-kernel,
	linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

[-- Attachment #1: Type: text/plain, Size: 3415 bytes --]

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc2 next-20170310]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/zhichang-yuan/LPC-legacy-ISA-I-O-support/20170314-114635
config: blackfin-allmodconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=blackfin 

All error/warnings (new ones prefixed by >>):

   In file included from include/linux/list.h:8:0,
                    from include/linux/resource_ext.h:17,
                    from include/linux/acpi.h:26,
                    from drivers/bus/hisi_lpc.c:19:
   drivers/bus/hisi_lpc.c: In function 'hisilpc_host_io_register':
>> include/linux/list.h:463:43: error: dereferencing pointer to incomplete type 'struct acpi_device'
     for (pos = list_first_entry(head, typeof(*pos), member); \
                                               
   include/linux/kernel.h:852:18: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                     ^~~~
   include/linux/list.h:376:2: note: in expansion of macro 'list_entry'
     list_entry((ptr)->next, type, member)
     ^~~~~~~~~~
   include/linux/list.h:463:13: note: in expansion of macro 'list_first_entry'
     for (pos = list_first_entry(head, typeof(*pos), member); \
                ^~~~~~~~~~~~~~~~
>> drivers/bus/hisi_lpc.c:477:3: note: in expansion of macro 'list_for_each_entry'
      list_for_each_entry(child, &root->children, node) {
      ^~~~~~~~~~~~~~~~~~~
   drivers/bus/hisi_lpc.c: In function 'hisilpc_probe':
   drivers/bus/hisi_lpc.c:550:4: error: implicit declaration of function 'acpi_walk_dep_device_list' [-Werror=implicit-function-declaration]
       acpi_walk_dep_device_list(adev->handle);
       ^~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +463 include/linux/list.h

^1da177e Linus Torvalds 2005-04-16  457   * list_for_each_entry	-	iterate over list of given type
8e3a67a9 Randy Dunlap   2006-06-25  458   * @pos:	the type * to use as a loop cursor.
^1da177e Linus Torvalds 2005-04-16  459   * @head:	the head for your list.
3943f42c Andrey Utkin   2014-11-14  460   * @member:	the name of the list_head within the struct.
^1da177e Linus Torvalds 2005-04-16  461   */
^1da177e Linus Torvalds 2005-04-16  462  #define list_for_each_entry(pos, head, member)				\
93be3c2e Oleg Nesterov  2013-11-12 @463  	for (pos = list_first_entry(head, typeof(*pos), member);	\
e66eed65 Linus Torvalds 2011-05-19  464  	     &pos->member != (head);					\
8120e2e5 Oleg Nesterov  2013-11-12  465  	     pos = list_next_entry(pos, member))
^1da177e Linus Torvalds 2005-04-16  466  

:::::: The code at line 463 was first introduced by commit
:::::: 93be3c2eb3371f022ad88acf1ab6bee8e3c38378 list: introduce list_last_entry(), use list_{first,last}_entry()

:::::: TO: Oleg Nesterov <oleg@redhat.com>
:::::: CC: Linus Torvalds <torvalds@linux-foundation.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 43892 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-13  2:42 ` [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met zhichang.yuan
  2017-03-13 21:24   ` Rafael J. Wysocki
  2017-03-14  5:11   ` kbuild test robot
@ 2017-03-14  6:10   ` kbuild test robot
  2 siblings, 0 replies; 24+ messages in thread
From: kbuild test robot @ 2017-03-14  6:10 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, mark.rutland, rjw, arnd, linux-arm-kernel,
	linux-acpi, lorenzo.pieralisi, benh, linux-kernel, linuxarm,
	devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

[-- Attachment #1: Type: text/plain, Size: 1466 bytes --]

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc2 next-20170310]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/zhichang-yuan/LPC-legacy-ISA-I-O-support/20170314-114635
config: tile-allyesconfig (attached as .config)
compiler: tilegx-linux-gcc (GCC) 4.6.2
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=tile 

All errors (new ones prefixed by >>):

   drivers/bus/hisi_lpc.c: In function 'hisilpc_probe':
   drivers/bus/hisi_lpc.c:529:4: error: implicit declaration of function 'acpi_walk_dep_device_list'
>> drivers/bus/hisi_lpc.c:529:34: error: dereferencing pointer to incomplete type
   cc1: some warnings being treated as errors

vim +529 drivers/bus/hisi_lpc.c

   523			struct acpi_device *adev;
   524	
   525			adev = to_acpi_device_node(dev->fwnode);
   526			if (!adev)
   527				ret = -ENODEV;
   528			else
 > 529				acpi_walk_dep_device_list(adev->handle);
   530		} else {
   531			ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
   532			if (ret)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 48199 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-13 21:24   ` Rafael J. Wysocki
@ 2017-03-14  8:14     ` Gabriele Paoloni
  2017-03-16  2:21     ` zhichang.yuan
  1 sibling, 0 replies; 24+ messages in thread
From: Gabriele Paoloni @ 2017-03-14  8:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Yuanzhichang
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, arnd, linux-arm-kernel, linux-acpi,
	lorenzo.pieralisi, benh, linux-kernel, Linuxarm, devicetree,
	linux-pci, linux-serial, minyard, liviu.dudau, zourongrong,
	John Garry, zhichang.yuan02, kantyzc, xuwei (O)

Hi Rafael

Many thanks for your review

> -----Original Message-----
> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: 13 March 2017 21:25
> To: Yuanzhichang
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> mark.rutland@arm.com; arnd@arndb.de; linux-arm-
> kernel@lists.infradead.org; linux-acpi@vger.kernel.org;
> lorenzo.pieralisi@arm.com; benh@kernel.crashing.org; linux-
> kernel@vger.kernel.org; Linuxarm; devicetree@vger.kernel.org; linux-
> pci@vger.kernel.org; linux-serial@vger.kernel.org; minyard@acm.org;
> liviu.dudau@arm.com; zourongrong@gmail.com; John Garry; Gabriele
> Paoloni; zhichang.yuan02@gmail.com; kantyzc@163.com; xuwei (O)
> Subject: Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices
> whose dependency has not met
> 
> On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
> > In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue on
> Asus
> > T100TA), the '_DEP' was supported to solve the dependency of Asus
> battery. But
> > this patch is specific to Asus battery device.
> > In the real world, there are other devices which need the dependency
> to play the
> > role on the enumeration order. For example, all the Hip06 LPC
> > periperals(IPMI-BT, uart, etc) must be scanned after the LPC host
> driver
> > finished the probing. So, it makes sense to add a checking whether
> the ACPI
> > device meet all the dependencies during its enumeration slot, if not,
> the
> > enumeration will be delayed till all dependency master finish their
> work.
> >
> > This patch adds the dependency checking in ACPI enumeration, also the
> > corresponding handling to retrigger the Hip06 LPC peripherals'
> scanning.
> 
> AFAICS, _DEP is generally abused in the wild and cannot be made
> generic.  Sorry.

Another option here would be to revert this patch and add a dependency
check in the probe functions of the LPC possible children nodes (e.g. 
in the IPMI driver:
http://elixir.free-electrons.com/source/drivers/char/ipmi/ipmi_si_intf.c?v=4.10#L2683
)  

we could add 

	if (device->dep_unmet)
		return -EPROBE_DEFER;

as we now have in acpi/battery.c...

I think this should not make any difference for current shipped FW that has
got no DEP method...

What do you think?

Many Thanks
Gab

> 
> Thanks,
> Rafael

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 0/7] LPC: legacy ISA I/O support
  2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
                   ` (6 preceding siblings ...)
  2017-03-13  2:42 ` [PATCH V7 7/7] LPC: Add the ACPI LPC support zhichang.yuan
@ 2017-03-14  8:39 ` Arnd Bergmann
  2017-03-15  4:05   ` zhichang.yuan
  7 siblings, 1 reply; 24+ messages in thread
From: Arnd Bergmann @ 2017-03-14  8:39 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, Rafael Wysocki, Mark Rutland, rjw, Linux ARM,
	ACPI Devel Maling List, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List, linuxarm,
	devicetree, linux-pci, linux-serial, Corey Minyard, liviu.dudau,
	Zou Rongrong, John Garry, Gabriele Paoloni, zhichang.yuan02,
	kantyzc, Wei Xu

On Mon, Mar 13, 2017 at 3:42 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> This patchset supports the IPMI-bt device attached to the Low-Pin-Count
> interface implemented on Hisilicon Hip06/Hip07 SoC.
>                         -----------
>                         | LPC host|
>                         |         |
>                         -----------
>                              |
>                 _____________V_______________LPC
>                   |                       |
>                   V                       V
>                                      ------------
>                                      |  BT(ipmi)|
>                                      ------------
>
> When master accesses those peripherals beneath the Hip06/Hip07 LPC, a specific
> LPC driver is needed to make LPC host generate the standard LPC I/O cycles with
> the target peripherals'I/O port addresses. But on curent arm64 world, there is
> no real I/O accesses. All the I/O operations through in/out pair are based on
> MMIO which is not satisfied the I/O mechanism on Hip06/Hip07 LPC.
> To solve this issue and keep the relevant existing peripherals' driver
> untouched, this patchset implements:
>   - introduces a generic I/O space management framwork, LIBIO, to support I/O
>     operations of both MMIO buses and the host controllers which access their
>     peripherals with host local I/O addresses;
>   - redefines the in/out accessors to provide unified interfaces for MMIO and
>     legacy I/O. Based on the LIBIO, the calling of in/out() from upper-layer
>     drivers, such as ipmi-si, will be redirected to the corresponding
>     device-specific I/O hooks to perfrom the I/O accesses.
> Based on this patch-set, all the I/O accesses to Hip06/Hip07 LPC peripherals
> can be supported without any changes on the existing ipmi-si driver.

Thanks for reposting this. I have a few high-level comments first, based on
the walk through the code I did with Gabriele and John last week:

- I think the libio framework is more generic than it needs to be, but as
  Alex really liked it this way and it was done like this based on his earlier
  comments, I think that's ok.

- after we went back and forth on the ACPI implementation, we concluded
  that it is correct to do the same as on DT and completely abstract the
  number space for I/O ports. No code should rely on a Linux port number
  to have any particular relation to the physical address or the the address
  on a PCI or LPC bus.

- The name "libio" still needs to be changed, this is way too generic, as
  "I/O" can refer to many things in the kernel, and almost none of them
  are related to x86 programmed I/O ports in any way. My suggestion
  would be "generic_ioport", or possibly "libioport", "libpio" or "pci_io". Any
  of them would work for me, or someone else could come up with a better
  name that describes what it is.

- I'm pretty sure the current implementation is broken for the ioport_map
  function that tries to turn an IORESOURCE_IO number into a pointer.
  Forcing CONFIG_GENERIC_IOMAP on would solve this, but also
  make all MMIO operations slower, which we probably don't want.
  It's probably enough to add a check in ioport_map() to see if the range
  is mapped into a virtual address or not.

- We could simplify the lookup a bit by using the trick from arch/ia64
  of using an array instead of linked list for walking the port numbers.
  There, the upper bits of the port number refer to an address space
  number while the lower bits refer to the bus address within that
  address space. This should work just as well as the current
  implementation but would be a little easier to understand. Maybe
  Bjorn can comment on this too, as I think he was involved with the
  ia64 implementation.

      Arnd

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 0/7] LPC: legacy ISA I/O support
  2017-03-14  8:39 ` [PATCH V7 0/7] LPC: legacy ISA I/O support Arnd Bergmann
@ 2017-03-15  4:05   ` zhichang.yuan
  2017-03-15 13:23     ` Arnd Bergmann
  0 siblings, 1 reply; 24+ messages in thread
From: zhichang.yuan @ 2017-03-15  4:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, Rafael Wysocki, Mark Rutland, rjw, Linux ARM,
	ACPI Devel Maling List, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List, linuxarm,
	devicetree, linux-pci, linux-serial, Corey Minyard, liviu.dudau,
	Zou Rongrong, John Garry, Gabriele Paoloni, zhichang.yuan02,
	kantyzc, Wei Xu

Hi, Arnd,

Many thanks for your review!

On 2017/3/14 16:39, Arnd Bergmann wrote:
> On Mon, Mar 13, 2017 at 3:42 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> This patchset supports the IPMI-bt device attached to the Low-Pin-Count
>> interface implemented on Hisilicon Hip06/Hip07 SoC.
>>                         -----------
>>                         | LPC host|
>>                         |         |
>>                         -----------
>>                              |
>>                 _____________V_______________LPC
>>                   |                       |
>>                   V                       V
>>                                      ------------
>>                                      |  BT(ipmi)|
>>                                      ------------
>>
>> When master accesses those peripherals beneath the Hip06/Hip07 LPC, a specific
>> LPC driver is needed to make LPC host generate the standard LPC I/O cycles with
>> the target peripherals'I/O port addresses. But on curent arm64 world, there is
>> no real I/O accesses. All the I/O operations through in/out pair are based on
>> MMIO which is not satisfied the I/O mechanism on Hip06/Hip07 LPC.
>> To solve this issue and keep the relevant existing peripherals' driver
>> untouched, this patchset implements:
>>   - introduces a generic I/O space management framwork, LIBIO, to support I/O
>>     operations of both MMIO buses and the host controllers which access their
>>     peripherals with host local I/O addresses;
>>   - redefines the in/out accessors to provide unified interfaces for MMIO and
>>     legacy I/O. Based on the LIBIO, the calling of in/out() from upper-layer
>>     drivers, such as ipmi-si, will be redirected to the corresponding
>>     device-specific I/O hooks to perfrom the I/O accesses.
>> Based on this patch-set, all the I/O accesses to Hip06/Hip07 LPC peripherals
>> can be supported without any changes on the existing ipmi-si driver.
> 
> Thanks for reposting this. I have a few high-level comments first, based on
> the walk through the code I did with Gabriele and John last week:
> 
> - I think the libio framework is more generic than it needs to be, but as
>   Alex really liked it this way and it was done like this based on his earlier
>   comments, I think that's ok.
> 
> - after we went back and forth on the ACPI implementation, we concluded
>   that it is correct to do the same as on DT and completely abstract the
>   number space for I/O ports. No code should rely on a Linux port number
>   to have any particular relation to the physical address or the the address
>   on a PCI or LPC bus.
Thanks again for your helps in Linaro Connect!
I think we are heading for this direction, is it?

> 
> - The name "libio" still needs to be changed, this is way too generic, as
>   "I/O" can refer to many things in the kernel, and almost none of them
>   are related to x86 programmed I/O ports in any way. My suggestion
>   would be "generic_ioport", or possibly "libioport", "libpio" or "pci_io". Any
>   of them would work for me, or someone else could come up with a better
>   name that describes what it is.

Ok. We will make a better name:)

> 
> - I'm pretty sure the current implementation is broken for the ioport_map
>   function that tries to turn an IORESOURCE_IO number into a pointer.
>   Forcing CONFIG_GENERIC_IOMAP on would solve this, but also
>   make all MMIO operations slower, which we probably don't want.
>   It's probably enough to add a check in ioport_map() to see if the range
>   is mapped into a virtual address or not.


Yes, I think our LIBIO will break the ioport_map() at this moment.
I try to solve this issue. Could you help to check the following ideas?
I am not deeper understanding the whole I/O framework, the following maybe not correct:(

ioport_map seems architecture-dependent. For our LIBIO, we don't want to replace the existing I/O
frameworks which support MMIO at this moment. Can we add these two revise to solve this issue?
1) Make LIBIO only target for non GENERIC_IOMAP platforms

config LIBIO
        bool "Generic logical IO management"
        depends on !GENERIC_IOMAP
        def_bool y if PCI && (ARC || MN10300 || UNICORE32 || SPARC || MICROBLAZE || S390 || AVR32 || CRIS || BLACKFIN || XTENSA || ARM64)

2) Modify the ioport_map() defined in asm-generic/io.h
Add the checks to identify the input 'port' is MMIO, otherwise, return NULL;

Then is it enough to avoid the negative effect on the existing I/O framework?

> 
> - We could simplify the lookup a bit by using the trick from arch/ia64
>   of using an array instead of linked list for walking the port numbers.
>   There, the upper bits of the port number refer to an address space
>   number while the lower bits refer to the bus address within that
>   address space. This should work just as well as the current
>   implementation but would be a little easier to understand. Maybe
>   Bjorn can comment on this too, as I think he was involved with the
>   ia64 implementation.
> 
Yes, It will be more efficient.

But the issue remained here is still how to coexist with the existing I/O frameworks.
I will continue to look into.

Thanks,
Zhichang

>       Arnd
> 
> .
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 0/7] LPC: legacy ISA I/O support
  2017-03-15  4:05   ` zhichang.yuan
@ 2017-03-15 13:23     ` Arnd Bergmann
  0 siblings, 0 replies; 24+ messages in thread
From: Arnd Bergmann @ 2017-03-15 13:23 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, Rafael Wysocki, Mark Rutland, rjw, Linux ARM,
	ACPI Devel Maling List, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List, linuxarm,
	devicetree, linux-pci, linux-serial, Corey Minyard, liviu.dudau,
	Zou Rongrong, John Garry, Gabriele Paoloni, zhichang.yuan02,
	kantyzc, Wei Xu

On Wed, Mar 15, 2017 at 5:05 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
>> - I think the libio framework is more generic than it needs to be, but as
>>   Alex really liked it this way and it was done like this based on his earlier
>>   comments, I think that's ok.
>>
>> - after we went back and forth on the ACPI implementation, we concluded
>>   that it is correct to do the same as on DT and completely abstract the
>>   number space for I/O ports. No code should rely on a Linux port number
>>   to have any particular relation to the physical address or the the address
>>   on a PCI or LPC bus.
> Thanks again for your helps in Linaro Connect!
> I think we are heading for this direction, is it?

Yes, I think so.

>> - I'm pretty sure the current implementation is broken for the ioport_map
>>   function that tries to turn an IORESOURCE_IO number into a pointer.
>>   Forcing CONFIG_GENERIC_IOMAP on would solve this, but also
>>   make all MMIO operations slower, which we probably don't want.
>>   It's probably enough to add a check in ioport_map() to see if the range
>>   is mapped into a virtual address or not.
>
>
> Yes, I think our LIBIO will break the ioport_map() at this moment.
> I try to solve this issue. Could you help to check the following ideas?
> I am not deeper understanding the whole I/O framework, the following maybe not correct:(
>
> ioport_map seems architecture-dependent. For our LIBIO, we don't want to replace the existing I/O
> frameworks which support MMIO at this moment. Can we add these two revise to solve this issue?
> 1) Make LIBIO only target for non GENERIC_IOMAP platforms
>
> config LIBIO
>         bool "Generic logical IO management"
>         depends on !GENERIC_IOMAP

I don't think there is even a problem with GENERIC_IOMAP: If both are
set, passing a low number as a pointer will turn an ioread32() into an
inl(), which is implemented by libio.

>         def_bool y if PCI && (ARC || MN10300 || UNICORE32 || SPARC || MICROBLAZE || S390 || AVR32 || CRIS || BLACKFIN || XTENSA || ARM64)

I think most of these architectures just use their own inb/outb functions,
and should not use libio at all.

It's also possible that they use an older way of mapping I/O ports by calling
ioremap() on the physical address and treating the pointer as a 32-bit
I/O port number (relying on the PCI_IOBASE=0 default). Architectures doing
that might have other issues with libio, and I wouldn't try converting those.

> 2) Modify the ioport_map() defined in asm-generic/io.h
> Add the checks to identify the input 'port' is MMIO, otherwise, return NULL;

This seems fine.

>> - We could simplify the lookup a bit by using the trick from arch/ia64
>>   of using an array instead of linked list for walking the port numbers.
>>   There, the upper bits of the port number refer to an address space
>>   number while the lower bits refer to the bus address within that
>>   address space. This should work just as well as the current
>>   implementation but would be a little easier to understand. Maybe
>>   Bjorn can comment on this too, as I think he was involved with the
>>   ia64 implementation.
>>
> Yes, It will be more efficient.
>
> But the issue remained here is still how to coexist with the existing I/O frameworks.
> I will continue to look into.

Ok. Let's wait for Bjorn to reply on this idea before you spend too much time
on this though.

      Arnd

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-13 21:24   ` Rafael J. Wysocki
  2017-03-14  8:14     ` Gabriele Paoloni
@ 2017-03-16  2:21     ` zhichang.yuan
  2017-03-16 10:13       ` Arnd Bergmann
  1 sibling, 1 reply; 24+ messages in thread
From: zhichang.yuan @ 2017-03-16  2:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, mark.rutland, arnd, linux-arm-kernel, linux-acpi,
	lorenzo.pieralisi, benh, linux-kernel, linuxarm, devicetree,
	linux-pci, linux-serial, minyard, liviu.dudau, zourongrong,
	john.garry, gabriele.paoloni, zhichang.yuan02, kantyzc, xuwei5

Hi, Rafael,

Thanks for your review!

On 2017/3/14 5:24, Rafael J. Wysocki wrote:
> On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
>> In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue on Asus
>> T100TA), the '_DEP' was supported to solve the dependency of Asus battery. But
>> this patch is specific to Asus battery device.
>> In the real world, there are other devices which need the dependency to play the
>> role on the enumeration order. For example, all the Hip06 LPC
>> periperals(IPMI-BT, uart, etc) must be scanned after the LPC host driver
>> finished the probing. So, it makes sense to add a checking whether the ACPI
>> device meet all the dependencies during its enumeration slot, if not, the
>> enumeration will be delayed till all dependency master finish their work.
>>
>> This patch adds the dependency checking in ACPI enumeration, also the
>> corresponding handling to retrigger the Hip06 LPC peripherals' scanning.
> 
> AFAICS, _DEP is generally abused in the wild and cannot be made generic.  Sorry.
> 

>From the ACPI specification, _DEP is for operation region accesses.
You are right...

How about we add a ACPI handler for our LPC bus?? Just like amba.
In this way, we also can solve the issue about LPC enumeration order.

Thanks,
Zhichang


> Thanks,
> Rafael
> 
> 
> .
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-16  2:21     ` zhichang.yuan
@ 2017-03-16 10:13       ` Arnd Bergmann
  2017-03-16 14:56         ` zhichang.yuan
  2017-03-16 16:13         ` Gabriele Paoloni
  0 siblings, 2 replies; 24+ messages in thread
From: Arnd Bergmann @ 2017-03-16 10:13 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Rafael Wysocki, Mark Rutland,
	Linux ARM, ACPI Devel Maling List, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List, linuxarm,
	devicetree, linux-pci, linux-serial, Corey Minyard, liviu.dudau,
	Zou Rongrong, John Garry, Gabriele Paoloni, zhichang.yuan02,
	kantyzc, Wei Xu

On Thu, Mar 16, 2017 at 3:21 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> Hi, Rafael,
>
> Thanks for your review!
>
> On 2017/3/14 5:24, Rafael J. Wysocki wrote:
>> On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
>>> In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue on Asus
>>> T100TA), the '_DEP' was supported to solve the dependency of Asus battery. But
>>> this patch is specific to Asus battery device.
>>> In the real world, there are other devices which need the dependency to play the
>>> role on the enumeration order. For example, all the Hip06 LPC
>>> periperals(IPMI-BT, uart, etc) must be scanned after the LPC host driver
>>> finished the probing. So, it makes sense to add a checking whether the ACPI
>>> device meet all the dependencies during its enumeration slot, if not, the
>>> enumeration will be delayed till all dependency master finish their work.
>>>
>>> This patch adds the dependency checking in ACPI enumeration, also the
>>> corresponding handling to retrigger the Hip06 LPC peripherals' scanning.
>>
>> AFAICS, _DEP is generally abused in the wild and cannot be made generic.  Sorry.
>>
>
> From the ACPI specification, _DEP is for operation region accesses.
> You are right...
>
> How about we add a ACPI handler for our LPC bus?? Just like amba.
> In this way, we also can solve the issue about LPC enumeration order.

As far as I can tell, PCI and LPC have exactly the same requirement here,
so whatever you end up doing for one should be used for the other as well.

      Arnd

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-16 10:13       ` Arnd Bergmann
@ 2017-03-16 14:56         ` zhichang.yuan
  2017-03-16 16:13         ` Gabriele Paoloni
  1 sibling, 0 replies; 24+ messages in thread
From: zhichang.yuan @ 2017-03-16 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Rafael Wysocki, Mark Rutland,
	Linux ARM, ACPI Devel Maling List, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List, linuxarm,
	devicetree, linux-pci, linux-serial, Corey Minyard, liviu.dudau,
	Zou Rongrong, John Garry, Gabriele Paoloni, kantyzc, Wei Xu

Hi, Arnd,



On 03/16/2017 06:13 PM, Arnd Bergmann wrote:
> On Thu, Mar 16, 2017 at 3:21 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> Hi, Rafael,
>>
>> Thanks for your review!
>>
>> On 2017/3/14 5:24, Rafael J. Wysocki wrote:
>>> On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
>>>> In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue on Asus
>>>> T100TA), the '_DEP' was supported to solve the dependency of Asus battery. But
>>>> this patch is specific to Asus battery device.
>>>> In the real world, there are other devices which need the dependency to play the
>>>> role on the enumeration order. For example, all the Hip06 LPC
>>>> periperals(IPMI-BT, uart, etc) must be scanned after the LPC host driver
>>>> finished the probing. So, it makes sense to add a checking whether the ACPI
>>>> device meet all the dependencies during its enumeration slot, if not, the
>>>> enumeration will be delayed till all dependency master finish their work.
>>>>
>>>> This patch adds the dependency checking in ACPI enumeration, also the
>>>> corresponding handling to retrigger the Hip06 LPC peripherals' scanning.
>>>
>>> AFAICS, _DEP is generally abused in the wild and cannot be made generic.  Sorry.
>>>
>>
>> From the ACPI specification, _DEP is for operation region accesses.
>> You are right...
>>
>> How about we add a ACPI handler for our LPC bus?? Just like amba.
>> In this way, we also can solve the issue about LPC enumeration order.
> 
> As far as I can tell, PCI and LPC have exactly the same requirement here,
> so whatever you end up doing for one should be used for the other as well.
> 

Thanks for your remind!

To some extend, our LPC is similar to PCI. We also need to setup the host
resources before scanning the children. For PCI, there is an ACPI handler of
pci_root_handler. Although our LPC is not so complicated and powerful as PCI(for
example, LPC can't probe downside devices), I think, we can still make LPC host
ready to work in its own ACPI handler callback....

Cheers,
Zhichang


>       Arnd
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-16 10:13       ` Arnd Bergmann
  2017-03-16 14:56         ` zhichang.yuan
@ 2017-03-16 16:13         ` Gabriele Paoloni
  2017-03-24  0:23           ` Gabriele Paoloni
  1 sibling, 1 reply; 24+ messages in thread
From: Gabriele Paoloni @ 2017-03-16 16:13 UTC (permalink / raw)
  To: Arnd Bergmann, Yuanzhichang
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Rafael Wysocki, Mark Rutland,
	Linux ARM, ACPI Devel Maling List, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List, Linuxarm,
	devicetree, linux-pci, linux-serial, Corey Minyard, liviu.dudau,
	Zou Rongrong, John Garry, zhichang.yuan02, kantyzc, xuwei (O)

Hi Arnd

> -----Original Message-----
> From: arndbergmann@gmail.com [mailto:arndbergmann@gmail.com] On Behalf
> Of Arnd Bergmann
> Sent: 16 March 2017 10:13
> To: Yuanzhichang
> Cc: Rafael J. Wysocki; Catalin Marinas; Will Deacon; Rob Herring; Frank
> Rowand; Bjorn Helgaas; Rafael Wysocki; Mark Rutland; Linux ARM; ACPI
> Devel Maling List; Lorenzo Pieralisi; Benjamin Herrenschmidt; Linux
> Kernel Mailing List; Linuxarm; devicetree@vger.kernel.org; linux-pci;
> linux-serial@vger.kernel.org; Corey Minyard; liviu.dudau@arm.com; Zou
> Rongrong; John Garry; Gabriele Paoloni; zhichang.yuan02@gmail.com;
> kantyzc@163.com; xuwei (O)
> Subject: Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices
> whose dependency has not met
> 
> On Thu, Mar 16, 2017 at 3:21 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
> > Hi, Rafael,
> >
> > Thanks for your review!
> >
> > On 2017/3/14 5:24, Rafael J. Wysocki wrote:
> >> On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
> >>> In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue
> on Asus
> >>> T100TA), the '_DEP' was supported to solve the dependency of Asus
> battery. But
> >>> this patch is specific to Asus battery device.
> >>> In the real world, there are other devices which need the
> dependency to play the
> >>> role on the enumeration order. For example, all the Hip06 LPC
> >>> periperals(IPMI-BT, uart, etc) must be scanned after the LPC host
> driver
> >>> finished the probing. So, it makes sense to add a checking whether
> the ACPI
> >>> device meet all the dependencies during its enumeration slot, if
> not, the
> >>> enumeration will be delayed till all dependency master finish their
> work.
> >>>
> >>> This patch adds the dependency checking in ACPI enumeration, also
> the
> >>> corresponding handling to retrigger the Hip06 LPC peripherals'
> scanning.
> >>
> >> AFAICS, _DEP is generally abused in the wild and cannot be made
> generic.  Sorry.
> >>
> >
> > From the ACPI specification, _DEP is for operation region accesses.
> > You are right...
> >
> > How about we add a ACPI handler for our LPC bus?? Just like amba.
> > In this way, we also can solve the issue about LPC enumeration order.
> 
> As far as I can tell, PCI and LPC have exactly the same requirement
> here,
> so whatever you end up doing for one should be used for the other as
> well.

Well as you know PCI has got his own handler, identified by his own
namespace id "PNP0A03".
Now when you say "you end up doing for one should be used for the other"
are you saying that we should introduce a new class of devices?
i.e. should we have an ACPI namespace identifier for non-PCI IO Host
Controllers?  

Otherwise, if my understanding is correct, having a specific new ACPI
handler for HiSilicon LPC would mean to adding another function_init()
in the list of acpi handlers inits in acpi_scan_init().

But then every vendor would declare his own one...is this really correct?

Many Thanks
Gab

> 
>       Arnd

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met
  2017-03-16 16:13         ` Gabriele Paoloni
@ 2017-03-24  0:23           ` Gabriele Paoloni
  0 siblings, 0 replies; 24+ messages in thread
From: Gabriele Paoloni @ 2017-03-24  0:23 UTC (permalink / raw)
  To: Gabriele Paoloni, Arnd Bergmann, Yuanzhichang
  Cc: Mark Rutland, Benjamin Herrenschmidt, Rafael Wysocki, linux-pci,
	Will Deacon, Linuxarm, Frank Rowand, Lorenzo Pieralisi,
	ACPI Devel Maling List, linux-serial, Catalin Marinas,
	devicetree, Corey Minyard, liviu.dudau, Rob Herring,
	Bjorn Helgaas, kantyzc, zhichang.yuan02, Linux ARM,
	Rafael J. Wysocki, Linux Kernel Mailing List, Zou Rongrong

Hi Arnd

> -----Original Message-----
> From: linuxarm-bounces@huawei.com [mailto:linuxarm-bounces@huawei.com]
> On Behalf Of Gabriele Paoloni
> Sent: 16 March 2017 16:14
> To: Arnd Bergmann; Yuanzhichang
> Cc: Mark Rutland; Benjamin Herrenschmidt; Rafael Wysocki; linux-pci;
> Will Deacon; Linuxarm; Frank Rowand; Lorenzo Pieralisi; ACPI Devel
> Maling List; linux-serial@vger.kernel.org; Catalin Marinas;
> devicetree@vger.kernel.org; Corey Minyard; liviu.dudau@arm.com; Rob
> Herring; Bjorn Helgaas; kantyzc@163.com; zhichang.yuan02@gmail.com;
> Linux ARM; Rafael J. Wysocki; Linux Kernel Mailing List; Zou Rongrong
> Subject: RE: [PATCH V7 5/7] ACPI: Delay the enumeration on the devices
> whose dependency has not met
> 
> Hi Arnd
> 
> > -----Original Message-----
> > From: arndbergmann@gmail.com [mailto:arndbergmann@gmail.com] On
> Behalf
> > Of Arnd Bergmann
> > Sent: 16 March 2017 10:13
> > To: Yuanzhichang
> > Cc: Rafael J. Wysocki; Catalin Marinas; Will Deacon; Rob Herring;
> Frank
> > Rowand; Bjorn Helgaas; Rafael Wysocki; Mark Rutland; Linux ARM; ACPI
> > Devel Maling List; Lorenzo Pieralisi; Benjamin Herrenschmidt; Linux
> > Kernel Mailing List; Linuxarm; devicetree@vger.kernel.org; linux-pci;
> > linux-serial@vger.kernel.org; Corey Minyard; liviu.dudau@arm.com; Zou
> > Rongrong; John Garry; Gabriele Paoloni; zhichang.yuan02@gmail.com;
> > kantyzc@163.com; xuwei (O)
> > Subject: Re: [PATCH V7 5/7] ACPI: Delay the enumeration on the
> devices
> > whose dependency has not met
> >
> > On Thu, Mar 16, 2017 at 3:21 AM, zhichang.yuan
> > <yuanzhichang@hisilicon.com> wrote:
> > > Hi, Rafael,
> > >
> > > Thanks for your review!
> > >
> > > On 2017/3/14 5:24, Rafael J. Wysocki wrote:
> > >> On Monday, March 13, 2017 10:42:41 AM zhichang.yuan wrote:
> > >>> In commit 40e7fcb1929(ACPI: Add _DEP support to fix battery issue
> > on Asus
> > >>> T100TA), the '_DEP' was supported to solve the dependency of Asus
> > battery. But
> > >>> this patch is specific to Asus battery device.
> > >>> In the real world, there are other devices which need the
> > dependency to play the
> > >>> role on the enumeration order. For example, all the Hip06 LPC
> > >>> periperals(IPMI-BT, uart, etc) must be scanned after the LPC host
> > driver
> > >>> finished the probing. So, it makes sense to add a checking
> whether
> > the ACPI
> > >>> device meet all the dependencies during its enumeration slot, if
> > not, the
> > >>> enumeration will be delayed till all dependency master finish
> their
> > work.
> > >>>
> > >>> This patch adds the dependency checking in ACPI enumeration, also
> > the
> > >>> corresponding handling to retrigger the Hip06 LPC peripherals'
> > scanning.
> > >>
> > >> AFAICS, _DEP is generally abused in the wild and cannot be made
> > generic.  Sorry.
> > >>
> > >
> > > From the ACPI specification, _DEP is for operation region accesses.
> > > You are right...
> > >
> > > How about we add a ACPI handler for our LPC bus?? Just like amba.
> > > In this way, we also can solve the issue about LPC enumeration
> order.
> >
> > As far as I can tell, PCI and LPC have exactly the same requirement
> > here,
> > so whatever you end up doing for one should be used for the other as
> > well.
> 
> Well as you know PCI has got his own handler, identified by his own
> namespace id "PNP0A03".
> Now when you say "you end up doing for one should be used for the
> other"
> are you saying that we should introduce a new class of devices?
> i.e. should we have an ACPI namespace identifier for non-PCI IO Host
> Controllers?
> 
> Otherwise, if my understanding is correct, having a specific new ACPI
> handler for HiSilicon LPC would mean to adding another function_init()
> in the list of acpi handlers inits in acpi_scan_init().
> 
> But then every vendor would declare his own one...is this really
> correct?

Do you have any feedback on this?

Otherwise I think that maybe we could consider moving back to the
arch_initcall approach as proposed in V6:
https://lkml.org/lkml/2017/1/24/28

Thanks
Gab

> 
> Many Thanks
> Gab
> 
> >
> >       Arnd
> _______________________________________________
> linuxarm mailing list
> linuxarm@huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH V7 2/7] PCI: Apply the new generic I/O management on PCI IO hosts
  2017-03-13  2:42 ` [PATCH V7 2/7] PCI: Apply the new generic I/O management on PCI IO hosts zhichang.yuan
@ 2017-03-27 19:46   ` dann frazier
  0 siblings, 0 replies; 24+ messages in thread
From: dann frazier @ 2017-03-27 19:46 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, frowand.list,
	Bjorn Helgaas, rafael, Mark Rutland, rjw, Arnd Bergmann,
	linux-arm-kernel, linux-acpi, lorenzo.pieralisi, benh,
	linux-kernel, linuxarm, devicetree, linux-pci, linux-serial,
	minyard, liviu.dudau, zourongrong, john.garry, gabriele.paoloni,
	zhichang.yuan02, kantyzc, xuwei5

On Sun, Mar 12, 2017 at 8:42 PM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> After introducing the new generic I/O space management(LIBIO), the original PCI
> MMIO relevant helpers need to be updated based on the new interfaces defined in
> LIBIO.
> This patch adapts the corresponding code to match the changes introduced by
> LIBIO.
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>        #earlier draft
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>       #drivers/pci parts
> ---
>  drivers/acpi/pci_root.c |  8 +++--
>  drivers/of/address.c    |  4 ++-
>  drivers/pci/pci.c       | 96 +++++++++++--------------------------------------
>  include/linux/pci.h     |  3 +-
>  4 files changed, 30 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
> index 919be0a..4d8cc24 100644
> --- a/drivers/acpi/pci_root.c
> +++ b/drivers/acpi/pci_root.c
> @@ -730,7 +730,8 @@ static void acpi_pci_root_validate_resources(struct device *dev,
>         }
>  }
>
> -static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
> +static void acpi_pci_root_remap_iospace(struct fwnode_handle *fwnode,
> +                       struct resource_entry *entry)
>  {
>  #ifdef PCI_IOBASE
>         struct resource *res = entry->res;
> @@ -739,7 +740,7 @@ static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
>         resource_size_t length = resource_size(res);
>         unsigned long port;
>
> -       if (pci_register_io_range(cpu_addr, length))
> +       if (pci_register_io_range(fwnode, cpu_addr, length))
>                 goto err;
>
>         port = pci_address_to_pio(cpu_addr);
> @@ -781,7 +782,8 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
>         else {
>                 resource_list_for_each_entry_safe(entry, tmp, list) {
>                         if (entry->res->flags & IORESOURCE_IO)
> -                               acpi_pci_root_remap_iospace(entry);
> +                               acpi_pci_root_remap_iospace(&device->fwnode,
> +                                               entry);
>
>                         if (entry->res->flags & IORESOURCE_DISABLED)
>                                 resource_list_destroy_entry(entry);
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 02b2903..fb5d16a 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -2,6 +2,7 @@
>  #define pr_fmt(fmt)    "OF: " fmt
>
>  #include <linux/device.h>
> +#include <linux/fwnode.h>
>  #include <linux/io.h>
>  #include <linux/ioport.h>
>  #include <linux/module.h>
> @@ -323,7 +324,8 @@ int of_pci_range_to_resource(struct of_pci_range *range,
>
>         if (res->flags & IORESOURCE_IO) {
>                 unsigned long port;
> -               err = pci_register_io_range(range->cpu_addr, range->size);
> +               err = pci_register_io_range(&np->fwnode, range->cpu_addr,
> +                               range->size);
>                 if (err)
>                         goto invalid_range;
>                 port = pci_address_to_pio(range->cpu_addr);
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 7904d02..079319f 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3238,65 +3238,37 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
>  }
>  EXPORT_SYMBOL(pci_request_regions_exclusive);
>
> -#ifdef PCI_IOBASE
> -struct io_range {
> -       struct list_head list;
> -       phys_addr_t start;
> -       resource_size_t size;
> -};
> -
> -static LIST_HEAD(io_range_list);
> -static DEFINE_SPINLOCK(io_range_lock);
> -#endif
> -
>  /*
>   * Record the PCI IO range (expressed as CPU physical address + size).
>   * Return a negative value if an error has occured, zero otherwise
>   */
> -int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
> +int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
> +                       resource_size_t size)
>  {
>         int err = 0;
>
>  #ifdef PCI_IOBASE
> -       struct io_range *range;
> -       resource_size_t allocated_size = 0;
> -
> -       /* check if the range hasn't been previously recorded */
> -       spin_lock(&io_range_lock);
> -       list_for_each_entry(range, &io_range_list, list) {
> -               if (addr >= range->start && addr + size <= range->start + size) {
> -                       /* range already registered, bail out */
> -                       goto end_register;
> -               }
> -               allocated_size += range->size;
> -       }
> -
> -       /* range not registed yet, check for available space */
> -       if (allocated_size + size - 1 > IO_SPACE_LIMIT) {
> -               /* if it's too big check if 64K space can be reserved */
> -               if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) {
> -                       err = -E2BIG;
> -                       goto end_register;
> -               }
> +       struct libio_range *range, *tmprange;
>
> -               size = SZ_64K;
> -               pr_warn("Requested IO range too big, new size set to 64K\n");
> -       }
> +       if (!size || addr + size < addr)
> +               return -EINVAL;
>
> -       /* add the range to the list */
> -       range = kzalloc(sizeof(*range), GFP_ATOMIC);
> -       if (!range) {
> -               err = -ENOMEM;
> -               goto end_register;
> -       }
> +       WARN_ON(!PAGE_ALIGNED(addr) || !PAGE_ALIGNED(size));
>
> -       range->start = addr;
> +       range = kzalloc(sizeof(*range), GFP_KERNEL);
> +       if (!range)
> +               return -ENOMEM;
> +       range->node = fwnode;
> +       range->flags = IO_CPU_MMIO;
>         range->size = size;
> +       range->hw_start = addr;
>
> -       list_add_tail(&range->list, &io_range_list);
> -
> -end_register:
> -       spin_unlock(&io_range_lock);
> +       tmprange = register_libio_range(range);
> +       if (tmprange != range) {
> +               kfree(range);
> +               if (!IS_ERR(tmprange))
> +                       err = 0;
> +       }
>  #endif
>
>         return err;
> @@ -3307,21 +3279,10 @@ phys_addr_t pci_pio_to_address(unsigned long pio)
>         phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
>
>  #ifdef PCI_IOBASE
> -       struct io_range *range;
> -       resource_size_t allocated_size = 0;
> -
>         if (pio > IO_SPACE_LIMIT)
>                 return address;
>
> -       spin_lock(&io_range_lock);
> -       list_for_each_entry(range, &io_range_list, list) {
> -               if (pio >= allocated_size && pio < allocated_size + range->size) {
> -                       address = range->start + pio - allocated_size;
> -                       break;
> -               }
> -               allocated_size += range->size;
> -       }
> -       spin_unlock(&io_range_lock);
> +       address = libio_to_hwaddr(pio);
>  #endif
>
>         return address;
> @@ -3330,25 +3291,8 @@ phys_addr_t pci_pio_to_address(unsigned long pio)
>  unsigned long __weak pci_address_to_pio(phys_addr_t address)
>  {
>  #ifdef PCI_IOBASE
> -       struct io_range *res;
> -       resource_size_t offset = 0;
> -       unsigned long addr = -1;
> -
> -       spin_lock(&io_range_lock);
> -       list_for_each_entry(res, &io_range_list, list) {
> -               if (address >= res->start && address < res->start + res->size) {
> -                       addr = address - res->start + offset;
> -                       break;
> -               }
> -               offset += res->size;
> -       }
> -       spin_unlock(&io_range_lock);
> -
> -       return addr;
> +       return libio_translate_cpuaddr(address);
>  #else
> -       if (address > IO_SPACE_LIMIT)
> -               return (unsigned long)-1;
> -
>         return (unsigned long) address;
>  #endif
>  }

fyi, this fails to build if PCI_IOBASE is defined and CONFIG_LIBIO=n:

drivers/built-in.o: In function `pci_register_io_range':
/home/ubuntu/linux-4.10.0/drivers/pci/pci.c:3266: undefined reference
to `register_libio_range'
drivers/built-in.o: In function `pci_pio_to_address':
/home/ubuntu/linux-4.10.0/drivers/pci/pci.c:3285: undefined reference
to `libio_to_hwaddr'
drivers/built-in.o: In function `pci_address_to_pio':
/home/ubuntu/linux-4.10.0/drivers/pci/pci.c:3294: undefined reference
to `libio_translate_cpuaddr'

  -dann

> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index eb3da1a..6401327 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1194,7 +1194,8 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
>                         void *alignf_data);
>
>
> -int pci_register_io_range(phys_addr_t addr, resource_size_t size);
> +int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
> +                       resource_size_t size);
>  unsigned long pci_address_to_pio(phys_addr_t addr);
>  phys_addr_t pci_pio_to_address(unsigned long pio);
>  int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2017-03-27 19:46 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-13  2:42 [PATCH V7 0/7] LPC: legacy ISA I/O support zhichang.yuan
2017-03-13  2:42 ` [PATCH V7 1/7] LIBIO: Introduce a generic PIO mapping method zhichang.yuan
2017-03-13  2:42 ` [PATCH V7 2/7] PCI: Apply the new generic I/O management on PCI IO hosts zhichang.yuan
2017-03-27 19:46   ` dann frazier
2017-03-13  2:42 ` [PATCH V7 3/7] OF: Add missing I/O range exception for indirect-IO devices zhichang.yuan
2017-03-13  2:42 ` [PATCH V7 4/7] LPC: Support the device-tree LPC host on Hip06/Hip07 zhichang.yuan
2017-03-13  2:42 ` [PATCH V7 5/7] ACPI: Delay the enumeration on the devices whose dependency has not met zhichang.yuan
2017-03-13 21:24   ` Rafael J. Wysocki
2017-03-14  8:14     ` Gabriele Paoloni
2017-03-16  2:21     ` zhichang.yuan
2017-03-16 10:13       ` Arnd Bergmann
2017-03-16 14:56         ` zhichang.yuan
2017-03-16 16:13         ` Gabriele Paoloni
2017-03-24  0:23           ` Gabriele Paoloni
2017-03-14  5:11   ` kbuild test robot
2017-03-14  6:10   ` kbuild test robot
2017-03-13  2:42 ` [PATCH V7 6/7] LIBIO: Support the dynamically logical PIO registration of ACPI host I/O zhichang.yuan
2017-03-14  4:27   ` kbuild test robot
2017-03-14  5:10   ` kbuild test robot
2017-03-13  2:42 ` [PATCH V7 7/7] LPC: Add the ACPI LPC support zhichang.yuan
2017-03-14  5:25   ` kbuild test robot
2017-03-14  8:39 ` [PATCH V7 0/7] LPC: legacy ISA I/O support Arnd Bergmann
2017-03-15  4:05   ` zhichang.yuan
2017-03-15 13:23     ` Arnd Bergmann

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).