All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-30 15:26 ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 V7:
  - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
  - Improved the mapping process in LOGIC_PIO to gain better efficiency when
    redirecting the I/O accesses to right device driver;
  - To reduce the impact on PCI MMIO to a minimum, add a new
    CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
  - Added a new ACPI handler for indirect-IO hosts/devices;
  - Fixed the compile issues on V6; 

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;

V7 thread here: https://lkml.org/lkml/2017/3/12/279
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 (6):
  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: Support the probing on the devices which apply indirect-IO
  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/Makefile                              |   1 +
 drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
 drivers/acpi/internal.h                            |   5 +
 drivers/acpi/pci_root.c                            |   8 +-
 drivers/acpi/scan.c                                |   1 +
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
 drivers/of/address.c                               |  95 +++-
 drivers/pci/pci.c                                  | 104 +---
 include/asm-generic/io.h                           |  50 ++
 include/linux/logic_pio.h                          | 174 +++++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  26 +
 lib/Makefile                                       |   2 +
 lib/logic_pio.c                                    | 413 ++++++++++++++++
 22 files changed, 1758 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/acpi/acpi_indirectio.c
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

-- 
1.9.1

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

* [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-30 15:26 ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 V7:
  - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
  - Improved the mapping process in LOGIC_PIO to gain better efficiency when
    redirecting the I/O accesses to right device driver;
  - To reduce the impact on PCI MMIO to a minimum, add a new
    CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
  - Added a new ACPI handler for indirect-IO hosts/devices;
  - Fixed the compile issues on V6; 

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;

V7 thread here: https://lkml.org/lkml/2017/3/12/279
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 (6):
  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: Support the probing on the devices which apply indirect-IO
  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/Makefile                              |   1 +
 drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
 drivers/acpi/internal.h                            |   5 +
 drivers/acpi/pci_root.c                            |   8 +-
 drivers/acpi/scan.c                                |   1 +
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
 drivers/of/address.c                               |  95 +++-
 drivers/pci/pci.c                                  | 104 +---
 include/asm-generic/io.h                           |  50 ++
 include/linux/logic_pio.h                          | 174 +++++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  26 +
 lib/Makefile                                       |   2 +
 lib/logic_pio.c                                    | 413 ++++++++++++++++
 22 files changed, 1758 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/acpi/acpi_indirectio.c
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

-- 
1.9.1

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

* [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-30 15:26 ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

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 V7:
  - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
  - Improved the mapping process in LOGIC_PIO to gain better efficiency when
    redirecting the I/O accesses to right device driver;
  - To reduce the impact on PCI MMIO to a minimum, add a new
    CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
  - Added a new ACPI handler for indirect-IO hosts/devices;
  - Fixed the compile issues on V6; 

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;

V7 thread here: https://lkml.org/lkml/2017/3/12/279
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 (6):
  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: Support the probing on the devices which apply indirect-IO
  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/Makefile                              |   1 +
 drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
 drivers/acpi/internal.h                            |   5 +
 drivers/acpi/pci_root.c                            |   8 +-
 drivers/acpi/scan.c                                |   1 +
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
 drivers/of/address.c                               |  95 +++-
 drivers/pci/pci.c                                  | 104 +---
 include/asm-generic/io.h                           |  50 ++
 include/linux/logic_pio.h                          | 174 +++++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  26 +
 lib/Makefile                                       |   2 +
 lib/logic_pio.c                                    | 413 ++++++++++++++++
 22 files changed, 1758 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/acpi/acpi_indirectio.c
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

-- 
1.9.1

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
  2017-03-30 15:26 ` zhichang.yuan
  (?)
  (?)
@ 2017-03-30 15:26   ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, devicetree, lorenzo.pieralisi, gabriele.paoloni,
	minyard, benh, john.garry, linux-kernel, xuwei5, linuxarm,
	zhichang.yuan, linux-acpi, zourongrong, linux-pci, olof,
	zhichang.yuan02, kantyzc, brian.starkey

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 the logical PIO space with different logical/fake PIOs. After this,
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 in 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/logic_pio.h | 174 +++++++++++++++++++
 lib/Kconfig               |  26 +++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 413 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ef015e..f7fbec3 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -351,6 +351,8 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #define IO_SPACE_LIMIT 0xffff
 #endif
 
+#include <linux/logic_pio.h>
+
 /*
  * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be
  * implemented on hardware that needs an additional delay for I/O accesses to
@@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
  */
 
 #ifndef inb
+#ifdef CONFIG_INDIRECT_PIO
+#define inb logic_inb
+#else
 #define inb inb
 static inline u8 inb(unsigned long addr)
 {
 	return readb(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inw
+#ifdef CONFIG_INDIRECT_PIO
+#define inw logic_inw
+#else
 #define inw inw
 static inline u16 inw(unsigned long addr)
 {
 	return readw(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inl
+#ifdef CONFIG_INDIRECT_PIO
+#define inl logic_inl
+#else
 #define inl inl
 static inline u32 inl(unsigned long addr)
 {
 	return readl(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outb
+#ifdef CONFIG_INDIRECT_PIO
+#define outb logic_outb
+#else
 #define outb outb
 static inline void outb(u8 value, unsigned long addr)
 {
 	writeb(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outw
+#ifdef CONFIG_INDIRECT_PIO
+#define outw logic_outw
+#else
 #define outw outw
 static inline void outw(u16 value, unsigned long addr)
 {
 	writew(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outl
+#ifdef CONFIG_INDIRECT_PIO
+#define outl logic_outl
+#else
 #define outl outl
 static inline void outl(u32 value, unsigned long addr)
 {
 	writel(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
  */
 
 #ifndef insb
+#ifdef CONFIG_INDIRECT_PIO
+#define insb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insw
+#ifdef CONFIG_INDIRECT_PIO
+#define insw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insl
+#ifdef CONFIG_INDIRECT_PIO
+#define insl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsb
+#ifdef CONFIG_INDIRECT_PIO
+#define outsb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsw
+#ifdef CONFIG_INDIRECT_PIO
+#define outsw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsl
+#ifdef CONFIG_INDIRECT_PIO
+#define outsl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insb_p
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..e9f5644
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,174 @@
+/*
+ * 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>
+
+/*
+ *		Total IO space is 0 to IO_SPACE_LIMIT
+ *
+ *    section			pio
+ * |________|________________________________________|
+ *
+ * In this division, the benefits are:
+ * 1) The MMIO PIO space is consecutive, then ioport_map() still works well
+ * for MMIO;
+ * 2) The search happened in inX/outX with input PIO will have better
+ * performance for indirect_IO. For MMIO, the performance is nearly same
+ * even when CONFIG_INDIRECT_PIO is enabled;
+ *
+ * Some notes:
+ * 1) Don't increase the IO_SPACE_LIMIT to avoid modification on so many
+ * architectural files;
+ * 2) To reduce the impact on the original I/O space to a minimum, we only
+ * apply this IO space division when CONFIG_INDIRECT_PIO is enabled; And
+ * only allocate the last section to INDIRECT_PIO, all the other PIO space are
+ * for MMIO;
+ * 3) For better efficiency, one more I/O segment can be separated from 'pio'
+ * bit section. But it will make the IO space size decreased. Won't apply at
+ * this moment;
+ */
+#ifdef CONFIG_INDIRECT_PIO
+#define PIO_SECT_BITS		2
+#else
+#define PIO_SECT_BITS		0
+#endif
+#define PIO_MAX_SECT		(0x01UL << PIO_SECT_BITS)
+#define PIO_SECT_MASK		(PIO_MAX_SECT - 1)
+
+/* The last section. */
+#define PIO_INDIRECT		(PIO_MAX_SECT - 1)
+/* This one is for MMIO(PCI) to keep compatibility */
+#define PIO_CPU_MMIO		0x00UL
+
+struct logic_pio_root {
+	struct list_head sec_head;
+	resource_size_t sec_min;
+	resource_size_t sec_max;
+};
+
+#if ((IO_SPACE_LIMIT + 1) & IO_SPACE_LIMIT)
+#error "(IO_SPACE_LIMIT + 1) must be power of 2!"
+#endif
+
+#define PIO_VAL_MASK		(IO_SPACE_LIMIT >> PIO_SECT_BITS)
+#define PIO_VAL_BIT_LEN		(ilog2(PIO_VAL_MASK) + 1)
+
+#define PIO_SECT_MIN(sec_id)	((sec_id) << PIO_VAL_BIT_LEN)
+#define PIO_SECT_MAX(sec_id)	(PIO_SECT_MIN(sec_id) | PIO_VAL_MASK)
+
+#define PIO_SECT_ID(pio)	((pio >> PIO_VAL_BIT_LEN) & PIO_SECT_MASK)
+
+struct logic_pio_sect {
+	struct list_head list;
+	resource_size_t io_start;
+
+	struct logic_pio_hwaddr *hwpeer;
+};
+#define to_pio_sect(node) container_of(node, struct logic_pio_sect, list)
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	struct logic_pio_sect *pio_peer;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+#define to_pio_hwaddr(node) container_of(node, struct logic_pio_hwaddr, list)
+
+struct hostio_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);
+};
+
+#ifdef CONFIG_INDIRECT_PIO
+#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
+#endif
+
+extern u8 logic_inb(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern u16 logic_inw(unsigned long addr);
+extern u32 logic_inl(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_outsb(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsw(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsl(unsigned long addr, const void *buffer,
+			unsigned int count);
+#ifdef CONFIG_LOGIC_PIO
+extern struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+extern unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr);
+#else
+static inline struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
+static inline unsigned long
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t hw_addr)
+{
+	return -1;
+}
+#endif
+
+/*
+ * These are used by pci. As LOGIC_PIO is bound with PCI, no need to add dummy
+ * functions for them.
+ */
+extern struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+	unsigned long align);
+
+extern resource_size_t logic_pio_to_hwaddr(unsigned long pio);
+
+extern unsigned long logic_pio_trans_cpuaddr(resource_size_t hw_addr);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LIBIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a..503c2e0 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,32 @@ config ARCH_USE_CMPXCHG_LOCKREF
 config ARCH_HAS_FAST_MULTIPLIER
 	bool
 
+config LOGIC_PIO
+	bool "Generic logical I/O management"
+	def_bool y if PCI && !X86 && !IA64 && !POWERPC
+	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 INDIRECT_PIO
+	bool "Access I/O in non-MMIO mode" if LOGIC_PIO
+	help
+	  On some platforms where no separate I/O space exist, there are I/O
+	  hosts which can not be accessed in MMIO mode. Based on LOGIC_PIO
+	  mechanism, the host-local I/O resource can be mapped into system
+	  logic PIO space shared with MMIO hosts, such as PCI/PCIE, then system
+	  can access the I/O devices with the mapped logic PIO through I/O
+	  accessors.
+	  This way has a little I/O performance cost. Please make sure your
+	  devices really need this configure item enabled.
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 320ac46a..26dcec0 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_LOGIC_PIO) += logic_pio.o
+
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/logic_pio.c b/lib/logic_pio.c
new file mode 100644
index 0000000..ca247e3
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,413 @@
+/*
+ * 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>
+
+/* The unique hardware address list. */
+static LIST_HEAD(io_range_list);
+static DEFINE_MUTEX(io_range_mutex);
+
+/*
+ * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
+ */
+static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
+#ifdef CONFIG_INDIRECT_PIO
+	/*
+	 * At this moment, assign all the other logic PIO space to MMIO.
+	 * If more elements added, please adjust the ending index and .sec_max;
+	 * Please keep MMIO element started from index ZERO.
+	 */
+	[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
+	},
+
+	/* The last element */
+	[PIO_INDIRECT] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
+	},
+#else
+	[PIO_CPU_MMIO] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
+	},
+
+#endif
+};
+
+/*
+ * 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 logic_pio_hwaddr *
+logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
+			resource_size_t start, resource_size_t end)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->fwnode != fwnode)
+			continue;
+		/* without any overlap with current range */
+		if (start >= range->hw_start + range->size ||
+			end < range->hw_start)
+			continue;
+		/* overlap is not supported now. */
+		if (start < range->hw_start ||
+			end >= range->hw_start + range->size)
+			return ERR_PTR(-EBUSY);
+		/* had been registered. */
+		return range;
+	}
+
+	return NULL;
+}
+
+
+static int logic_pio_alloc_range(struct logic_pio_root *root,
+		resource_size_t size, unsigned long align,
+		struct list_head **prev, resource_size_t *pio_alloc)
+{
+	struct logic_pio_sect *entry;
+	resource_size_t tmp_start;
+	resource_size_t idle_start, idle_end;
+
+	idle_start = root->sec_min;
+	*prev = &root->sec_head;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer ||
+			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 logic_pio_sect *next;
+
+			idle_start = entry->io_start + entry->hwpeer->size;
+			next = list_next_or_null_rcu(&root->sec_head,
+				&entry->list, struct logic_pio_sect, 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 + size <= idle_end) {
+			*prev = &entry->list;
+			*pio_alloc = idle_start;
+			return 0;
+		}
+
+nextentry:
+		idle_start = entry->io_start + entry->hwpeer->size;
+		*prev = &entry->list;
+	}
+	/* check the last free gap... */
+	idle_end = root->sec_max;
+
+	tmp_start = idle_start;
+	idle_start = ALIGN(idle_start, align);
+	if (idle_start >= tmp_start &&
+		idle_start + size <= idle_end) {
+		*pio_alloc = idle_start;
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*
+ * 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 logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+		unsigned long align)
+{
+	struct logic_pio_hwaddr *range;
+	struct logic_pio_sect *newsect;
+	resource_size_t pio_alloc;
+	struct list_head *prev, *hwprev;
+	unsigned long sect_id;
+	int err;
+
+	if (!newrange || !newrange->fwnode || !newrange->size)
+		return ERR_PTR(-EINVAL);
+
+	sect_id = newrange->flags;
+	if (sect_id >= PIO_MAX_SECT)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&io_range_mutex);
+	range = logic_pio_find_range_byaddr(newrange->fwnode,
+			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);
+		mutex_unlock(&io_range_mutex);
+		return range;
+	}
+
+	err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
+			newrange->size, align, &prev, &pio_alloc);
+	if (err) {
+		pr_err("can't find free %pa logical IO range!\n",
+			&newrange->size);
+		goto exitproc;
+	}
+
+	if (prev == &logic_pio_root_list[sect_id].sec_head) {
+		hwprev = &io_range_list;
+	} else {
+		newsect = to_pio_sect(prev);
+		hwprev = &newsect->hwpeer->list;
+	}
+
+	newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
+	if (!newsect) {
+		err = -ENOMEM;
+		goto exitproc;
+	}
+	newsect->io_start = pio_alloc;
+	newsect->hwpeer = newrange;
+	list_add_rcu(&newsect->list, prev);
+
+	newrange->pio_peer = newsect;
+	list_add_rcu(&newrange->list, hwprev);
+
+exitproc:
+	mutex_unlock(&io_range_mutex);
+	return err ? ERR_PTR(err) : newrange;
+}
+
+/*
+ * traverse the io_range_list to find the registered node whose device node
+ * and/or physical IO address match to.
+ */
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->fwnode == fwnode)
+			return range;
+	}
+	return NULL;
+}
+
+/*
+ * 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 logic_pio_to_hwaddr(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	/* The caller should check the section id is valid. */
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return pio - entry->io_start + entry->hwpeer->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
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = logic_pio_find_range_byaddr(fwnode, addr, addr);
+	if (!range)
+		return -1;
+
+	return addr - range->hw_start + range->pio_peer->io_start;
+}
+
+unsigned long
+logic_pio_trans_cpuaddr(resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->pio_peer->io_start;
+	}
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	if (pio < root->sec_min || pio > root->sec_max)
+		return NULL;
+	/*
+	 * non indirectIO section, no need to convert the addr. Jump to mmio ops
+	 * directly.
+	 */
+	if (&root->sec_head == &logic_pio_root_list[PIO_CPU_MMIO].sec_head)
+		return NULL;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return entry->hwpeer;
+	}
+
+	return NULL;
+}
+
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	struct logic_pio_hwaddr *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 logic_out##bw(type value, unsigned long addr)			\
+{									\
+	struct logic_pio_hwaddr *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 logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	struct logic_pio_hwaddr *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 logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	struct logic_pio_hwaddr *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_LOGIC_IO(b, u8)
+
+EXPORT_SYMBOL(logic_inb);
+EXPORT_SYMBOL(logic_outb);
+EXPORT_SYMBOL(logic_insb);
+EXPORT_SYMBOL(logic_outsb);
+
+BUILD_LOGIC_IO(w, u16)
+
+EXPORT_SYMBOL(logic_inw);
+EXPORT_SYMBOL(logic_outw);
+EXPORT_SYMBOL(logic_insw);
+EXPORT_SYMBOL(logic_outsw);
+
+BUILD_LOGIC_IO(l, u32)
+
+EXPORT_SYMBOL(logic_inl);
+EXPORT_SYMBOL(logic_outl);
+EXPORT_SYMBOL(logic_insl);
+EXPORT_SYMBOL(logic_outsl);
+#endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */
-- 
1.9.1

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 the logical PIO space with different logical/fake PIOs. After this,
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 in 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/logic_pio.h | 174 +++++++++++++++++++
 lib/Kconfig               |  26 +++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 413 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ef015e..f7fbec3 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -351,6 +351,8 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #define IO_SPACE_LIMIT 0xffff
 #endif
 
+#include <linux/logic_pio.h>
+
 /*
  * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be
  * implemented on hardware that needs an additional delay for I/O accesses to
@@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
  */
 
 #ifndef inb
+#ifdef CONFIG_INDIRECT_PIO
+#define inb logic_inb
+#else
 #define inb inb
 static inline u8 inb(unsigned long addr)
 {
 	return readb(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inw
+#ifdef CONFIG_INDIRECT_PIO
+#define inw logic_inw
+#else
 #define inw inw
 static inline u16 inw(unsigned long addr)
 {
 	return readw(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inl
+#ifdef CONFIG_INDIRECT_PIO
+#define inl logic_inl
+#else
 #define inl inl
 static inline u32 inl(unsigned long addr)
 {
 	return readl(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outb
+#ifdef CONFIG_INDIRECT_PIO
+#define outb logic_outb
+#else
 #define outb outb
 static inline void outb(u8 value, unsigned long addr)
 {
 	writeb(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outw
+#ifdef CONFIG_INDIRECT_PIO
+#define outw logic_outw
+#else
 #define outw outw
 static inline void outw(u16 value, unsigned long addr)
 {
 	writew(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outl
+#ifdef CONFIG_INDIRECT_PIO
+#define outl logic_outl
+#else
 #define outl outl
 static inline void outl(u32 value, unsigned long addr)
 {
 	writel(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
  */
 
 #ifndef insb
+#ifdef CONFIG_INDIRECT_PIO
+#define insb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insw
+#ifdef CONFIG_INDIRECT_PIO
+#define insw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insl
+#ifdef CONFIG_INDIRECT_PIO
+#define insl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsb
+#ifdef CONFIG_INDIRECT_PIO
+#define outsb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsw
+#ifdef CONFIG_INDIRECT_PIO
+#define outsw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsl
+#ifdef CONFIG_INDIRECT_PIO
+#define outsl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insb_p
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..e9f5644
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,174 @@
+/*
+ * 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>
+
+/*
+ *		Total IO space is 0 to IO_SPACE_LIMIT
+ *
+ *    section			pio
+ * |________|________________________________________|
+ *
+ * In this division, the benefits are:
+ * 1) The MMIO PIO space is consecutive, then ioport_map() still works well
+ * for MMIO;
+ * 2) The search happened in inX/outX with input PIO will have better
+ * performance for indirect_IO. For MMIO, the performance is nearly same
+ * even when CONFIG_INDIRECT_PIO is enabled;
+ *
+ * Some notes:
+ * 1) Don't increase the IO_SPACE_LIMIT to avoid modification on so many
+ * architectural files;
+ * 2) To reduce the impact on the original I/O space to a minimum, we only
+ * apply this IO space division when CONFIG_INDIRECT_PIO is enabled; And
+ * only allocate the last section to INDIRECT_PIO, all the other PIO space are
+ * for MMIO;
+ * 3) For better efficiency, one more I/O segment can be separated from 'pio'
+ * bit section. But it will make the IO space size decreased. Won't apply at
+ * this moment;
+ */
+#ifdef CONFIG_INDIRECT_PIO
+#define PIO_SECT_BITS		2
+#else
+#define PIO_SECT_BITS		0
+#endif
+#define PIO_MAX_SECT		(0x01UL << PIO_SECT_BITS)
+#define PIO_SECT_MASK		(PIO_MAX_SECT - 1)
+
+/* The last section. */
+#define PIO_INDIRECT		(PIO_MAX_SECT - 1)
+/* This one is for MMIO(PCI) to keep compatibility */
+#define PIO_CPU_MMIO		0x00UL
+
+struct logic_pio_root {
+	struct list_head sec_head;
+	resource_size_t sec_min;
+	resource_size_t sec_max;
+};
+
+#if ((IO_SPACE_LIMIT + 1) & IO_SPACE_LIMIT)
+#error "(IO_SPACE_LIMIT + 1) must be power of 2!"
+#endif
+
+#define PIO_VAL_MASK		(IO_SPACE_LIMIT >> PIO_SECT_BITS)
+#define PIO_VAL_BIT_LEN		(ilog2(PIO_VAL_MASK) + 1)
+
+#define PIO_SECT_MIN(sec_id)	((sec_id) << PIO_VAL_BIT_LEN)
+#define PIO_SECT_MAX(sec_id)	(PIO_SECT_MIN(sec_id) | PIO_VAL_MASK)
+
+#define PIO_SECT_ID(pio)	((pio >> PIO_VAL_BIT_LEN) & PIO_SECT_MASK)
+
+struct logic_pio_sect {
+	struct list_head list;
+	resource_size_t io_start;
+
+	struct logic_pio_hwaddr *hwpeer;
+};
+#define to_pio_sect(node) container_of(node, struct logic_pio_sect, list)
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	struct logic_pio_sect *pio_peer;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+#define to_pio_hwaddr(node) container_of(node, struct logic_pio_hwaddr, list)
+
+struct hostio_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);
+};
+
+#ifdef CONFIG_INDIRECT_PIO
+#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
+#endif
+
+extern u8 logic_inb(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern u16 logic_inw(unsigned long addr);
+extern u32 logic_inl(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_outsb(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsw(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsl(unsigned long addr, const void *buffer,
+			unsigned int count);
+#ifdef CONFIG_LOGIC_PIO
+extern struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+extern unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr);
+#else
+static inline struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
+static inline unsigned long
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t hw_addr)
+{
+	return -1;
+}
+#endif
+
+/*
+ * These are used by pci. As LOGIC_PIO is bound with PCI, no need to add dummy
+ * functions for them.
+ */
+extern struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+	unsigned long align);
+
+extern resource_size_t logic_pio_to_hwaddr(unsigned long pio);
+
+extern unsigned long logic_pio_trans_cpuaddr(resource_size_t hw_addr);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LIBIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a..503c2e0 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,32 @@ config ARCH_USE_CMPXCHG_LOCKREF
 config ARCH_HAS_FAST_MULTIPLIER
 	bool
 
+config LOGIC_PIO
+	bool "Generic logical I/O management"
+	def_bool y if PCI && !X86 && !IA64 && !POWERPC
+	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 INDIRECT_PIO
+	bool "Access I/O in non-MMIO mode" if LOGIC_PIO
+	help
+	  On some platforms where no separate I/O space exist, there are I/O
+	  hosts which can not be accessed in MMIO mode. Based on LOGIC_PIO
+	  mechanism, the host-local I/O resource can be mapped into system
+	  logic PIO space shared with MMIO hosts, such as PCI/PCIE, then system
+	  can access the I/O devices with the mapped logic PIO through I/O
+	  accessors.
+	  This way has a little I/O performance cost. Please make sure your
+	  devices really need this configure item enabled.
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 320ac46a..26dcec0 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_LOGIC_PIO) += logic_pio.o
+
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/logic_pio.c b/lib/logic_pio.c
new file mode 100644
index 0000000..ca247e3
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,413 @@
+/*
+ * 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>
+
+/* The unique hardware address list. */
+static LIST_HEAD(io_range_list);
+static DEFINE_MUTEX(io_range_mutex);
+
+/*
+ * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
+ */
+static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
+#ifdef CONFIG_INDIRECT_PIO
+	/*
+	 * At this moment, assign all the other logic PIO space to MMIO.
+	 * If more elements added, please adjust the ending index and .sec_max;
+	 * Please keep MMIO element started from index ZERO.
+	 */
+	[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
+	},
+
+	/* The last element */
+	[PIO_INDIRECT] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
+	},
+#else
+	[PIO_CPU_MMIO] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
+	},
+
+#endif
+};
+
+/*
+ * 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 logic_pio_hwaddr *
+logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
+			resource_size_t start, resource_size_t end)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->fwnode != fwnode)
+			continue;
+		/* without any overlap with current range */
+		if (start >= range->hw_start + range->size ||
+			end < range->hw_start)
+			continue;
+		/* overlap is not supported now. */
+		if (start < range->hw_start ||
+			end >= range->hw_start + range->size)
+			return ERR_PTR(-EBUSY);
+		/* had been registered. */
+		return range;
+	}
+
+	return NULL;
+}
+
+
+static int logic_pio_alloc_range(struct logic_pio_root *root,
+		resource_size_t size, unsigned long align,
+		struct list_head **prev, resource_size_t *pio_alloc)
+{
+	struct logic_pio_sect *entry;
+	resource_size_t tmp_start;
+	resource_size_t idle_start, idle_end;
+
+	idle_start = root->sec_min;
+	*prev = &root->sec_head;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer ||
+			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 logic_pio_sect *next;
+
+			idle_start = entry->io_start + entry->hwpeer->size;
+			next = list_next_or_null_rcu(&root->sec_head,
+				&entry->list, struct logic_pio_sect, 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 + size <= idle_end) {
+			*prev = &entry->list;
+			*pio_alloc = idle_start;
+			return 0;
+		}
+
+nextentry:
+		idle_start = entry->io_start + entry->hwpeer->size;
+		*prev = &entry->list;
+	}
+	/* check the last free gap... */
+	idle_end = root->sec_max;
+
+	tmp_start = idle_start;
+	idle_start = ALIGN(idle_start, align);
+	if (idle_start >= tmp_start &&
+		idle_start + size <= idle_end) {
+		*pio_alloc = idle_start;
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*
+ * 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 logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+		unsigned long align)
+{
+	struct logic_pio_hwaddr *range;
+	struct logic_pio_sect *newsect;
+	resource_size_t pio_alloc;
+	struct list_head *prev, *hwprev;
+	unsigned long sect_id;
+	int err;
+
+	if (!newrange || !newrange->fwnode || !newrange->size)
+		return ERR_PTR(-EINVAL);
+
+	sect_id = newrange->flags;
+	if (sect_id >= PIO_MAX_SECT)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&io_range_mutex);
+	range = logic_pio_find_range_byaddr(newrange->fwnode,
+			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);
+		mutex_unlock(&io_range_mutex);
+		return range;
+	}
+
+	err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
+			newrange->size, align, &prev, &pio_alloc);
+	if (err) {
+		pr_err("can't find free %pa logical IO range!\n",
+			&newrange->size);
+		goto exitproc;
+	}
+
+	if (prev == &logic_pio_root_list[sect_id].sec_head) {
+		hwprev = &io_range_list;
+	} else {
+		newsect = to_pio_sect(prev);
+		hwprev = &newsect->hwpeer->list;
+	}
+
+	newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
+	if (!newsect) {
+		err = -ENOMEM;
+		goto exitproc;
+	}
+	newsect->io_start = pio_alloc;
+	newsect->hwpeer = newrange;
+	list_add_rcu(&newsect->list, prev);
+
+	newrange->pio_peer = newsect;
+	list_add_rcu(&newrange->list, hwprev);
+
+exitproc:
+	mutex_unlock(&io_range_mutex);
+	return err ? ERR_PTR(err) : newrange;
+}
+
+/*
+ * traverse the io_range_list to find the registered node whose device node
+ * and/or physical IO address match to.
+ */
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->fwnode == fwnode)
+			return range;
+	}
+	return NULL;
+}
+
+/*
+ * 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 logic_pio_to_hwaddr(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	/* The caller should check the section id is valid. */
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return pio - entry->io_start + entry->hwpeer->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
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = logic_pio_find_range_byaddr(fwnode, addr, addr);
+	if (!range)
+		return -1;
+
+	return addr - range->hw_start + range->pio_peer->io_start;
+}
+
+unsigned long
+logic_pio_trans_cpuaddr(resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->pio_peer->io_start;
+	}
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	if (pio < root->sec_min || pio > root->sec_max)
+		return NULL;
+	/*
+	 * non indirectIO section, no need to convert the addr. Jump to mmio ops
+	 * directly.
+	 */
+	if (&root->sec_head == &logic_pio_root_list[PIO_CPU_MMIO].sec_head)
+		return NULL;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return entry->hwpeer;
+	}
+
+	return NULL;
+}
+
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	struct logic_pio_hwaddr *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 logic_out##bw(type value, unsigned long addr)			\
+{									\
+	struct logic_pio_hwaddr *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 logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	struct logic_pio_hwaddr *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 logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	struct logic_pio_hwaddr *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_LOGIC_IO(b, u8)
+
+EXPORT_SYMBOL(logic_inb);
+EXPORT_SYMBOL(logic_outb);
+EXPORT_SYMBOL(logic_insb);
+EXPORT_SYMBOL(logic_outsb);
+
+BUILD_LOGIC_IO(w, u16)
+
+EXPORT_SYMBOL(logic_inw);
+EXPORT_SYMBOL(logic_outw);
+EXPORT_SYMBOL(logic_insw);
+EXPORT_SYMBOL(logic_outsw);
+
+BUILD_LOGIC_IO(l, u32)
+
+EXPORT_SYMBOL(logic_inl);
+EXPORT_SYMBOL(logic_outl);
+EXPORT_SYMBOL(logic_insl);
+EXPORT_SYMBOL(logic_outsl);
+#endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */
-- 
1.9.1

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, devicetree, lorenzo.pieralisi, gabriele.paoloni,
	minyard, benh, john.garry, linux-kernel, xuwei5, linuxarm,
	zhichang.yuan, linux-acpi, zourongrong, linux-pci, olof,
	zhichang.yuan02, kantyzc, brian.starkey

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 the logical PIO space with different logical/fake PIOs. After this,
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 in 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/logic_pio.h | 174 +++++++++++++++++++
 lib/Kconfig               |  26 +++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 413 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ef015e..f7fbec3 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -351,6 +351,8 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #define IO_SPACE_LIMIT 0xffff
 #endif
 
+#include <linux/logic_pio.h>
+
 /*
  * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be
  * implemented on hardware that needs an additional delay for I/O accesses to
@@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
  */
 
 #ifndef inb
+#ifdef CONFIG_INDIRECT_PIO
+#define inb logic_inb
+#else
 #define inb inb
 static inline u8 inb(unsigned long addr)
 {
 	return readb(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inw
+#ifdef CONFIG_INDIRECT_PIO
+#define inw logic_inw
+#else
 #define inw inw
 static inline u16 inw(unsigned long addr)
 {
 	return readw(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inl
+#ifdef CONFIG_INDIRECT_PIO
+#define inl logic_inl
+#else
 #define inl inl
 static inline u32 inl(unsigned long addr)
 {
 	return readl(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outb
+#ifdef CONFIG_INDIRECT_PIO
+#define outb logic_outb
+#else
 #define outb outb
 static inline void outb(u8 value, unsigned long addr)
 {
 	writeb(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outw
+#ifdef CONFIG_INDIRECT_PIO
+#define outw logic_outw
+#else
 #define outw outw
 static inline void outw(u16 value, unsigned long addr)
 {
 	writew(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outl
+#ifdef CONFIG_INDIRECT_PIO
+#define outl logic_outl
+#else
 #define outl outl
 static inline void outl(u32 value, unsigned long addr)
 {
 	writel(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
  */
 
 #ifndef insb
+#ifdef CONFIG_INDIRECT_PIO
+#define insb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insw
+#ifdef CONFIG_INDIRECT_PIO
+#define insw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insl
+#ifdef CONFIG_INDIRECT_PIO
+#define insl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsb
+#ifdef CONFIG_INDIRECT_PIO
+#define outsb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsw
+#ifdef CONFIG_INDIRECT_PIO
+#define outsw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsl
+#ifdef CONFIG_INDIRECT_PIO
+#define outsl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insb_p
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..e9f5644
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,174 @@
+/*
+ * 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>
+
+/*
+ *		Total IO space is 0 to IO_SPACE_LIMIT
+ *
+ *    section			pio
+ * |________|________________________________________|
+ *
+ * In this division, the benefits are:
+ * 1) The MMIO PIO space is consecutive, then ioport_map() still works well
+ * for MMIO;
+ * 2) The search happened in inX/outX with input PIO will have better
+ * performance for indirect_IO. For MMIO, the performance is nearly same
+ * even when CONFIG_INDIRECT_PIO is enabled;
+ *
+ * Some notes:
+ * 1) Don't increase the IO_SPACE_LIMIT to avoid modification on so many
+ * architectural files;
+ * 2) To reduce the impact on the original I/O space to a minimum, we only
+ * apply this IO space division when CONFIG_INDIRECT_PIO is enabled; And
+ * only allocate the last section to INDIRECT_PIO, all the other PIO space are
+ * for MMIO;
+ * 3) For better efficiency, one more I/O segment can be separated from 'pio'
+ * bit section. But it will make the IO space size decreased. Won't apply at
+ * this moment;
+ */
+#ifdef CONFIG_INDIRECT_PIO
+#define PIO_SECT_BITS		2
+#else
+#define PIO_SECT_BITS		0
+#endif
+#define PIO_MAX_SECT		(0x01UL << PIO_SECT_BITS)
+#define PIO_SECT_MASK		(PIO_MAX_SECT - 1)
+
+/* The last section. */
+#define PIO_INDIRECT		(PIO_MAX_SECT - 1)
+/* This one is for MMIO(PCI) to keep compatibility */
+#define PIO_CPU_MMIO		0x00UL
+
+struct logic_pio_root {
+	struct list_head sec_head;
+	resource_size_t sec_min;
+	resource_size_t sec_max;
+};
+
+#if ((IO_SPACE_LIMIT + 1) & IO_SPACE_LIMIT)
+#error "(IO_SPACE_LIMIT + 1) must be power of 2!"
+#endif
+
+#define PIO_VAL_MASK		(IO_SPACE_LIMIT >> PIO_SECT_BITS)
+#define PIO_VAL_BIT_LEN		(ilog2(PIO_VAL_MASK) + 1)
+
+#define PIO_SECT_MIN(sec_id)	((sec_id) << PIO_VAL_BIT_LEN)
+#define PIO_SECT_MAX(sec_id)	(PIO_SECT_MIN(sec_id) | PIO_VAL_MASK)
+
+#define PIO_SECT_ID(pio)	((pio >> PIO_VAL_BIT_LEN) & PIO_SECT_MASK)
+
+struct logic_pio_sect {
+	struct list_head list;
+	resource_size_t io_start;
+
+	struct logic_pio_hwaddr *hwpeer;
+};
+#define to_pio_sect(node) container_of(node, struct logic_pio_sect, list)
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	struct logic_pio_sect *pio_peer;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+#define to_pio_hwaddr(node) container_of(node, struct logic_pio_hwaddr, list)
+
+struct hostio_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);
+};
+
+#ifdef CONFIG_INDIRECT_PIO
+#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
+#endif
+
+extern u8 logic_inb(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern u16 logic_inw(unsigned long addr);
+extern u32 logic_inl(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_outsb(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsw(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsl(unsigned long addr, const void *buffer,
+			unsigned int count);
+#ifdef CONFIG_LOGIC_PIO
+extern struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+extern unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr);
+#else
+static inline struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
+static inline unsigned long
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t hw_addr)
+{
+	return -1;
+}
+#endif
+
+/*
+ * These are used by pci. As LOGIC_PIO is bound with PCI, no need to add dummy
+ * functions for them.
+ */
+extern struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+	unsigned long align);
+
+extern resource_size_t logic_pio_to_hwaddr(unsigned long pio);
+
+extern unsigned long logic_pio_trans_cpuaddr(resource_size_t hw_addr);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LIBIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a..503c2e0 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,32 @@ config ARCH_USE_CMPXCHG_LOCKREF
 config ARCH_HAS_FAST_MULTIPLIER
 	bool
 
+config LOGIC_PIO
+	bool "Generic logical I/O management"
+	def_bool y if PCI && !X86 && !IA64 && !POWERPC
+	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 INDIRECT_PIO
+	bool "Access I/O in non-MMIO mode" if LOGIC_PIO
+	help
+	  On some platforms where no separate I/O space exist, there are I/O
+	  hosts which can not be accessed in MMIO mode. Based on LOGIC_PIO
+	  mechanism, the host-local I/O resource can be mapped into system
+	  logic PIO space shared with MMIO hosts, such as PCI/PCIE, then system
+	  can access the I/O devices with the mapped logic PIO through I/O
+	  accessors.
+	  This way has a little I/O performance cost. Please make sure your
+	  devices really need this configure item enabled.
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 320ac46a..26dcec0 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_LOGIC_PIO) += logic_pio.o
+
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/logic_pio.c b/lib/logic_pio.c
new file mode 100644
index 0000000..ca247e3
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,413 @@
+/*
+ * 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>
+
+/* The unique hardware address list. */
+static LIST_HEAD(io_range_list);
+static DEFINE_MUTEX(io_range_mutex);
+
+/*
+ * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
+ */
+static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
+#ifdef CONFIG_INDIRECT_PIO
+	/*
+	 * At this moment, assign all the other logic PIO space to MMIO.
+	 * If more elements added, please adjust the ending index and .sec_max;
+	 * Please keep MMIO element started from index ZERO.
+	 */
+	[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
+	},
+
+	/* The last element */
+	[PIO_INDIRECT] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
+	},
+#else
+	[PIO_CPU_MMIO] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
+	},
+
+#endif
+};
+
+/*
+ * 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 logic_pio_hwaddr *
+logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
+			resource_size_t start, resource_size_t end)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->fwnode != fwnode)
+			continue;
+		/* without any overlap with current range */
+		if (start >= range->hw_start + range->size ||
+			end < range->hw_start)
+			continue;
+		/* overlap is not supported now. */
+		if (start < range->hw_start ||
+			end >= range->hw_start + range->size)
+			return ERR_PTR(-EBUSY);
+		/* had been registered. */
+		return range;
+	}
+
+	return NULL;
+}
+
+
+static int logic_pio_alloc_range(struct logic_pio_root *root,
+		resource_size_t size, unsigned long align,
+		struct list_head **prev, resource_size_t *pio_alloc)
+{
+	struct logic_pio_sect *entry;
+	resource_size_t tmp_start;
+	resource_size_t idle_start, idle_end;
+
+	idle_start = root->sec_min;
+	*prev = &root->sec_head;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer ||
+			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 logic_pio_sect *next;
+
+			idle_start = entry->io_start + entry->hwpeer->size;
+			next = list_next_or_null_rcu(&root->sec_head,
+				&entry->list, struct logic_pio_sect, 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 + size <= idle_end) {
+			*prev = &entry->list;
+			*pio_alloc = idle_start;
+			return 0;
+		}
+
+nextentry:
+		idle_start = entry->io_start + entry->hwpeer->size;
+		*prev = &entry->list;
+	}
+	/* check the last free gap... */
+	idle_end = root->sec_max;
+
+	tmp_start = idle_start;
+	idle_start = ALIGN(idle_start, align);
+	if (idle_start >= tmp_start &&
+		idle_start + size <= idle_end) {
+		*pio_alloc = idle_start;
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*
+ * 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 logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+		unsigned long align)
+{
+	struct logic_pio_hwaddr *range;
+	struct logic_pio_sect *newsect;
+	resource_size_t pio_alloc;
+	struct list_head *prev, *hwprev;
+	unsigned long sect_id;
+	int err;
+
+	if (!newrange || !newrange->fwnode || !newrange->size)
+		return ERR_PTR(-EINVAL);
+
+	sect_id = newrange->flags;
+	if (sect_id >= PIO_MAX_SECT)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&io_range_mutex);
+	range = logic_pio_find_range_byaddr(newrange->fwnode,
+			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);
+		mutex_unlock(&io_range_mutex);
+		return range;
+	}
+
+	err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
+			newrange->size, align, &prev, &pio_alloc);
+	if (err) {
+		pr_err("can't find free %pa logical IO range!\n",
+			&newrange->size);
+		goto exitproc;
+	}
+
+	if (prev == &logic_pio_root_list[sect_id].sec_head) {
+		hwprev = &io_range_list;
+	} else {
+		newsect = to_pio_sect(prev);
+		hwprev = &newsect->hwpeer->list;
+	}
+
+	newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
+	if (!newsect) {
+		err = -ENOMEM;
+		goto exitproc;
+	}
+	newsect->io_start = pio_alloc;
+	newsect->hwpeer = newrange;
+	list_add_rcu(&newsect->list, prev);
+
+	newrange->pio_peer = newsect;
+	list_add_rcu(&newrange->list, hwprev);
+
+exitproc:
+	mutex_unlock(&io_range_mutex);
+	return err ? ERR_PTR(err) : newrange;
+}
+
+/*
+ * traverse the io_range_list to find the registered node whose device node
+ * and/or physical IO address match to.
+ */
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->fwnode == fwnode)
+			return range;
+	}
+	return NULL;
+}
+
+/*
+ * 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 logic_pio_to_hwaddr(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	/* The caller should check the section id is valid. */
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return pio - entry->io_start + entry->hwpeer->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
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = logic_pio_find_range_byaddr(fwnode, addr, addr);
+	if (!range)
+		return -1;
+
+	return addr - range->hw_start + range->pio_peer->io_start;
+}
+
+unsigned long
+logic_pio_trans_cpuaddr(resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->pio_peer->io_start;
+	}
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	if (pio < root->sec_min || pio > root->sec_max)
+		return NULL;
+	/*
+	 * non indirectIO section, no need to convert the addr. Jump to mmio ops
+	 * directly.
+	 */
+	if (&root->sec_head == &logic_pio_root_list[PIO_CPU_MMIO].sec_head)
+		return NULL;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return entry->hwpeer;
+	}
+
+	return NULL;
+}
+
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	struct logic_pio_hwaddr *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 logic_out##bw(type value, unsigned long addr)			\
+{									\
+	struct logic_pio_hwaddr *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 logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	struct logic_pio_hwaddr *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 logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	struct logic_pio_hwaddr *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_LOGIC_IO(b, u8)
+
+EXPORT_SYMBOL(logic_inb);
+EXPORT_SYMBOL(logic_outb);
+EXPORT_SYMBOL(logic_insb);
+EXPORT_SYMBOL(logic_outsb);
+
+BUILD_LOGIC_IO(w, u16)
+
+EXPORT_SYMBOL(logic_inw);
+EXPORT_SYMBOL(logic_outw);
+EXPORT_SYMBOL(logic_insw);
+EXPORT_SYMBOL(logic_outsw);
+
+BUILD_LOGIC_IO(l, u32)
+
+EXPORT_SYMBOL(logic_inl);
+EXPORT_SYMBOL(logic_outl);
+EXPORT_SYMBOL(logic_insl);
+EXPORT_SYMBOL(logic_outsl);
+#endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */
-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

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 the logical PIO space with different logical/fake PIOs. After this,
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 in 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/logic_pio.h | 174 +++++++++++++++++++
 lib/Kconfig               |  26 +++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 413 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ef015e..f7fbec3 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -351,6 +351,8 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #define IO_SPACE_LIMIT 0xffff
 #endif
 
+#include <linux/logic_pio.h>
+
 /*
  * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be
  * implemented on hardware that needs an additional delay for I/O accesses to
@@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
  */
 
 #ifndef inb
+#ifdef CONFIG_INDIRECT_PIO
+#define inb logic_inb
+#else
 #define inb inb
 static inline u8 inb(unsigned long addr)
 {
 	return readb(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inw
+#ifdef CONFIG_INDIRECT_PIO
+#define inw logic_inw
+#else
 #define inw inw
 static inline u16 inw(unsigned long addr)
 {
 	return readw(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inl
+#ifdef CONFIG_INDIRECT_PIO
+#define inl logic_inl
+#else
 #define inl inl
 static inline u32 inl(unsigned long addr)
 {
 	return readl(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outb
+#ifdef CONFIG_INDIRECT_PIO
+#define outb logic_outb
+#else
 #define outb outb
 static inline void outb(u8 value, unsigned long addr)
 {
 	writeb(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outw
+#ifdef CONFIG_INDIRECT_PIO
+#define outw logic_outw
+#else
 #define outw outw
 static inline void outw(u16 value, unsigned long addr)
 {
 	writew(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outl
+#ifdef CONFIG_INDIRECT_PIO
+#define outl logic_outl
+#else
 #define outl outl
 static inline void outl(u32 value, unsigned long addr)
 {
 	writel(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
  */
 
 #ifndef insb
+#ifdef CONFIG_INDIRECT_PIO
+#define insb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insw
+#ifdef CONFIG_INDIRECT_PIO
+#define insw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insl
+#ifdef CONFIG_INDIRECT_PIO
+#define insl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsb
+#ifdef CONFIG_INDIRECT_PIO
+#define outsb logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsw
+#ifdef CONFIG_INDIRECT_PIO
+#define outsw logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef outsl
+#ifdef CONFIG_INDIRECT_PIO
+#define outsl logic_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_INDIRECT_PIO */
 #endif
 
 #ifndef insb_p
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..e9f5644
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,174 @@
+/*
+ * 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>
+
+/*
+ *		Total IO space is 0 to IO_SPACE_LIMIT
+ *
+ *    section			pio
+ * |________|________________________________________|
+ *
+ * In this division, the benefits are:
+ * 1) The MMIO PIO space is consecutive, then ioport_map() still works well
+ * for MMIO;
+ * 2) The search happened in inX/outX with input PIO will have better
+ * performance for indirect_IO. For MMIO, the performance is nearly same
+ * even when CONFIG_INDIRECT_PIO is enabled;
+ *
+ * Some notes:
+ * 1) Don't increase the IO_SPACE_LIMIT to avoid modification on so many
+ * architectural files;
+ * 2) To reduce the impact on the original I/O space to a minimum, we only
+ * apply this IO space division when CONFIG_INDIRECT_PIO is enabled; And
+ * only allocate the last section to INDIRECT_PIO, all the other PIO space are
+ * for MMIO;
+ * 3) For better efficiency, one more I/O segment can be separated from 'pio'
+ * bit section. But it will make the IO space size decreased. Won't apply at
+ * this moment;
+ */
+#ifdef CONFIG_INDIRECT_PIO
+#define PIO_SECT_BITS		2
+#else
+#define PIO_SECT_BITS		0
+#endif
+#define PIO_MAX_SECT		(0x01UL << PIO_SECT_BITS)
+#define PIO_SECT_MASK		(PIO_MAX_SECT - 1)
+
+/* The last section. */
+#define PIO_INDIRECT		(PIO_MAX_SECT - 1)
+/* This one is for MMIO(PCI) to keep compatibility */
+#define PIO_CPU_MMIO		0x00UL
+
+struct logic_pio_root {
+	struct list_head sec_head;
+	resource_size_t sec_min;
+	resource_size_t sec_max;
+};
+
+#if ((IO_SPACE_LIMIT + 1) & IO_SPACE_LIMIT)
+#error "(IO_SPACE_LIMIT + 1) must be power of 2!"
+#endif
+
+#define PIO_VAL_MASK		(IO_SPACE_LIMIT >> PIO_SECT_BITS)
+#define PIO_VAL_BIT_LEN		(ilog2(PIO_VAL_MASK) + 1)
+
+#define PIO_SECT_MIN(sec_id)	((sec_id) << PIO_VAL_BIT_LEN)
+#define PIO_SECT_MAX(sec_id)	(PIO_SECT_MIN(sec_id) | PIO_VAL_MASK)
+
+#define PIO_SECT_ID(pio)	((pio >> PIO_VAL_BIT_LEN) & PIO_SECT_MASK)
+
+struct logic_pio_sect {
+	struct list_head list;
+	resource_size_t io_start;
+
+	struct logic_pio_hwaddr *hwpeer;
+};
+#define to_pio_sect(node) container_of(node, struct logic_pio_sect, list)
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	struct logic_pio_sect *pio_peer;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+#define to_pio_hwaddr(node) container_of(node, struct logic_pio_hwaddr, list)
+
+struct hostio_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);
+};
+
+#ifdef CONFIG_INDIRECT_PIO
+#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
+#endif
+
+extern u8 logic_inb(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern u16 logic_inw(unsigned long addr);
+extern u32 logic_inl(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_outsb(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsw(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsl(unsigned long addr, const void *buffer,
+			unsigned int count);
+#ifdef CONFIG_LOGIC_PIO
+extern struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+extern unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr);
+#else
+static inline struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
+static inline unsigned long
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t hw_addr)
+{
+	return -1;
+}
+#endif
+
+/*
+ * These are used by pci. As LOGIC_PIO is bound with PCI, no need to add dummy
+ * functions for them.
+ */
+extern struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+	unsigned long align);
+
+extern resource_size_t logic_pio_to_hwaddr(unsigned long pio);
+
+extern unsigned long logic_pio_trans_cpuaddr(resource_size_t hw_addr);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LIBIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a..503c2e0 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,32 @@ config ARCH_USE_CMPXCHG_LOCKREF
 config ARCH_HAS_FAST_MULTIPLIER
 	bool
 
+config LOGIC_PIO
+	bool "Generic logical I/O management"
+	def_bool y if PCI && !X86 && !IA64 && !POWERPC
+	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 INDIRECT_PIO
+	bool "Access I/O in non-MMIO mode" if LOGIC_PIO
+	help
+	  On some platforms where no separate I/O space exist, there are I/O
+	  hosts which can not be accessed in MMIO mode. Based on LOGIC_PIO
+	  mechanism, the host-local I/O resource can be mapped into system
+	  logic PIO space shared with MMIO hosts, such as PCI/PCIE, then system
+	  can access the I/O devices with the mapped logic PIO through I/O
+	  accessors.
+	  This way has a little I/O performance cost. Please make sure your
+	  devices really need this configure item enabled.
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 320ac46a..26dcec0 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_LOGIC_PIO) += logic_pio.o
+
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/logic_pio.c b/lib/logic_pio.c
new file mode 100644
index 0000000..ca247e3
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,413 @@
+/*
+ * 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>
+
+/* The unique hardware address list. */
+static LIST_HEAD(io_range_list);
+static DEFINE_MUTEX(io_range_mutex);
+
+/*
+ * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
+ */
+static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
+#ifdef CONFIG_INDIRECT_PIO
+	/*
+	 * At this moment, assign all the other logic PIO space to MMIO.
+	 * If more elements added, please adjust the ending index and .sec_max;
+	 * Please keep MMIO element started from index ZERO.
+	 */
+	[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
+	},
+
+	/* The last element */
+	[PIO_INDIRECT] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
+	},
+#else
+	[PIO_CPU_MMIO] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
+	},
+
+#endif
+};
+
+/*
+ * 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 logic_pio_hwaddr *
+logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
+			resource_size_t start, resource_size_t end)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->fwnode != fwnode)
+			continue;
+		/* without any overlap with current range */
+		if (start >= range->hw_start + range->size ||
+			end < range->hw_start)
+			continue;
+		/* overlap is not supported now. */
+		if (start < range->hw_start ||
+			end >= range->hw_start + range->size)
+			return ERR_PTR(-EBUSY);
+		/* had been registered. */
+		return range;
+	}
+
+	return NULL;
+}
+
+
+static int logic_pio_alloc_range(struct logic_pio_root *root,
+		resource_size_t size, unsigned long align,
+		struct list_head **prev, resource_size_t *pio_alloc)
+{
+	struct logic_pio_sect *entry;
+	resource_size_t tmp_start;
+	resource_size_t idle_start, idle_end;
+
+	idle_start = root->sec_min;
+	*prev = &root->sec_head;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer ||
+			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 logic_pio_sect *next;
+
+			idle_start = entry->io_start + entry->hwpeer->size;
+			next = list_next_or_null_rcu(&root->sec_head,
+				&entry->list, struct logic_pio_sect, 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 + size <= idle_end) {
+			*prev = &entry->list;
+			*pio_alloc = idle_start;
+			return 0;
+		}
+
+nextentry:
+		idle_start = entry->io_start + entry->hwpeer->size;
+		*prev = &entry->list;
+	}
+	/* check the last free gap... */
+	idle_end = root->sec_max;
+
+	tmp_start = idle_start;
+	idle_start = ALIGN(idle_start, align);
+	if (idle_start >= tmp_start &&
+		idle_start + size <= idle_end) {
+		*pio_alloc = idle_start;
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*
+ * 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 logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+		unsigned long align)
+{
+	struct logic_pio_hwaddr *range;
+	struct logic_pio_sect *newsect;
+	resource_size_t pio_alloc;
+	struct list_head *prev, *hwprev;
+	unsigned long sect_id;
+	int err;
+
+	if (!newrange || !newrange->fwnode || !newrange->size)
+		return ERR_PTR(-EINVAL);
+
+	sect_id = newrange->flags;
+	if (sect_id >= PIO_MAX_SECT)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&io_range_mutex);
+	range = logic_pio_find_range_byaddr(newrange->fwnode,
+			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);
+		mutex_unlock(&io_range_mutex);
+		return range;
+	}
+
+	err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
+			newrange->size, align, &prev, &pio_alloc);
+	if (err) {
+		pr_err("can't find free %pa logical IO range!\n",
+			&newrange->size);
+		goto exitproc;
+	}
+
+	if (prev == &logic_pio_root_list[sect_id].sec_head) {
+		hwprev = &io_range_list;
+	} else {
+		newsect = to_pio_sect(prev);
+		hwprev = &newsect->hwpeer->list;
+	}
+
+	newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
+	if (!newsect) {
+		err = -ENOMEM;
+		goto exitproc;
+	}
+	newsect->io_start = pio_alloc;
+	newsect->hwpeer = newrange;
+	list_add_rcu(&newsect->list, prev);
+
+	newrange->pio_peer = newsect;
+	list_add_rcu(&newrange->list, hwprev);
+
+exitproc:
+	mutex_unlock(&io_range_mutex);
+	return err ? ERR_PTR(err) : newrange;
+}
+
+/*
+ * traverse the io_range_list to find the registered node whose device node
+ * and/or physical IO address match to.
+ */
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->fwnode == fwnode)
+			return range;
+	}
+	return NULL;
+}
+
+/*
+ * 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 logic_pio_to_hwaddr(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	/* The caller should check the section id is valid. */
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return pio - entry->io_start + entry->hwpeer->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
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = logic_pio_find_range_byaddr(fwnode, addr, addr);
+	if (!range)
+		return -1;
+
+	return addr - range->hw_start + range->pio_peer->io_start;
+}
+
+unsigned long
+logic_pio_trans_cpuaddr(resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->pio_peer->io_start;
+	}
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	if (pio < root->sec_min || pio > root->sec_max)
+		return NULL;
+	/*
+	 * non indirectIO section, no need to convert the addr. Jump to mmio ops
+	 * directly.
+	 */
+	if (&root->sec_head == &logic_pio_root_list[PIO_CPU_MMIO].sec_head)
+		return NULL;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return entry->hwpeer;
+	}
+
+	return NULL;
+}
+
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	struct logic_pio_hwaddr *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 logic_out##bw(type value, unsigned long addr)			\
+{									\
+	struct logic_pio_hwaddr *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 logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	struct logic_pio_hwaddr *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 logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	struct logic_pio_hwaddr *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_LOGIC_IO(b, u8)
+
+EXPORT_SYMBOL(logic_inb);
+EXPORT_SYMBOL(logic_outb);
+EXPORT_SYMBOL(logic_insb);
+EXPORT_SYMBOL(logic_outsb);
+
+BUILD_LOGIC_IO(w, u16)
+
+EXPORT_SYMBOL(logic_inw);
+EXPORT_SYMBOL(logic_outw);
+EXPORT_SYMBOL(logic_insw);
+EXPORT_SYMBOL(logic_outsw);
+
+BUILD_LOGIC_IO(l, u32)
+
+EXPORT_SYMBOL(logic_inl);
+EXPORT_SYMBOL(logic_outl);
+EXPORT_SYMBOL(logic_insl);
+EXPORT_SYMBOL(logic_outsl);
+#endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */
-- 
1.9.1

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

* [PATCH V8 2/6] PCI: Apply the new generic I/O management on PCI IO hosts
  2017-03-30 15:26 ` zhichang.yuan
  (?)
  (?)
@ 2017-03-30 15:26   ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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
LOGIC_IO.
This patch adapts the corresponding code to match the changes introduced by
LOGIC_IO.

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
---
 drivers/acpi/pci_root.c |   8 ++--
 drivers/of/address.c    |   5 ++-
 drivers/pci/pci.c       | 104 +++++++++++-------------------------------------
 include/linux/pci.h     |   3 +-
 4 files changed, 34 insertions(+), 86 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..1693a6f 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,8 +2,10 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/logic_pio.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/pci.h>
@@ -323,7 +325,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..c265f89 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3238,68 +3238,38 @@ 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 logic_pio_hwaddr *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->fwnode = fwnode;
 	range->size = size;
-
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
+
+	tmprange = logic_pio_register_range(range, PAGE_SIZE);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
 #endif
 
-	return err;
+	return 0;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3307,21 +3277,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)
+	if ((PIO_SECT_ID(pio)) != PIO_CPU_MMIO)
 		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 = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3330,25 +3289,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 logic_pio_trans_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] 78+ messages in thread

* [PATCH V8 2/6] PCI: Apply the new generic I/O management on PCI IO hosts
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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
LOGIC_IO.
This patch adapts the corresponding code to match the changes introduced by
LOGIC_IO.

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
---
 drivers/acpi/pci_root.c |   8 ++--
 drivers/of/address.c    |   5 ++-
 drivers/pci/pci.c       | 104 +++++++++++-------------------------------------
 include/linux/pci.h     |   3 +-
 4 files changed, 34 insertions(+), 86 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..1693a6f 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,8 +2,10 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/logic_pio.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/pci.h>
@@ -323,7 +325,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..c265f89 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3238,68 +3238,38 @@ 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 logic_pio_hwaddr *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->fwnode = fwnode;
 	range->size = size;
-
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
+
+	tmprange = logic_pio_register_range(range, PAGE_SIZE);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
 #endif
 
-	return err;
+	return 0;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3307,21 +3277,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)
+	if ((PIO_SECT_ID(pio)) != PIO_CPU_MMIO)
 		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 = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3330,25 +3289,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 logic_pio_trans_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] 78+ messages in thread

* [PATCH V8 2/6] PCI: Apply the new generic I/O management on PCI IO hosts
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, devicetree, lorenzo.pieralisi, gabriele.paoloni,
	minyard, benh, john.garry, linux-kernel, xuwei5, linuxarm,
	zhichang.yuan, linux-acpi, zourongrong, linux-pci, olof,
	zhichang.yuan02, kantyzc, brian.starkey

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
LOGIC_IO.
This patch adapts the corresponding code to match the changes introduced by
LOGIC_IO.

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
---
 drivers/acpi/pci_root.c |   8 ++--
 drivers/of/address.c    |   5 ++-
 drivers/pci/pci.c       | 104 +++++++++++-------------------------------------
 include/linux/pci.h     |   3 +-
 4 files changed, 34 insertions(+), 86 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..1693a6f 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,8 +2,10 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/logic_pio.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/pci.h>
@@ -323,7 +325,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..c265f89 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3238,68 +3238,38 @@ 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 logic_pio_hwaddr *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->fwnode = fwnode;
 	range->size = size;
-
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
+
+	tmprange = logic_pio_register_range(range, PAGE_SIZE);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
 #endif
 
-	return err;
+	return 0;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3307,21 +3277,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)
+	if ((PIO_SECT_ID(pio)) != PIO_CPU_MMIO)
 		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 = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3330,25 +3289,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 logic_pio_trans_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


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 2/6] PCI: Apply the new generic I/O management on PCI IO hosts
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

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
LOGIC_IO.
This patch adapts the corresponding code to match the changes introduced by
LOGIC_IO.

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
---
 drivers/acpi/pci_root.c |   8 ++--
 drivers/of/address.c    |   5 ++-
 drivers/pci/pci.c       | 104 +++++++++++-------------------------------------
 include/linux/pci.h     |   3 +-
 4 files changed, 34 insertions(+), 86 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..1693a6f 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,8 +2,10 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/logic_pio.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/pci.h>
@@ -323,7 +325,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..c265f89 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3238,68 +3238,38 @@ 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 logic_pio_hwaddr *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->fwnode = fwnode;
 	range->size = size;
-
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
+
+	tmprange = logic_pio_register_range(range, PAGE_SIZE);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
 #endif
 
-	return err;
+	return 0;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3307,21 +3277,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)
+	if ((PIO_SECT_ID(pio)) != PIO_CPU_MMIO)
 		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 = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3330,25 +3289,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 logic_pio_trans_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] 78+ messages in thread

* [PATCH V8 3/6] OF: Add missing I/O range exception for indirect-IO  devices
  2017-03-30 15:26 ` zhichang.yuan
  (?)
  (?)
@ 2017-03-30 15:26   ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 1693a6f..d8ca284 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -552,9 +552,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;
@@ -567,6 +572,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)
@@ -587,6 +593,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -599,6 +607,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_by_fwnode(&dev->fwnode);
+		if (iorange && (iorange->flags != PIO_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);
@@ -631,13 +652,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);
 
@@ -679,29 +719,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 = logic_pio_trans_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] 78+ messages in thread

* [PATCH V8 3/6] OF: Add missing I/O range exception for indirect-IO  devices
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 1693a6f..d8ca284 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -552,9 +552,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;
@@ -567,6 +572,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)
@@ -587,6 +593,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -599,6 +607,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_by_fwnode(&dev->fwnode);
+		if (iorange && (iorange->flags != PIO_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);
@@ -631,13 +652,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);
 
@@ -679,29 +719,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 = logic_pio_trans_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] 78+ messages in thread

* [PATCH V8 3/6] OF: Add missing I/O range exception for indirect-IO devices
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, devicetree, lorenzo.pieralisi, gabriele.paoloni,
	minyard, benh, john.garry, linux-kernel, xuwei5, linuxarm,
	zhichang.yuan, linux-acpi, zourongrong, linux-pci, olof,
	zhichang.yuan02, kantyzc, brian.starkey

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 1693a6f..d8ca284 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -552,9 +552,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;
@@ -567,6 +572,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)
@@ -587,6 +593,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -599,6 +607,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_by_fwnode(&dev->fwnode);
+		if (iorange && (iorange->flags != PIO_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);
@@ -631,13 +652,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);
 
@@ -679,29 +719,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 = logic_pio_trans_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


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 3/6] OF: Add missing I/O range exception for indirect-IO devices
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

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 1693a6f..d8ca284 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -552,9 +552,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;
@@ -567,6 +572,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)
@@ -587,6 +593,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -599,6 +607,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_by_fwnode(&dev->fwnode);
+		if (iorange && (iorange->flags != PIO_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);
@@ -631,13 +652,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);
 
@@ -679,29 +719,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 = logic_pio_trans_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] 78+ messages in thread

* [PATCH V8 4/6] LPC: Support the device-tree LPC host on Hip06/Hip07
  2017-03-30 15:26 ` zhichang.yuan
  (?)
@ 2017-03-30 15:26   ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 to retrieve the host-local I/O port.

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                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 537 +++++++++++++++++++++
 9 files changed, 624 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 1b0a87f..740e23b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5945,6 +5945,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..4b548dd 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -64,6 +64,15 @@ 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
+	select LOGIC_PIO
+	select INDIRECT_PIO
+	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..018ea37
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,537 @@
+/*
+ * 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/logic_pio.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 logic_pio_hwaddr *io_host;
+};
+
+/* 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->pio_peer->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 = 0;
+	unsigned long ptaddr;
+	unsigned char *newbuf;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		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;
+
+	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 ||
+			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 ||
+			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 hostio_ops hisi_lpc_ops = {
+	.pfin = hisilpc_comm_in,
+	.pfout = hisilpc_comm_out,
+	.pfins = hisilpc_comm_ins,
+	.pfouts = hisilpc_comm_outs,
+};
+
+/**
+ * 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 */
+	if (!has_acpi_companion(dev)) {
+		struct logic_pio_hwaddr *range, *tmprange;
+
+		range = kzalloc(sizeof(*range), GFP_KERNEL);
+		if (!range)
+			return -ENOMEM;
+		range->fwnode = dev->fwnode;
+		range->flags = PIO_INDIRECT;
+		range->size = LPC_BUS_IO_SIZE;
+		range->hw_start = LPC_MIN_BUS_RANGE;
+
+		tmprange = logic_pio_register_range(range, 1);
+		if (tmprange != range) {
+			kfree(range);
+			if (IS_ERR(tmprange)) {
+				dev_err(dev, "OF: register IO range FAIL!\n");
+				return -EFAULT;
+			}
+		}
+		lpcdev->io_host = tmprange;
+	}
+	if (!lpcdev->io_host || !lpcdev->io_host->pio_peer) {
+		dev_err(dev, "Hisilpc IO hasn't registered!\n");
+		return -EFAULT;
+	}
+
+	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....
+	 * For ACPI children, the corresponding devices had been created
+	 * during the ACPI enumeration.
+	 * The OF scanning must be performed after initialization of 'lpcdev'
+	 * to avoid some children which complete the scanning trigger the
+	 * MMIO accesses which will probably cause panic.
+	 */
+	if (!has_acpi_companion(dev))
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+
+	if (!ret) {
+		dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+			&lpcdev->io_host->pio_peer->io_start,
+			&lpcdev->io_host->size);
+	} else {
+		/*
+		 * 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 prevent
+		 * some peripherals which had not finished the initialization to
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+		dev_info(dev, "OF: scan hisilpc children got failed(%d)\n",
+			ret);
+	}
+
+	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,
+};
+
+builtin_platform_driver(hisilpc_driver);
-- 
1.9.1

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

* [PATCH V8 4/6] LPC: Support the device-tree LPC host on Hip06/Hip07
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, 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 to retrieve the host-local I/O port.

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                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 537 +++++++++++++++++++++
 9 files changed, 624 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 1b0a87f..740e23b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5945,6 +5945,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..4b548dd 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -64,6 +64,15 @@ 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
+	select LOGIC_PIO
+	select INDIRECT_PIO
+	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..018ea37
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,537 @@
+/*
+ * 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/logic_pio.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 logic_pio_hwaddr *io_host;
+};
+
+/* 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->pio_peer->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 = 0;
+	unsigned long ptaddr;
+	unsigned char *newbuf;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		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;
+
+	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 ||
+			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 ||
+			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 hostio_ops hisi_lpc_ops = {
+	.pfin = hisilpc_comm_in,
+	.pfout = hisilpc_comm_out,
+	.pfins = hisilpc_comm_ins,
+	.pfouts = hisilpc_comm_outs,
+};
+
+/**
+ * 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 */
+	if (!has_acpi_companion(dev)) {
+		struct logic_pio_hwaddr *range, *tmprange;
+
+		range = kzalloc(sizeof(*range), GFP_KERNEL);
+		if (!range)
+			return -ENOMEM;
+		range->fwnode = dev->fwnode;
+		range->flags = PIO_INDIRECT;
+		range->size = LPC_BUS_IO_SIZE;
+		range->hw_start = LPC_MIN_BUS_RANGE;
+
+		tmprange = logic_pio_register_range(range, 1);
+		if (tmprange != range) {
+			kfree(range);
+			if (IS_ERR(tmprange)) {
+				dev_err(dev, "OF: register IO range FAIL!\n");
+				return -EFAULT;
+			}
+		}
+		lpcdev->io_host = tmprange;
+	}
+	if (!lpcdev->io_host || !lpcdev->io_host->pio_peer) {
+		dev_err(dev, "Hisilpc IO hasn't registered!\n");
+		return -EFAULT;
+	}
+
+	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....
+	 * For ACPI children, the corresponding devices had been created
+	 * during the ACPI enumeration.
+	 * The OF scanning must be performed after initialization of 'lpcdev'
+	 * to avoid some children which complete the scanning trigger the
+	 * MMIO accesses which will probably cause panic.
+	 */
+	if (!has_acpi_companion(dev))
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+
+	if (!ret) {
+		dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+			&lpcdev->io_host->pio_peer->io_start,
+			&lpcdev->io_host->size);
+	} else {
+		/*
+		 * 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 prevent
+		 * some peripherals which had not finished the initialization to
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+		dev_info(dev, "OF: scan hisilpc children got failed(%d)\n",
+			ret);
+	}
+
+	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,
+};
+
+builtin_platform_driver(hisilpc_driver);
-- 
1.9.1

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

* [PATCH V8 4/6] LPC: Support the device-tree LPC host on Hip06/Hip07
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

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 to retrieve the host-local I/O port.

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                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 537 +++++++++++++++++++++
 9 files changed, 624 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 at a01b0000 {
+	compatible = "hisilicon,hip06-lpc";
+	#address-cells = <2>;
+	#size-cells = <1>;
+	reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+	ipmi0: bt at e4 {
+		compatible = "ipmi-bt";
+		device_type = "ipmi";
+		reg = <0x01 0xe4 0x04>;
+	};
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 1b0a87f..740e23b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5945,6 +5945,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 at 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 at a01b0000 {
+			compatible = "hisilicon,hip06-lpc";
+			#size-cells = <1>;
+			#address-cells = <2>;
+			reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+			ipmi0: bt at 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 at a01b0000 {
+			compatible = "hisilicon,hip07-lpc";
+			#size-cells = <1>;
+			#address-cells = <2>;
+			reg = <0x0 0xa01b0000 0x0 0x1000>;
+
+			ipmi0: bt at e4 {
+				compatible = "ipmi-bt";
+				device_type = "ipmi";
+				reg = <0x01 0xe4 0x04>;
+				status = "disabled";
+			};
+		};
+
 		uart0: uart at 602b0000 {
 			compatible = "arm,sbsa-uart";
 			reg = <0x0 0x602b0000 0x0 0x1000>;
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 0a52da4..4b548dd 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -64,6 +64,15 @@ 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
+	select LOGIC_PIO
+	select INDIRECT_PIO
+	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..018ea37
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,537 @@
+/*
+ * 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/logic_pio.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 logic_pio_hwaddr *io_host;
+};
+
+/* 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->pio_peer->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 = 0;
+	unsigned long ptaddr;
+	unsigned char *newbuf;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		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;
+
+	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 ||
+			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 ||
+			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 hostio_ops hisi_lpc_ops = {
+	.pfin = hisilpc_comm_in,
+	.pfout = hisilpc_comm_out,
+	.pfins = hisilpc_comm_ins,
+	.pfouts = hisilpc_comm_outs,
+};
+
+/**
+ * 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 */
+	if (!has_acpi_companion(dev)) {
+		struct logic_pio_hwaddr *range, *tmprange;
+
+		range = kzalloc(sizeof(*range), GFP_KERNEL);
+		if (!range)
+			return -ENOMEM;
+		range->fwnode = dev->fwnode;
+		range->flags = PIO_INDIRECT;
+		range->size = LPC_BUS_IO_SIZE;
+		range->hw_start = LPC_MIN_BUS_RANGE;
+
+		tmprange = logic_pio_register_range(range, 1);
+		if (tmprange != range) {
+			kfree(range);
+			if (IS_ERR(tmprange)) {
+				dev_err(dev, "OF: register IO range FAIL!\n");
+				return -EFAULT;
+			}
+		}
+		lpcdev->io_host = tmprange;
+	}
+	if (!lpcdev->io_host || !lpcdev->io_host->pio_peer) {
+		dev_err(dev, "Hisilpc IO hasn't registered!\n");
+		return -EFAULT;
+	}
+
+	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....
+	 * For ACPI children, the corresponding devices had been created
+	 * during the ACPI enumeration.
+	 * The OF scanning must be performed after initialization of 'lpcdev'
+	 * to avoid some children which complete the scanning trigger the
+	 * MMIO accesses which will probably cause panic.
+	 */
+	if (!has_acpi_companion(dev))
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+
+	if (!ret) {
+		dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+			&lpcdev->io_host->pio_peer->io_start,
+			&lpcdev->io_host->size);
+	} else {
+		/*
+		 * 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 prevent
+		 * some peripherals which had not finished the initialization to
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+		dev_info(dev, "OF: scan hisilpc children got failed(%d)\n",
+			ret);
+	}
+
+	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,
+};
+
+builtin_platform_driver(hisilpc_driver);
-- 
1.9.1

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply  indirect-IO
  2017-03-30 15:26 ` zhichang.yuan
  (?)
@ 2017-03-30 15:26   ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, zourongrong, john.garry, gabriele.paoloni,
	zhichang.yuan02, kantyzc, xuwei5, zhichang.yuan

On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
with some special host-local I/O ports known on x86. To access the I/O
peripherals, an indirect-IO mechanism is introduced to mapped the host-local
I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
separate I/O space exists. Just as PCI MMIO, the host I/O range should be
registered before probing the downstream devices and set up the I/O mapping.
But current ACPI bus probing doesn't support these indirect-IO hosts/devices.

This patch introdueces a new ACPI handler for this device category. Through the
handler attach callback, the indirect-IO hosts I/O registration is done and
all peripherals' I/O resources are translated into logic/fake PIO before
starting the enumeration.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/internal.h        |   5 +
 drivers/acpi/scan.c            |   1 +
 4 files changed, 351 insertions(+)
 create mode 100644 drivers/acpi/acpi_indirectio.c

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index a391bbc..10e5f2b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
 acpi-$(CONFIG_ACPI_WATCHDOG)	+= acpi_watchdog.o
+acpi-$(CONFIG_INDIRECT_PIO)	+= acpi_indirectio.o
 
 # These are (potentially) separate modules
 
diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
new file mode 100644
index 0000000..c8c80b5
--- /dev/null
+++ b/drivers/acpi/acpi_indirectio.c
@@ -0,0 +1,344 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * 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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/logic_pio.h>
+
+#include "internal.h"
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+struct indirectio_device_desc {
+	void *pdata; /* device relevant info data */
+	int (*pre_setup)(struct acpi_device *adev, void *pdata);
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
+					   void *data)
+{
+	int *res_cnt = data;
+
+	if (acpi_logicio_supported_resource(res) &&
+		!acpi_dev_filter_resource_type(res, IORESOURCE_IO))
+		(*res_cnt)++;
+
+	return AE_OK;
+}
+
+static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
+		void *data)
+{
+	struct acpi_resource **resource = data;
+
+	if (acpi_logicio_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_logiciores_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_logiciores, &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_logiciores, &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_logiciores(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_info(dev, "CRS IO: len=0x%llx [0x%llx - 0x%llx]\n",
+			addr.address.address_length, addr.address.minimum,
+			addr.address.maximum);
+	sys_port = logic_pio_trans_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.
+ */
+static int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev)
+{
+	struct acpi_device *adev;
+	struct acpi_device *host;
+	struct acpi_buffer buffer;
+	acpi_status status;
+	int ret;
+
+	if (!child || !hostdev)
+		return -EINVAL;
+
+	host = to_acpi_device(hostdev);
+	adev = to_acpi_device(child);
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(child, "ACPI: device is not present!\n");
+		return 0;
+	}
+	/* whether the child had been enumerated? */
+	if (acpi_device_enumerated(adev)) {
+		dev_info(child, "ACPI: had been enumerated!\n");
+		return 0;
+	}
+
+	/* read the _CRS and convert as acpi_buffer */
+	status = acpi_build_logiciores_template(adev, &buffer);
+	if (ACPI_FAILURE(status)) {
+		dev_warn(child, "Failure evaluating %s\n", METHOD_NAME__CRS);
+		return -ENODEV;
+	}
+
+	/* translate the I/O resources */
+	ret = acpi_translate_logiciores(adev, host, &buffer);
+	if (ret) {
+		kfree(buffer.pointer);
+		dev_err(child, "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(child, "Error evaluating _SRS (0x%x)\n", status);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	struct logic_pio_hwaddr *range, *tmprange;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+
+	lpc_private = (struct lpc_private_data *)pdata;
+	range = kzalloc(sizeof(*range), GFP_KERNEL);
+	if (!range)
+		return -ENOMEM;
+	range->fwnode = &adev->fwnode;
+	range->flags = PIO_INDIRECT;
+	range->size = lpc_private->io_size;
+	range->hw_start = lpc_private->io_start;
+
+	tmprange = logic_pio_register_range(range, 1);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
+
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		int ret;
+
+		ret = acpi_set_logicio_resource(&child->dev, &adev->dev);
+		if (ret) {
+			dev_err(&child->dev, "set resource failed..\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_host_id[] = {
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+	{""},
+};
+
+static int acpi_indirectio_attach(struct acpi_device *adev,
+				const struct acpi_device_id *id)
+{
+	struct indirectio_device_desc *hostdata;
+	struct platform_device *pdev;
+	int ret;
+
+	hostdata = (struct indirectio_device_desc *)id->driver_data;
+	if (!hostdata || !hostdata->pre_setup)
+		return -EINVAL;
+
+	ret = hostdata->pre_setup(adev, hostdata->pdata);
+	if (!ret) {
+		pdev = acpi_create_platform_device(adev, NULL);
+		if (IS_ERR_OR_NULL(pdev)) {
+			dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+			return -EFAULT;
+		}
+		acpi_device_set_enumerated(adev);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+
+static struct acpi_scan_handler acpi_indirect_handler = {
+	.ids = acpi_indirect_host_id,
+	.attach = acpi_indirectio_attach,
+};
+
+void __init acpi_indirectio_scan_init(void)
+{
+	acpi_scan_add_handler(&acpi_indirect_handler);
+}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f159001..b11412d 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@
 void acpi_platform_init(void);
 void acpi_pnp_init(void);
 void acpi_int340x_thermal_init(void);
+#ifdef CONFIG_INDIRECT_PIO
+void acpi_indirectio_scan_init(void);
+#else
+static inline void acpi_indirectio_scan_init(void) {}
+#endif
 #ifdef CONFIG_ARM_AMBA
 void acpi_amba_init(void);
 #else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1926918..eda79ce 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2033,6 +2033,7 @@ int __init acpi_scan_init(void)
 	acpi_int340x_thermal_init();
 	acpi_amba_init();
 	acpi_watchdog_init();
+	acpi_indirectio_scan_init();
 
 	acpi_scan_add_handler(&generic_device_handler);
 
-- 
1.9.1

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply  indirect-IO
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, zourongrong, john.garry, gabriele.paoloni,
	zhichang.yuan02, kantyzc, xuwei5, zhichang.yuan

On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
with some special host-local I/O ports known on x86. To access the I/O
peripherals, an indirect-IO mechanism is introduced to mapped the host-local
I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
separate I/O space exists. Just as PCI MMIO, the host I/O range should be
registered before probing the downstream devices and set up the I/O mapping.
But current ACPI bus probing doesn't support these indirect-IO hosts/devices.

This patch introdueces a new ACPI handler for this device category. Through the
handler attach callback, the indirect-IO hosts I/O registration is done and
all peripherals' I/O resources are translated into logic/fake PIO before
starting the enumeration.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/internal.h        |   5 +
 drivers/acpi/scan.c            |   1 +
 4 files changed, 351 insertions(+)
 create mode 100644 drivers/acpi/acpi_indirectio.c

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index a391bbc..10e5f2b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
 acpi-$(CONFIG_ACPI_WATCHDOG)	+= acpi_watchdog.o
+acpi-$(CONFIG_INDIRECT_PIO)	+= acpi_indirectio.o
 
 # These are (potentially) separate modules
 
diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
new file mode 100644
index 0000000..c8c80b5
--- /dev/null
+++ b/drivers/acpi/acpi_indirectio.c
@@ -0,0 +1,344 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * 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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/logic_pio.h>
+
+#include "internal.h"
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+struct indirectio_device_desc {
+	void *pdata; /* device relevant info data */
+	int (*pre_setup)(struct acpi_device *adev, void *pdata);
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
+					   void *data)
+{
+	int *res_cnt = data;
+
+	if (acpi_logicio_supported_resource(res) &&
+		!acpi_dev_filter_resource_type(res, IORESOURCE_IO))
+		(*res_cnt)++;
+
+	return AE_OK;
+}
+
+static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
+		void *data)
+{
+	struct acpi_resource **resource = data;
+
+	if (acpi_logicio_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_logiciores_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_logiciores, &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_logiciores, &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_logiciores(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_info(dev, "CRS IO: len=0x%llx [0x%llx - 0x%llx]\n",
+			addr.address.address_length, addr.address.minimum,
+			addr.address.maximum);
+	sys_port = logic_pio_trans_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.
+ */
+static int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev)
+{
+	struct acpi_device *adev;
+	struct acpi_device *host;
+	struct acpi_buffer buffer;
+	acpi_status status;
+	int ret;
+
+	if (!child || !hostdev)
+		return -EINVAL;
+
+	host = to_acpi_device(hostdev);
+	adev = to_acpi_device(child);
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(child, "ACPI: device is not present!\n");
+		return 0;
+	}
+	/* whether the child had been enumerated? */
+	if (acpi_device_enumerated(adev)) {
+		dev_info(child, "ACPI: had been enumerated!\n");
+		return 0;
+	}
+
+	/* read the _CRS and convert as acpi_buffer */
+	status = acpi_build_logiciores_template(adev, &buffer);
+	if (ACPI_FAILURE(status)) {
+		dev_warn(child, "Failure evaluating %s\n", METHOD_NAME__CRS);
+		return -ENODEV;
+	}
+
+	/* translate the I/O resources */
+	ret = acpi_translate_logiciores(adev, host, &buffer);
+	if (ret) {
+		kfree(buffer.pointer);
+		dev_err(child, "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(child, "Error evaluating _SRS (0x%x)\n", status);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	struct logic_pio_hwaddr *range, *tmprange;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+
+	lpc_private = (struct lpc_private_data *)pdata;
+	range = kzalloc(sizeof(*range), GFP_KERNEL);
+	if (!range)
+		return -ENOMEM;
+	range->fwnode = &adev->fwnode;
+	range->flags = PIO_INDIRECT;
+	range->size = lpc_private->io_size;
+	range->hw_start = lpc_private->io_start;
+
+	tmprange = logic_pio_register_range(range, 1);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
+
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		int ret;
+
+		ret = acpi_set_logicio_resource(&child->dev, &adev->dev);
+		if (ret) {
+			dev_err(&child->dev, "set resource failed..\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_host_id[] = {
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+	{""},
+};
+
+static int acpi_indirectio_attach(struct acpi_device *adev,
+				const struct acpi_device_id *id)
+{
+	struct indirectio_device_desc *hostdata;
+	struct platform_device *pdev;
+	int ret;
+
+	hostdata = (struct indirectio_device_desc *)id->driver_data;
+	if (!hostdata || !hostdata->pre_setup)
+		return -EINVAL;
+
+	ret = hostdata->pre_setup(adev, hostdata->pdata);
+	if (!ret) {
+		pdev = acpi_create_platform_device(adev, NULL);
+		if (IS_ERR_OR_NULL(pdev)) {
+			dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+			return -EFAULT;
+		}
+		acpi_device_set_enumerated(adev);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+
+static struct acpi_scan_handler acpi_indirect_handler = {
+	.ids = acpi_indirect_host_id,
+	.attach = acpi_indirectio_attach,
+};
+
+void __init acpi_indirectio_scan_init(void)
+{
+	acpi_scan_add_handler(&acpi_indirect_handler);
+}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f159001..b11412d 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@
 void acpi_platform_init(void);
 void acpi_pnp_init(void);
 void acpi_int340x_thermal_init(void);
+#ifdef CONFIG_INDIRECT_PIO
+void acpi_indirectio_scan_init(void);
+#else
+static inline void acpi_indirectio_scan_init(void) {}
+#endif
 #ifdef CONFIG_ARM_AMBA
 void acpi_amba_init(void);
 #else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1926918..eda79ce 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2033,6 +2033,7 @@ int __init acpi_scan_init(void)
 	acpi_int340x_thermal_init();
 	acpi_amba_init();
 	acpi_watchdog_init();
+	acpi_indirectio_scan_init();
 
 	acpi_scan_add_handler(&generic_device_handler);
 
-- 
1.9.1

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
with some special host-local I/O ports known on x86. To access the I/O
peripherals, an indirect-IO mechanism is introduced to mapped the host-local
I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
separate I/O space exists. Just as PCI MMIO, the host I/O range should be
registered before probing the downstream devices and set up the I/O mapping.
But current ACPI bus probing doesn't support these indirect-IO hosts/devices.

This patch introdueces a new ACPI handler for this device category. Through the
handler attach callback, the indirect-IO hosts I/O registration is done and
all peripherals' I/O resources are translated into logic/fake PIO before
starting the enumeration.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/internal.h        |   5 +
 drivers/acpi/scan.c            |   1 +
 4 files changed, 351 insertions(+)
 create mode 100644 drivers/acpi/acpi_indirectio.c

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index a391bbc..10e5f2b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
 acpi-$(CONFIG_ACPI_WATCHDOG)	+= acpi_watchdog.o
+acpi-$(CONFIG_INDIRECT_PIO)	+= acpi_indirectio.o
 
 # These are (potentially) separate modules
 
diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
new file mode 100644
index 0000000..c8c80b5
--- /dev/null
+++ b/drivers/acpi/acpi_indirectio.c
@@ -0,0 +1,344 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * 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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/logic_pio.h>
+
+#include "internal.h"
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+struct indirectio_device_desc {
+	void *pdata; /* device relevant info data */
+	int (*pre_setup)(struct acpi_device *adev, void *pdata);
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
+					   void *data)
+{
+	int *res_cnt = data;
+
+	if (acpi_logicio_supported_resource(res) &&
+		!acpi_dev_filter_resource_type(res, IORESOURCE_IO))
+		(*res_cnt)++;
+
+	return AE_OK;
+}
+
+static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
+		void *data)
+{
+	struct acpi_resource **resource = data;
+
+	if (acpi_logicio_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_logiciores_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_logiciores, &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_logiciores, &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_logiciores(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_info(dev, "CRS IO: len=0x%llx [0x%llx - 0x%llx]\n",
+			addr.address.address_length, addr.address.minimum,
+			addr.address.maximum);
+	sys_port = logic_pio_trans_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.
+ */
+static int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev)
+{
+	struct acpi_device *adev;
+	struct acpi_device *host;
+	struct acpi_buffer buffer;
+	acpi_status status;
+	int ret;
+
+	if (!child || !hostdev)
+		return -EINVAL;
+
+	host = to_acpi_device(hostdev);
+	adev = to_acpi_device(child);
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(child, "ACPI: device is not present!\n");
+		return 0;
+	}
+	/* whether the child had been enumerated? */
+	if (acpi_device_enumerated(adev)) {
+		dev_info(child, "ACPI: had been enumerated!\n");
+		return 0;
+	}
+
+	/* read the _CRS and convert as acpi_buffer */
+	status = acpi_build_logiciores_template(adev, &buffer);
+	if (ACPI_FAILURE(status)) {
+		dev_warn(child, "Failure evaluating %s\n", METHOD_NAME__CRS);
+		return -ENODEV;
+	}
+
+	/* translate the I/O resources */
+	ret = acpi_translate_logiciores(adev, host, &buffer);
+	if (ret) {
+		kfree(buffer.pointer);
+		dev_err(child, "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(child, "Error evaluating _SRS (0x%x)\n", status);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	struct logic_pio_hwaddr *range, *tmprange;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+
+	lpc_private = (struct lpc_private_data *)pdata;
+	range = kzalloc(sizeof(*range), GFP_KERNEL);
+	if (!range)
+		return -ENOMEM;
+	range->fwnode = &adev->fwnode;
+	range->flags = PIO_INDIRECT;
+	range->size = lpc_private->io_size;
+	range->hw_start = lpc_private->io_start;
+
+	tmprange = logic_pio_register_range(range, 1);
+	if (tmprange != range) {
+		kfree(range);
+		if (IS_ERR(tmprange))
+			return -EFAULT;
+	}
+
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		int ret;
+
+		ret = acpi_set_logicio_resource(&child->dev, &adev->dev);
+		if (ret) {
+			dev_err(&child->dev, "set resource failed..\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_host_id[] = {
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+	{""},
+};
+
+static int acpi_indirectio_attach(struct acpi_device *adev,
+				const struct acpi_device_id *id)
+{
+	struct indirectio_device_desc *hostdata;
+	struct platform_device *pdev;
+	int ret;
+
+	hostdata = (struct indirectio_device_desc *)id->driver_data;
+	if (!hostdata || !hostdata->pre_setup)
+		return -EINVAL;
+
+	ret = hostdata->pre_setup(adev, hostdata->pdata);
+	if (!ret) {
+		pdev = acpi_create_platform_device(adev, NULL);
+		if (IS_ERR_OR_NULL(pdev)) {
+			dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+			return -EFAULT;
+		}
+		acpi_device_set_enumerated(adev);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+
+static struct acpi_scan_handler acpi_indirect_handler = {
+	.ids = acpi_indirect_host_id,
+	.attach = acpi_indirectio_attach,
+};
+
+void __init acpi_indirectio_scan_init(void)
+{
+	acpi_scan_add_handler(&acpi_indirect_handler);
+}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f159001..b11412d 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@
 void acpi_platform_init(void);
 void acpi_pnp_init(void);
 void acpi_int340x_thermal_init(void);
+#ifdef CONFIG_INDIRECT_PIO
+void acpi_indirectio_scan_init(void);
+#else
+static inline void acpi_indirectio_scan_init(void) {}
+#endif
 #ifdef CONFIG_ARM_AMBA
 void acpi_amba_init(void);
 #else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1926918..eda79ce 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2033,6 +2033,7 @@ int __init acpi_scan_init(void)
 	acpi_int340x_thermal_init();
 	acpi_amba_init();
 	acpi_watchdog_init();
+	acpi_indirectio_scan_init();
 
 	acpi_scan_add_handler(&generic_device_handler);
 
-- 
1.9.1

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

* [PATCH V8 6/6] LPC: Add the ACPI LPC support
  2017-03-30 15:26 ` zhichang.yuan
  (?)
@ 2017-03-30 15:26   ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, zourongrong, john.garry, gabriele.paoloni,
	zhichang.yuan02, kantyzc, xuwei5, zhichang.yuan

Based on the provious patches, this patch supports the ACPI LPC host on
Hip06/Hip07.

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

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index 018ea37..ef62045 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -458,7 +458,9 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	if (!has_acpi_companion(dev)) {
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+	} else {
 		struct logic_pio_hwaddr *range, *tmprange;
 
 		range = kzalloc(sizeof(*range), GFP_KERNEL);
@@ -526,10 +528,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] 78+ messages in thread

* [PATCH V8 6/6] LPC: Add the ACPI LPC support
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel
  Cc: mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, zourongrong, john.garry, gabriele.paoloni,
	zhichang.yuan02, kantyzc, xuwei5, zhichang.yuan

Based on the provious patches, this patch supports the ACPI LPC host on
Hip06/Hip07.

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

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index 018ea37..ef62045 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -458,7 +458,9 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	if (!has_acpi_companion(dev)) {
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+	} else {
 		struct logic_pio_hwaddr *range, *tmprange;
 
 		range = kzalloc(sizeof(*range), GFP_KERNEL);
@@ -526,10 +528,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] 78+ messages in thread

* [PATCH V8 6/6] LPC: Add the ACPI LPC support
@ 2017-03-30 15:26   ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-30 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

Based on the provious patches, this patch supports the ACPI LPC host on
Hip06/Hip07.

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

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index 018ea37..ef62045 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -458,7 +458,9 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	if (!has_acpi_companion(dev)) {
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+	} else {
 		struct logic_pio_hwaddr *range, *tmprange;
 
 		range = kzalloc(sizeof(*range), GFP_KERNEL);
@@ -526,10 +528,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] 78+ messages in thread

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply  indirect-IO
  2017-03-30 15:26   ` zhichang.yuan
  (?)
  (?)
@ 2017-03-30 20:31       ` Rafael J. Wysocki
  -1 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-30 20:31 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
	bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, rafael-DgEjT+Ai2ygdnm+yROfE0A,
	arnd-r2nGTMty4D4,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	mark.rutland-5wv7dgnIgG8, brian.starkey-5wv7dgnIgG8,
	olof-nZhT3qVonbNeoWH0uzbU5w, lorenzo.pieralisi-5wv7dgnIgG8,
	benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	linuxarm-hv44wF8Li93QT0dZR+AlfA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, minyard-HInyCGIudOg,
	zourongrong-Re5JQEeQqe8AvxtiuMwx3w,
	john.garry-hv44wF8Li93QT0dZR+AlfA,
	gabriele.paoloni-hv44wF8Li93QT0dZR+AlfA,
	zhichang.yuan02-Re5JQEeQqe8AvxtiuMwx3w, kantyzc-9Onoh4P/yGk,
	xuwei5-C8/M+/jPZTeaMJb+Lgu22Q

On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> 
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.

Can you explain to me briefly what exactly this code is expected to be doing?

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply  indirect-IO
@ 2017-03-30 20:31       ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-30 20:31 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, mark.rutland, brian.starkey,
	olof, lorenzo.pieralisi, benh, linux-kernel, linux-acpi,
	linuxarm, devicetree, linux-pci, minyard, zourongrong,
	john.garry, gabriele.paoloni, zhichang.yuan02, kantyzc, xuwei5

On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> 
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.

Can you explain to me briefly what exactly this code is expected to be doing?

Thanks,
Rafael

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-30 20:31       ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-30 20:31 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: mark.rutland, benh, gabriele.paoloni, rafael, linux-pci,
	will.deacon, linuxarm, frowand.list, lorenzo.pieralisi, arnd,
	xuwei5, linux-acpi, catalin.marinas, devicetree, minyard,
	john.garry, zourongrong, robh+dt, bhelgaas, kantyzc,
	zhichang.yuan02, linux-arm-kernel, linux-kernel, olof,
	brian.starkey

On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> 
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.

Can you explain to me briefly what exactly this code is expected to be doing?

Thanks,
Rafael


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-30 20:31       ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-30 20:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> 
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.

Can you explain to me briefly what exactly this code is expected to be doing?

Thanks,
Rafael

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

* Re: [PATCH V8 0/7] LPC: legacy ISA I/O support
  2017-03-30 15:26 ` zhichang.yuan
  (?)
  (?)
@ 2017-03-30 21:42   ` dann frazier
  -1 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-03-30 21:42 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, devicetree, lorenzo.pieralisi, Gabriele Paoloni,
	Corey Minyard, benh, John Garry, linux-kernel, xuwei5, linuxarm,
	linux-acpi, Zou Rongrong, linux-pci, olof

On Thu, Mar 30, 2017 at 9:26 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.
>
> Changes from V7:
>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>     redirecting the I/O accesses to right device driver;
>   - To reduce the impact on PCI MMIO to a minimum, add a new
>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>   - Added a new ACPI handler for indirect-IO hosts/devices;
>   - Fixed the compile issues on V6;
>
> 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;
>
> V7 thread here: https://lkml.org/lkml/2017/3/12/279
> 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 (6):
>   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: Support the probing on the devices which apply indirect-IO
>   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/Makefile                              |   1 +
>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>  drivers/acpi/internal.h                            |   5 +
>  drivers/acpi/pci_root.c                            |   8 +-
>  drivers/acpi/scan.c                                |   1 +
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>  drivers/of/address.c                               |  95 +++-
>  drivers/pci/pci.c                                  | 104 +---
>  include/asm-generic/io.h                           |  50 ++
>  include/linux/logic_pio.h                          | 174 +++++++
>  include/linux/pci.h                                |   3 +-
>  lib/Kconfig                                        |  26 +
>  lib/Makefile                                       |   2 +
>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>  22 files changed, 1758 insertions(+), 102 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>  create mode 100644 drivers/bus/hisi_lpc.c
>  create mode 100644 include/linux/logic_pio.h
>  create mode 100644 lib/logic_pio.c

Booted up on a D05, was able to use the LPC-connected IPMI interface.

Tested-by: dann frazier <dann.frazier@canonical.com>

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

* Re: [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-30 21:42   ` dann frazier
  0 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-03-30 21:42 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, devicetree, lorenzo.pieralisi, Gabriele Paoloni,
	Corey Minyard, benh, John Garry, linux-kernel, xuwei5, linuxarm,
	linux-acpi, Zou Rongrong, linux-pci, olof, zhichang.yuan,
	kantyzc, brian.starkey

On Thu, Mar 30, 2017 at 9:26 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.
>
> Changes from V7:
>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>     redirecting the I/O accesses to right device driver;
>   - To reduce the impact on PCI MMIO to a minimum, add a new
>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>   - Added a new ACPI handler for indirect-IO hosts/devices;
>   - Fixed the compile issues on V6;
>
> 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;
>
> V7 thread here: https://lkml.org/lkml/2017/3/12/279
> 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 (6):
>   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: Support the probing on the devices which apply indirect-IO
>   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/Makefile                              |   1 +
>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>  drivers/acpi/internal.h                            |   5 +
>  drivers/acpi/pci_root.c                            |   8 +-
>  drivers/acpi/scan.c                                |   1 +
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>  drivers/of/address.c                               |  95 +++-
>  drivers/pci/pci.c                                  | 104 +---
>  include/asm-generic/io.h                           |  50 ++
>  include/linux/logic_pio.h                          | 174 +++++++
>  include/linux/pci.h                                |   3 +-
>  lib/Kconfig                                        |  26 +
>  lib/Makefile                                       |   2 +
>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>  22 files changed, 1758 insertions(+), 102 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>  create mode 100644 drivers/bus/hisi_lpc.c
>  create mode 100644 include/linux/logic_pio.h
>  create mode 100644 lib/logic_pio.c

Booted up on a D05, was able to use the LPC-connected IPMI interface.

Tested-by: dann frazier <dann.frazier@canonical.com>

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

* Re: [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-30 21:42   ` dann frazier
  0 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-03-30 21:42 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Mark Rutland, Catalin Marinas, Gabriele Paoloni, rafael, benh,
	Will Deacon, linuxarm, Frank Rowand, lorenzo.pieralisi,
	Corey Minyard, xuwei5, linux-acpi, linux-pci, devicetree,
	Arnd Bergmann, John Garry, olof, Rob Herring, Bjorn Helgaas,
	kantyzc, zhichang.yuan, linux-arm-kernel, linux-kernel,
	Zou Rongrong, brian.starkey

On Thu, Mar 30, 2017 at 9:26 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.
>
> Changes from V7:
>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>     redirecting the I/O accesses to right device driver;
>   - To reduce the impact on PCI MMIO to a minimum, add a new
>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>   - Added a new ACPI handler for indirect-IO hosts/devices;
>   - Fixed the compile issues on V6;
>
> 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;
>
> V7 thread here: https://lkml.org/lkml/2017/3/12/279
> 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 (6):
>   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: Support the probing on the devices which apply indirect-IO
>   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/Makefile                              |   1 +
>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>  drivers/acpi/internal.h                            |   5 +
>  drivers/acpi/pci_root.c                            |   8 +-
>  drivers/acpi/scan.c                                |   1 +
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>  drivers/of/address.c                               |  95 +++-
>  drivers/pci/pci.c                                  | 104 +---
>  include/asm-generic/io.h                           |  50 ++
>  include/linux/logic_pio.h                          | 174 +++++++
>  include/linux/pci.h                                |   3 +-
>  lib/Kconfig                                        |  26 +
>  lib/Makefile                                       |   2 +
>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>  22 files changed, 1758 insertions(+), 102 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>  create mode 100644 drivers/bus/hisi_lpc.c
>  create mode 100644 include/linux/logic_pio.h
>  create mode 100644 lib/logic_pio.c

Booted up on a D05, was able to use the LPC-connected IPMI interface.

Tested-by: dann frazier <dann.frazier@canonical.com>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-30 21:42   ` dann frazier
  0 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-03-30 21:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 30, 2017 at 9:26 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.
>
> Changes from V7:
>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>     redirecting the I/O accesses to right device driver;
>   - To reduce the impact on PCI MMIO to a minimum, add a new
>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>   - Added a new ACPI handler for indirect-IO hosts/devices;
>   - Fixed the compile issues on V6;
>
> 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;
>
> V7 thread here: https://lkml.org/lkml/2017/3/12/279
> 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 (6):
>   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: Support the probing on the devices which apply indirect-IO
>   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/Makefile                              |   1 +
>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>  drivers/acpi/internal.h                            |   5 +
>  drivers/acpi/pci_root.c                            |   8 +-
>  drivers/acpi/scan.c                                |   1 +
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>  drivers/of/address.c                               |  95 +++-
>  drivers/pci/pci.c                                  | 104 +---
>  include/asm-generic/io.h                           |  50 ++
>  include/linux/logic_pio.h                          | 174 +++++++
>  include/linux/pci.h                                |   3 +-
>  lib/Kconfig                                        |  26 +
>  lib/Makefile                                       |   2 +
>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>  22 files changed, 1758 insertions(+), 102 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>  create mode 100644 drivers/bus/hisi_lpc.c
>  create mode 100644 include/linux/logic_pio.h
>  create mode 100644 lib/logic_pio.c

Booted up on a D05, was able to use the LPC-connected IPMI interface.

Tested-by: dann frazier <dann.frazier@canonical.com>

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

* Re: [PATCH V8 0/7] LPC: legacy ISA I/O support
  2017-03-30 21:42   ` dann frazier
  (?)
  (?)
@ 2017-03-31  6:36     ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:36 UTC (permalink / raw)
  To: dann frazier
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, devicetree, lorenzo.pieralisi, Gabriele Paoloni,
	Corey Minyard, benh, John Garry, linux-kernel, xuwei5, linuxarm,
	linux-acpi, Zou Rongrong, linux-pci

Hi, Dann,

Many thanks for your tests!

Best,
Zhichang

On 2017/3/31 5:42, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 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.
>>
>> Changes from V7:
>>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>>     redirecting the I/O accesses to right device driver;
>>   - To reduce the impact on PCI MMIO to a minimum, add a new
>>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>>   - Added a new ACPI handler for indirect-IO hosts/devices;
>>   - Fixed the compile issues on V6;
>>
>> 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;
>>
>> V7 thread here: https://lkml.org/lkml/2017/3/12/279
>> 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 (6):
>>   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: Support the probing on the devices which apply indirect-IO
>>   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/Makefile                              |   1 +
>>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>>  drivers/acpi/internal.h                            |   5 +
>>  drivers/acpi/pci_root.c                            |   8 +-
>>  drivers/acpi/scan.c                                |   1 +
>>  drivers/bus/Kconfig                                |   9 +
>>  drivers/bus/Makefile                               |   1 +
>>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>>  drivers/of/address.c                               |  95 +++-
>>  drivers/pci/pci.c                                  | 104 +---
>>  include/asm-generic/io.h                           |  50 ++
>>  include/linux/logic_pio.h                          | 174 +++++++
>>  include/linux/pci.h                                |   3 +-
>>  lib/Kconfig                                        |  26 +
>>  lib/Makefile                                       |   2 +
>>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>>  22 files changed, 1758 insertions(+), 102 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>  create mode 100644 drivers/bus/hisi_lpc.c
>>  create mode 100644 include/linux/logic_pio.h
>>  create mode 100644 lib/logic_pio.c
> 
> Booted up on a D05, was able to use the LPC-connected IPMI interface.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>
> 
> .
> 


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

* Re: [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-31  6:36     ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:36 UTC (permalink / raw)
  To: dann frazier
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, devicetree, lorenzo.pieralisi, Gabriele Paoloni,
	Corey Minyard, benh, John Garry, linux-kernel, xuwei5, linuxarm,
	linux-acpi, Zou Rongrong, linux-pci, olof, zhichang.yuan,
	kantyzc, brian.starkey

Hi, Dann,

Many thanks for your tests!

Best,
Zhichang

On 2017/3/31 5:42, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 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.
>>
>> Changes from V7:
>>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>>     redirecting the I/O accesses to right device driver;
>>   - To reduce the impact on PCI MMIO to a minimum, add a new
>>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>>   - Added a new ACPI handler for indirect-IO hosts/devices;
>>   - Fixed the compile issues on V6;
>>
>> 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;
>>
>> V7 thread here: https://lkml.org/lkml/2017/3/12/279
>> 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 (6):
>>   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: Support the probing on the devices which apply indirect-IO
>>   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/Makefile                              |   1 +
>>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>>  drivers/acpi/internal.h                            |   5 +
>>  drivers/acpi/pci_root.c                            |   8 +-
>>  drivers/acpi/scan.c                                |   1 +
>>  drivers/bus/Kconfig                                |   9 +
>>  drivers/bus/Makefile                               |   1 +
>>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>>  drivers/of/address.c                               |  95 +++-
>>  drivers/pci/pci.c                                  | 104 +---
>>  include/asm-generic/io.h                           |  50 ++
>>  include/linux/logic_pio.h                          | 174 +++++++
>>  include/linux/pci.h                                |   3 +-
>>  lib/Kconfig                                        |  26 +
>>  lib/Makefile                                       |   2 +
>>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>>  22 files changed, 1758 insertions(+), 102 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>  create mode 100644 drivers/bus/hisi_lpc.c
>>  create mode 100644 include/linux/logic_pio.h
>>  create mode 100644 lib/logic_pio.c
> 
> Booted up on a D05, was able to use the LPC-connected IPMI interface.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>
> 
> .
> 

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

* Re: [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-31  6:36     ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:36 UTC (permalink / raw)
  To: dann frazier
  Cc: Mark Rutland, Catalin Marinas, Gabriele Paoloni, rafael, benh,
	Will Deacon, linuxarm, Frank Rowand, lorenzo.pieralisi,
	Corey Minyard, xuwei5, linux-acpi, linux-pci, devicetree,
	Arnd Bergmann, John Garry, olof, Rob Herring, Bjorn Helgaas,
	kantyzc, zhichang.yuan, linux-arm-kernel, linux-kernel,
	Zou Rongrong, brian.starkey

Hi, Dann,

Many thanks for your tests!

Best,
Zhichang

On 2017/3/31 5:42, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 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.
>>
>> Changes from V7:
>>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>>     redirecting the I/O accesses to right device driver;
>>   - To reduce the impact on PCI MMIO to a minimum, add a new
>>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>>   - Added a new ACPI handler for indirect-IO hosts/devices;
>>   - Fixed the compile issues on V6;
>>
>> 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;
>>
>> V7 thread here: https://lkml.org/lkml/2017/3/12/279
>> 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 (6):
>>   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: Support the probing on the devices which apply indirect-IO
>>   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/Makefile                              |   1 +
>>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>>  drivers/acpi/internal.h                            |   5 +
>>  drivers/acpi/pci_root.c                            |   8 +-
>>  drivers/acpi/scan.c                                |   1 +
>>  drivers/bus/Kconfig                                |   9 +
>>  drivers/bus/Makefile                               |   1 +
>>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>>  drivers/of/address.c                               |  95 +++-
>>  drivers/pci/pci.c                                  | 104 +---
>>  include/asm-generic/io.h                           |  50 ++
>>  include/linux/logic_pio.h                          | 174 +++++++
>>  include/linux/pci.h                                |   3 +-
>>  lib/Kconfig                                        |  26 +
>>  lib/Makefile                                       |   2 +
>>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>>  22 files changed, 1758 insertions(+), 102 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>  create mode 100644 drivers/bus/hisi_lpc.c
>>  create mode 100644 include/linux/logic_pio.h
>>  create mode 100644 lib/logic_pio.c
> 
> Booted up on a D05, was able to use the LPC-connected IPMI interface.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>
> 
> .
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 0/7] LPC: legacy ISA I/O support
@ 2017-03-31  6:36     ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Dann,

Many thanks for your tests!

Best,
Zhichang

On 2017/3/31 5:42, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 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.
>>
>> Changes from V7:
>>   - Based on Arnd's comment, rename the LIBIO as LOGIC_PIO;
>>   - Improved the mapping process in LOGIC_PIO to gain better efficiency when
>>     redirecting the I/O accesses to right device driver;
>>   - To reduce the impact on PCI MMIO to a minimum, add a new
>>     CONFIG_INDIRECT_PIO for indirect-IO hosts/devices;
>>   - Added a new ACPI handler for indirect-IO hosts/devices;
>>   - Fixed the compile issues on V6;
>>
>> 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;
>>
>> V7 thread here: https://lkml.org/lkml/2017/3/12/279
>> 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 (6):
>>   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: Support the probing on the devices which apply indirect-IO
>>   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/Makefile                              |   1 +
>>  drivers/acpi/acpi_indirectio.c                     | 344 +++++++++++++
>>  drivers/acpi/internal.h                            |   5 +
>>  drivers/acpi/pci_root.c                            |   8 +-
>>  drivers/acpi/scan.c                                |   1 +
>>  drivers/bus/Kconfig                                |   9 +
>>  drivers/bus/Makefile                               |   1 +
>>  drivers/bus/hisi_lpc.c                             | 547 +++++++++++++++++++++
>>  drivers/of/address.c                               |  95 +++-
>>  drivers/pci/pci.c                                  | 104 +---
>>  include/asm-generic/io.h                           |  50 ++
>>  include/linux/logic_pio.h                          | 174 +++++++
>>  include/linux/pci.h                                |   3 +-
>>  lib/Kconfig                                        |  26 +
>>  lib/Makefile                                       |   2 +
>>  lib/logic_pio.c                                    | 413 ++++++++++++++++
>>  22 files changed, 1758 insertions(+), 102 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>  create mode 100644 drivers/bus/hisi_lpc.c
>>  create mode 100644 include/linux/logic_pio.h
>>  create mode 100644 lib/logic_pio.c
> 
> Booted up on a D05, was able to use the LPC-connected IPMI interface.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>
> 
> .
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-03-30 20:31       ` Rafael J. Wysocki
  (?)
  (?)
@ 2017-03-31  6:52         ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:52 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: mark.rutland, benh, gabriele.paoloni, rafael, linux-pci,
	will.deacon, linuxarm, frowand.list, lorenzo.pieralisi, arnd,
	xuwei5, linux-acpi, catalin.marinas, devicetree, minyard,
	john.garry, zourongrong, robh+dt, bhelgaas, kantyzc,
	zhichang.yuan02, linux-arm-kernel, linux-kernel, olof,
	brian.starkey

Hi, Rafael,

Thanks for reviewing this!

On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
> 
> Can you explain to me briefly what exactly this code is expected to be doing?

As you know currently for ARM architecture IO space is memory mapped and
is only used by pci devices. The port number is dynamically allocated
converting the device IO address into a PIO token: i.e.
http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
This patch is meant to support a new class of IO host controller
that are not PCI based and that still require to have the IO addresses
be translated in the same PIO token space as the PCI controller

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 
> 
> .
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-31  6:52         ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:52 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, mark.rutland, brian.starkey,
	olof, lorenzo.pieralisi, benh, linux-kernel, linux-acpi,
	linuxarm, devicetree, linux-pci, minyard, zourongrong,
	john.garry, gabriele.paoloni, zhichang.yuan02, kantyzc, xuwei5

Hi, Rafael,

Thanks for reviewing this!

On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
> 
> Can you explain to me briefly what exactly this code is expected to be doing?

As you know currently for ARM architecture IO space is memory mapped and
is only used by pci devices. The port number is dynamically allocated
converting the device IO address into a PIO token: i.e.
http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
This patch is meant to support a new class of IO host controller
that are not PCI based and that still require to have the IO addresses
be translated in the same PIO token space as the PCI controller

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 
> 
> .
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-31  6:52         ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:52 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: mark.rutland, benh, gabriele.paoloni, rafael, linux-pci,
	will.deacon, linuxarm, frowand.list, lorenzo.pieralisi, arnd,
	xuwei5, linux-acpi, catalin.marinas, devicetree, minyard,
	john.garry, zourongrong, robh+dt, bhelgaas, kantyzc,
	zhichang.yuan02, linux-arm-kernel, linux-kernel, olof,
	brian.starkey

Hi, Rafael,

Thanks for reviewing this!

On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
> 
> Can you explain to me briefly what exactly this code is expected to be doing?

As you know currently for ARM architecture IO space is memory mapped and
is only used by pci devices. The port number is dynamically allocated
converting the device IO address into a PIO token: i.e.
http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
This patch is meant to support a new class of IO host controller
that are not PCI based and that still require to have the IO addresses
be translated in the same PIO token space as the PCI controller

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 
> 
> .
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-31  6:52         ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-03-31  6:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Rafael,

Thanks for reviewing this!

On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
> 
> Can you explain to me briefly what exactly this code is expected to be doing?

As you know currently for ARM architecture IO space is memory mapped and
is only used by pci devices. The port number is dynamically allocated
converting the device IO address into a PIO token: i.e.
http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
This patch is meant to support a new class of IO host controller
that are not PCI based and that still require to have the IO addresses
be translated in the same PIO token space as the PCI controller

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 
> 
> .
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-03-31  6:52         ` zhichang.yuan
  (?)
  (?)
@ 2017-03-31 23:02           ` Rafael J. Wysocki
  -1 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-31 23:02 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Rafael J. Wysocki, Arnd Bergmann,
	linux-arm-kernel, Mark Rutland, Brian Starkey, Olof Johansson,
	Lorenzo Pieralisi, Benjamin Herrenschmidt,
	Linux Kernel Mailing List, ACPI Devel Maling List, linuxarm

On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> Hi, Rafael,
>
> Thanks for reviewing this!
>
> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>> with some special host-local I/O ports known on x86. To access the I/O
>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>> registered before probing the downstream devices and set up the I/O mapping.
>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>
>>> This patch introdueces a new ACPI handler for this device category. Through the
>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>> starting the enumeration.
>>
>> Can you explain to me briefly what exactly this code is expected to be doing?
>
> As you know currently for ARM architecture IO space is memory mapped and
> is only used by pci devices. The port number is dynamically allocated
> converting the device IO address into a PIO token: i.e.
> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> This patch is meant to support a new class of IO host controller
> that are not PCI based and that still require to have the IO addresses
> be translated in the same PIO token space as the PCI controller

IOW, this is ARM-specific, right?

Thanks,
Rafael

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-31 23:02           ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-31 23:02 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Rafael J. Wysocki, Arnd Bergmann,
	linux-arm-kernel, Mark Rutland, Brian Starkey, Olof Johansson,
	Lorenzo Pieralisi, Benjamin Herrenschmidt,
	Linux Kernel Mailing List, ACPI Devel Maling List, linuxarm,
	devicetree, Linux PCI, Corey Minyard, Zou Rongrong, John Garry,
	Gabriele Paoloni, zhichang.yuan02, kantyzc, xuwei5

On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> Hi, Rafael,
>
> Thanks for reviewing this!
>
> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>> with some special host-local I/O ports known on x86. To access the I/O
>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>> registered before probing the downstream devices and set up the I/O mapping.
>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>
>>> This patch introdueces a new ACPI handler for this device category. Through the
>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>> starting the enumeration.
>>
>> Can you explain to me briefly what exactly this code is expected to be doing?
>
> As you know currently for ARM architecture IO space is memory mapped and
> is only used by pci devices. The port number is dynamically allocated
> converting the device IO address into a PIO token: i.e.
> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> This patch is meant to support a new class of IO host controller
> that are not PCI based and that still require to have the IO addresses
> be translated in the same PIO token space as the PCI controller

IOW, this is ARM-specific, right?

Thanks,
Rafael

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-31 23:02           ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-31 23:02 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Rafael J. Wysocki, Arnd Bergmann,
	linux-arm-kernel, Mark Rutland, Brian Starkey, Olof Johansson,
	Lorenzo Pieralisi, Benjamin Herrenschmidt,
	Linux Kernel Mailing List, ACPI Devel Maling List, linuxarm,
	devicetree, Linux PCI, Corey Minyard, Zou Rongrong, John Garry,
	Gabriele Paoloni, zhichang.yuan02, kantyzc, xuwei5

On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> Hi, Rafael,
>
> Thanks for reviewing this!
>
> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>> with some special host-local I/O ports known on x86. To access the I/O
>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>> registered before probing the downstream devices and set up the I/O mapping.
>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>
>>> This patch introdueces a new ACPI handler for this device category. Through the
>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>> starting the enumeration.
>>
>> Can you explain to me briefly what exactly this code is expected to be doing?
>
> As you know currently for ARM architecture IO space is memory mapped and
> is only used by pci devices. The port number is dynamically allocated
> converting the device IO address into a PIO token: i.e.
> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> This patch is meant to support a new class of IO host controller
> that are not PCI based and that still require to have the IO addresses
> be translated in the same PIO token space as the PCI controller

IOW, this is ARM-specific, right?

Thanks,
Rafael

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-03-31 23:02           ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-03-31 23:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> Hi, Rafael,
>
> Thanks for reviewing this!
>
> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>> with some special host-local I/O ports known on x86. To access the I/O
>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>> registered before probing the downstream devices and set up the I/O mapping.
>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>
>>> This patch introdueces a new ACPI handler for this device category. Through the
>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>> starting the enumeration.
>>
>> Can you explain to me briefly what exactly this code is expected to be doing?
>
> As you know currently for ARM architecture IO space is memory mapped and
> is only used by pci devices. The port number is dynamically allocated
> converting the device IO address into a PIO token: i.e.
> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> This patch is meant to support a new class of IO host controller
> that are not PCI based and that still require to have the IO addresses
> be translated in the same PIO token space as the PCI controller

IOW, this is ARM-specific, right?

Thanks,
Rafael

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-03-31 23:02           ` Rafael J. Wysocki
  (?)
  (?)
@ 2017-04-01  2:16             ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-01  2:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, Olof Johansson, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List,
	ACPI Devel Maling List, linuxarm, devicetree



On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> Hi, Rafael,
>>
>> Thanks for reviewing this!
>>
>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>
>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>> starting the enumeration.
>>>
>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>
>> As you know currently for ARM architecture IO space is memory mapped and
>> is only used by pci devices. The port number is dynamically allocated
>> converting the device IO address into a PIO token: i.e.
>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>> This patch is meant to support a new class of IO host controller
>> that are not PCI based and that still require to have the IO addresses
>> be translated in the same PIO token space as the PCI controller
> 
> IOW, this is ARM-specific, right?

Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.
But, I think the handler driver is architecture dependent.

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-01  2:16             ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-01  2:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, zhichang.yuan
  Cc: Rafael J. Wysocki, Catalin Marinas, Will Deacon, Rob Herring,
	Frank Rowand, Bjorn Helgaas, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, Olof Johansson, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List,
	ACPI Devel Maling List, linuxarm, devicetree, Linux PCI,
	Corey Minyard, Zou Rongrong, John Garry, Gabriele Paoloni,
	kantyzc, xuwei5



On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> Hi, Rafael,
>>
>> Thanks for reviewing this!
>>
>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>
>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>> starting the enumeration.
>>>
>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>
>> As you know currently for ARM architecture IO space is memory mapped and
>> is only used by pci devices. The port number is dynamically allocated
>> converting the device IO address into a PIO token: i.e.
>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>> This patch is meant to support a new class of IO host controller
>> that are not PCI based and that still require to have the IO addresses
>> be translated in the same PIO token space as the PCI controller
> 
> IOW, this is ARM-specific, right?

Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.
But, I think the handler driver is architecture dependent.

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-01  2:16             ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-01  2:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, zhichang.yuan
  Cc: Mark Rutland, Benjamin Herrenschmidt, Gabriele Paoloni,
	Linux PCI, Will Deacon, linuxarm, Frank Rowand,
	Lorenzo Pieralisi, Arnd Bergmann, xuwei5, ACPI Devel Maling List,
	Catalin Marinas, devicetree, Corey Minyard, John Garry,
	Zou Rongrong, Rob Herring, Bjorn Helgaas, kantyzc,
	linux-arm-kernel, Rafael J. Wysocki, Linux Kernel Mailing List,
	Olof Johansson, Brian Starkey



On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> Hi, Rafael,
>>
>> Thanks for reviewing this!
>>
>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>
>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>> starting the enumeration.
>>>
>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>
>> As you know currently for ARM architecture IO space is memory mapped and
>> is only used by pci devices. The port number is dynamically allocated
>> converting the device IO address into a PIO token: i.e.
>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>> This patch is meant to support a new class of IO host controller
>> that are not PCI based and that still require to have the IO addresses
>> be translated in the same PIO token space as the PCI controller
> 
> IOW, this is ARM-specific, right?

Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.
But, I think the handler driver is architecture dependent.

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-01  2:16             ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-01  2:16 UTC (permalink / raw)
  To: linux-arm-kernel



On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> Hi, Rafael,
>>
>> Thanks for reviewing this!
>>
>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>
>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>> starting the enumeration.
>>>
>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>
>> As you know currently for ARM architecture IO space is memory mapped and
>> is only used by pci devices. The port number is dynamically allocated
>> converting the device IO address into a PIO token: i.e.
>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>> This patch is meant to support a new class of IO host controller
>> that are not PCI based and that still require to have the IO addresses
>> be translated in the same PIO token space as the PCI controller
> 
> IOW, this is ARM-specific, right?

Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.
But, I think the handler driver is architecture dependent.

Thanks,
Zhichang

> 
> Thanks,
> Rafael
> 

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
  2017-03-30 15:26   ` zhichang.yuan
  (?)
  (?)
@ 2017-04-01  5:58     ` kbuild test robot
  -1 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  5:58 UTC (permalink / raw)
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, mark.rutland,
	brian.starkey, olof, lorenzo.pieralisi, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, minyard,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

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

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
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 error/warnings (new ones prefixed by >>):

>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
                       ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:41:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:42:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
      ^
   lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: error: array index in initializer not of integer type
     [PIO_INDIRECT] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:47:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
      ^
   lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:48:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
      ^
   lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:49:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
      ^
   lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
     idle_start = root->sec_min;
                      ^~
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^

vim +/PIO_MAX_SECT +32 lib/logic_pio.c

    12	 * GNU General Public License for more details.
    13	 *
    14	 * You should have received a copy of the GNU General Public License
    15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16	 */
    17	
  > 18	#include <linux/of.h>
    19	#include <linux/io.h>
    20	#include <linux/mm.h>
    21	#include <linux/rculist.h>
    22	#include <linux/sizes.h>
    23	#include <linux/slab.h>
    24	
    25	/* The unique hardware address list. */
    26	static LIST_HEAD(io_range_list);
    27	static DEFINE_MUTEX(io_range_mutex);
    28	
    29	/*
    30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
    31	 */
  > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
    33	#ifdef CONFIG_INDIRECT_PIO
    34		/*
    35		 * At this moment, assign all the other logic PIO space to MMIO.
    36		 * If more elements added, please adjust the ending index and .sec_max;
    37		 * Please keep MMIO element started from index ZERO.
    38		 */
  > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
  > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
  > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
  > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
    43		},
    44	
    45		/* The last element */
    46		[PIO_INDIRECT] = {
    47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
    48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
    49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
    50		},
    51	#else
    52		[PIO_CPU_MMIO] = {
    53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
    54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
    55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
    56		},
    57	
    58	#endif
    59	};
    60	
    61	/*
    62	 * Search a io_range registered which match the fwnode and addr.
    63	 *
    64	 * @fwnode: the host fwnode which must be valid;
    65	 * @start: the start hardware address of this search;
    66	 * @end: the end hardware address of this search. can be equal to @start;
    67	 *
    68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
    69	 * valid virtual address represent a matched node was found.
    70	 */
    71	static struct logic_pio_hwaddr *
    72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
    73				resource_size_t start, resource_size_t end)
    74	{
    75		struct logic_pio_hwaddr *range;
    76	
  > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
    78			if (!range->pio_peer) {
    79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
    80					&range->hw_start);
    81				continue;
    82			}
    83			if (range->fwnode != fwnode)
    84				continue;
    85			/* without any overlap with current range */
    86			if (start >= range->hw_start + range->size ||
    87				end < range->hw_start)
    88				continue;
    89			/* overlap is not supported now. */
    90			if (start < range->hw_start ||
    91				end >= range->hw_start + range->size)
    92				return ERR_PTR(-EBUSY);
    93			/* had been registered. */
    94			return range;
    95		}
    96	
    97		return NULL;
    98	}
    99	
   100	
   101	static int logic_pio_alloc_range(struct logic_pio_root *root,
   102			resource_size_t size, unsigned long align,
   103			struct list_head **prev, resource_size_t *pio_alloc)
   104	{
   105		struct logic_pio_sect *entry;
   106		resource_size_t tmp_start;
   107		resource_size_t idle_start, idle_end;
   108	
 > 109		idle_start = root->sec_min;
   110		*prev = &root->sec_head;
   111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
   112			if (!entry->hwpeer ||
   113				idle_start > entry->io_start) {
   114				WARN(1, "skip an invalid io range during traversal!\n");
   115				goto nextentry;
   116			}
   117			/* set the end edge. */
   118			if (idle_start == entry->io_start) {
   119				struct logic_pio_sect *next;
   120	
   121				idle_start = entry->io_start + entry->hwpeer->size;
 > 122				next = list_next_or_null_rcu(&root->sec_head,
 > 123					&entry->list, struct logic_pio_sect, list);
   124				if (next) {
   125					entry = next;
   126				} else {
   127					*prev = &entry->list;
   128					break;
   129				}
   130			}
   131			idle_end = entry->io_start - 1;
   132	
   133			/* contiguous range... */
   134			if (idle_start > idle_end)
   135				goto nextentry;
   136	
   137			tmp_start = idle_start;
   138			idle_start = ALIGN(idle_start, align);
   139			if (idle_start >= tmp_start &&
   140				idle_start + size <= idle_end) {
   141				*prev = &entry->list;
   142				*pio_alloc = idle_start;
   143				return 0;
   144			}
   145	
   146	nextentry:
   147			idle_start = entry->io_start + entry->hwpeer->size;
   148			*prev = &entry->list;
   149		}
   150		/* check the last free gap... */
   151		idle_end = root->sec_max;
   152	
   153		tmp_start = idle_start;
   154		idle_start = ALIGN(idle_start, align);
   155		if (idle_start >= tmp_start &&
   156			idle_start + size <= idle_end) {
   157			*pio_alloc = idle_start;
   158			return 0;
   159		}
   160	
   161		return -EBUSY;
   162	}
   163	
   164	/*
   165	 * register a io range node in the io range list.
   166	 *
   167	 * @newrange: pointer to the io range to be registered.
   168	 *
   169	 * return 'newrange' when success, ERR_VALUE() is for failures.
   170	 * specially, return a valid pointer which is not equal to 'newrange' when
   171	 * the io range had been registered before.
   172	 */
   173	struct logic_pio_hwaddr
   174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
   175			unsigned long align)
   176	{
   177		struct logic_pio_hwaddr *range;
   178		struct logic_pio_sect *newsect;
   179		resource_size_t pio_alloc;
   180		struct list_head *prev, *hwprev;
   181		unsigned long sect_id;
   182		int err;
   183	
   184		if (!newrange || !newrange->fwnode || !newrange->size)
   185			return ERR_PTR(-EINVAL);
   186	
   187		sect_id = newrange->flags;
   188		if (sect_id >= PIO_MAX_SECT)
   189			return ERR_PTR(-EINVAL);
   190	
   191		mutex_lock(&io_range_mutex);
   192		range = logic_pio_find_range_byaddr(newrange->fwnode,
   193				newrange->hw_start,
   194				newrange->hw_start + newrange->size - 1);
   195		if (range) {
   196			if (!IS_ERR(range))
   197				pr_info("the request IO range had been registered!\n");
   198			else
   199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
   200					&newrange->hw_start, &newrange->size);
   201			mutex_unlock(&io_range_mutex);
   202			return range;
   203		}
   204	
   205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
   206				newrange->size, align, &prev, &pio_alloc);
   207		if (err) {
   208			pr_err("can't find free %pa logical IO range!\n",
   209				&newrange->size);
   210			goto exitproc;
   211		}
   212	
   213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
   214			hwprev = &io_range_list;
   215		} else {
 > 216			newsect = to_pio_sect(prev);
 > 217			hwprev = &newsect->hwpeer->list;
   218		}
   219	
   220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);

---
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: 49584 bytes --]

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-01  5:58     ` kbuild test robot
  0 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  5:58 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, mark.rutland,
	brian.starkey, olof, lorenzo.pieralisi, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, minyard,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

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

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
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 error/warnings (new ones prefixed by >>):

>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
                       ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:41:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:42:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
      ^
   lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: error: array index in initializer not of integer type
     [PIO_INDIRECT] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:47:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
      ^
   lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:48:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
      ^
   lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:49:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
      ^
   lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
     idle_start = root->sec_min;
                      ^~
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^

vim +/PIO_MAX_SECT +32 lib/logic_pio.c

    12	 * GNU General Public License for more details.
    13	 *
    14	 * You should have received a copy of the GNU General Public License
    15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16	 */
    17	
  > 18	#include <linux/of.h>
    19	#include <linux/io.h>
    20	#include <linux/mm.h>
    21	#include <linux/rculist.h>
    22	#include <linux/sizes.h>
    23	#include <linux/slab.h>
    24	
    25	/* The unique hardware address list. */
    26	static LIST_HEAD(io_range_list);
    27	static DEFINE_MUTEX(io_range_mutex);
    28	
    29	/*
    30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
    31	 */
  > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
    33	#ifdef CONFIG_INDIRECT_PIO
    34		/*
    35		 * At this moment, assign all the other logic PIO space to MMIO.
    36		 * If more elements added, please adjust the ending index and .sec_max;
    37		 * Please keep MMIO element started from index ZERO.
    38		 */
  > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
  > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
  > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
  > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
    43		},
    44	
    45		/* The last element */
    46		[PIO_INDIRECT] = {
    47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
    48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
    49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
    50		},
    51	#else
    52		[PIO_CPU_MMIO] = {
    53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
    54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
    55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
    56		},
    57	
    58	#endif
    59	};
    60	
    61	/*
    62	 * Search a io_range registered which match the fwnode and addr.
    63	 *
    64	 * @fwnode: the host fwnode which must be valid;
    65	 * @start: the start hardware address of this search;
    66	 * @end: the end hardware address of this search. can be equal to @start;
    67	 *
    68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
    69	 * valid virtual address represent a matched node was found.
    70	 */
    71	static struct logic_pio_hwaddr *
    72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
    73				resource_size_t start, resource_size_t end)
    74	{
    75		struct logic_pio_hwaddr *range;
    76	
  > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
    78			if (!range->pio_peer) {
    79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
    80					&range->hw_start);
    81				continue;
    82			}
    83			if (range->fwnode != fwnode)
    84				continue;
    85			/* without any overlap with current range */
    86			if (start >= range->hw_start + range->size ||
    87				end < range->hw_start)
    88				continue;
    89			/* overlap is not supported now. */
    90			if (start < range->hw_start ||
    91				end >= range->hw_start + range->size)
    92				return ERR_PTR(-EBUSY);
    93			/* had been registered. */
    94			return range;
    95		}
    96	
    97		return NULL;
    98	}
    99	
   100	
   101	static int logic_pio_alloc_range(struct logic_pio_root *root,
   102			resource_size_t size, unsigned long align,
   103			struct list_head **prev, resource_size_t *pio_alloc)
   104	{
   105		struct logic_pio_sect *entry;
   106		resource_size_t tmp_start;
   107		resource_size_t idle_start, idle_end;
   108	
 > 109		idle_start = root->sec_min;
   110		*prev = &root->sec_head;
   111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
   112			if (!entry->hwpeer ||
   113				idle_start > entry->io_start) {
   114				WARN(1, "skip an invalid io range during traversal!\n");
   115				goto nextentry;
   116			}
   117			/* set the end edge. */
   118			if (idle_start == entry->io_start) {
   119				struct logic_pio_sect *next;
   120	
   121				idle_start = entry->io_start + entry->hwpeer->size;
 > 122				next = list_next_or_null_rcu(&root->sec_head,
 > 123					&entry->list, struct logic_pio_sect, list);
   124				if (next) {
   125					entry = next;
   126				} else {
   127					*prev = &entry->list;
   128					break;
   129				}
   130			}
   131			idle_end = entry->io_start - 1;
   132	
   133			/* contiguous range... */
   134			if (idle_start > idle_end)
   135				goto nextentry;
   136	
   137			tmp_start = idle_start;
   138			idle_start = ALIGN(idle_start, align);
   139			if (idle_start >= tmp_start &&
   140				idle_start + size <= idle_end) {
   141				*prev = &entry->list;
   142				*pio_alloc = idle_start;
   143				return 0;
   144			}
   145	
   146	nextentry:
   147			idle_start = entry->io_start + entry->hwpeer->size;
   148			*prev = &entry->list;
   149		}
   150		/* check the last free gap... */
   151		idle_end = root->sec_max;
   152	
   153		tmp_start = idle_start;
   154		idle_start = ALIGN(idle_start, align);
   155		if (idle_start >= tmp_start &&
   156			idle_start + size <= idle_end) {
   157			*pio_alloc = idle_start;
   158			return 0;
   159		}
   160	
   161		return -EBUSY;
   162	}
   163	
   164	/*
   165	 * register a io range node in the io range list.
   166	 *
   167	 * @newrange: pointer to the io range to be registered.
   168	 *
   169	 * return 'newrange' when success, ERR_VALUE() is for failures.
   170	 * specially, return a valid pointer which is not equal to 'newrange' when
   171	 * the io range had been registered before.
   172	 */
   173	struct logic_pio_hwaddr
   174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
   175			unsigned long align)
   176	{
   177		struct logic_pio_hwaddr *range;
   178		struct logic_pio_sect *newsect;
   179		resource_size_t pio_alloc;
   180		struct list_head *prev, *hwprev;
   181		unsigned long sect_id;
   182		int err;
   183	
   184		if (!newrange || !newrange->fwnode || !newrange->size)
   185			return ERR_PTR(-EINVAL);
   186	
   187		sect_id = newrange->flags;
   188		if (sect_id >= PIO_MAX_SECT)
   189			return ERR_PTR(-EINVAL);
   190	
   191		mutex_lock(&io_range_mutex);
   192		range = logic_pio_find_range_byaddr(newrange->fwnode,
   193				newrange->hw_start,
   194				newrange->hw_start + newrange->size - 1);
   195		if (range) {
   196			if (!IS_ERR(range))
   197				pr_info("the request IO range had been registered!\n");
   198			else
   199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
   200					&newrange->hw_start, &newrange->size);
   201			mutex_unlock(&io_range_mutex);
   202			return range;
   203		}
   204	
   205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
   206				newrange->size, align, &prev, &pio_alloc);
   207		if (err) {
   208			pr_err("can't find free %pa logical IO range!\n",
   209				&newrange->size);
   210			goto exitproc;
   211		}
   212	
   213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
   214			hwprev = &io_range_list;
   215		} else {
 > 216			newsect = to_pio_sect(prev);
 > 217			hwprev = &newsect->hwpeer->list;
   218		}
   219	
   220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);

---
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: 49584 bytes --]

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-01  5:58     ` kbuild test robot
  0 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  5:58 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: mark.rutland, benh, gabriele.paoloni, rafael, linux-pci,
	will.deacon, linuxarm, frowand.list, lorenzo.pieralisi, arnd,
	xuwei5, linux-acpi, catalin.marinas, devicetree, minyard,
	john.garry, olof, robh+dt, bhelgaas, kantyzc, zhichang.yuan02,
	linux-arm-kernel, linux-kernel, zhichang.yuan, kbuild-all,
	zourongrong, brian.starkey

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

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
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 error/warnings (new ones prefixed by >>):

>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
                       ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:41:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:42:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
      ^
   lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: error: array index in initializer not of integer type
     [PIO_INDIRECT] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:47:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
      ^
   lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:48:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
      ^
   lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:49:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
      ^
   lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
     idle_start = root->sec_min;
                      ^~
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^

vim +/PIO_MAX_SECT +32 lib/logic_pio.c

    12	 * GNU General Public License for more details.
    13	 *
    14	 * You should have received a copy of the GNU General Public License
    15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16	 */
    17	
  > 18	#include <linux/of.h>
    19	#include <linux/io.h>
    20	#include <linux/mm.h>
    21	#include <linux/rculist.h>
    22	#include <linux/sizes.h>
    23	#include <linux/slab.h>
    24	
    25	/* The unique hardware address list. */
    26	static LIST_HEAD(io_range_list);
    27	static DEFINE_MUTEX(io_range_mutex);
    28	
    29	/*
    30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
    31	 */
  > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
    33	#ifdef CONFIG_INDIRECT_PIO
    34		/*
    35		 * At this moment, assign all the other logic PIO space to MMIO.
    36		 * If more elements added, please adjust the ending index and .sec_max;
    37		 * Please keep MMIO element started from index ZERO.
    38		 */
  > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
  > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
  > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
  > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
    43		},
    44	
    45		/* The last element */
    46		[PIO_INDIRECT] = {
    47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
    48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
    49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
    50		},
    51	#else
    52		[PIO_CPU_MMIO] = {
    53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
    54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
    55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
    56		},
    57	
    58	#endif
    59	};
    60	
    61	/*
    62	 * Search a io_range registered which match the fwnode and addr.
    63	 *
    64	 * @fwnode: the host fwnode which must be valid;
    65	 * @start: the start hardware address of this search;
    66	 * @end: the end hardware address of this search. can be equal to @start;
    67	 *
    68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
    69	 * valid virtual address represent a matched node was found.
    70	 */
    71	static struct logic_pio_hwaddr *
    72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
    73				resource_size_t start, resource_size_t end)
    74	{
    75		struct logic_pio_hwaddr *range;
    76	
  > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
    78			if (!range->pio_peer) {
    79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
    80					&range->hw_start);
    81				continue;
    82			}
    83			if (range->fwnode != fwnode)
    84				continue;
    85			/* without any overlap with current range */
    86			if (start >= range->hw_start + range->size ||
    87				end < range->hw_start)
    88				continue;
    89			/* overlap is not supported now. */
    90			if (start < range->hw_start ||
    91				end >= range->hw_start + range->size)
    92				return ERR_PTR(-EBUSY);
    93			/* had been registered. */
    94			return range;
    95		}
    96	
    97		return NULL;
    98	}
    99	
   100	
   101	static int logic_pio_alloc_range(struct logic_pio_root *root,
   102			resource_size_t size, unsigned long align,
   103			struct list_head **prev, resource_size_t *pio_alloc)
   104	{
   105		struct logic_pio_sect *entry;
   106		resource_size_t tmp_start;
   107		resource_size_t idle_start, idle_end;
   108	
 > 109		idle_start = root->sec_min;
   110		*prev = &root->sec_head;
   111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
   112			if (!entry->hwpeer ||
   113				idle_start > entry->io_start) {
   114				WARN(1, "skip an invalid io range during traversal!\n");
   115				goto nextentry;
   116			}
   117			/* set the end edge. */
   118			if (idle_start == entry->io_start) {
   119				struct logic_pio_sect *next;
   120	
   121				idle_start = entry->io_start + entry->hwpeer->size;
 > 122				next = list_next_or_null_rcu(&root->sec_head,
 > 123					&entry->list, struct logic_pio_sect, list);
   124				if (next) {
   125					entry = next;
   126				} else {
   127					*prev = &entry->list;
   128					break;
   129				}
   130			}
   131			idle_end = entry->io_start - 1;
   132	
   133			/* contiguous range... */
   134			if (idle_start > idle_end)
   135				goto nextentry;
   136	
   137			tmp_start = idle_start;
   138			idle_start = ALIGN(idle_start, align);
   139			if (idle_start >= tmp_start &&
   140				idle_start + size <= idle_end) {
   141				*prev = &entry->list;
   142				*pio_alloc = idle_start;
   143				return 0;
   144			}
   145	
   146	nextentry:
   147			idle_start = entry->io_start + entry->hwpeer->size;
   148			*prev = &entry->list;
   149		}
   150		/* check the last free gap... */
   151		idle_end = root->sec_max;
   152	
   153		tmp_start = idle_start;
   154		idle_start = ALIGN(idle_start, align);
   155		if (idle_start >= tmp_start &&
   156			idle_start + size <= idle_end) {
   157			*pio_alloc = idle_start;
   158			return 0;
   159		}
   160	
   161		return -EBUSY;
   162	}
   163	
   164	/*
   165	 * register a io range node in the io range list.
   166	 *
   167	 * @newrange: pointer to the io range to be registered.
   168	 *
   169	 * return 'newrange' when success, ERR_VALUE() is for failures.
   170	 * specially, return a valid pointer which is not equal to 'newrange' when
   171	 * the io range had been registered before.
   172	 */
   173	struct logic_pio_hwaddr
   174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
   175			unsigned long align)
   176	{
   177		struct logic_pio_hwaddr *range;
   178		struct logic_pio_sect *newsect;
   179		resource_size_t pio_alloc;
   180		struct list_head *prev, *hwprev;
   181		unsigned long sect_id;
   182		int err;
   183	
   184		if (!newrange || !newrange->fwnode || !newrange->size)
   185			return ERR_PTR(-EINVAL);
   186	
   187		sect_id = newrange->flags;
   188		if (sect_id >= PIO_MAX_SECT)
   189			return ERR_PTR(-EINVAL);
   190	
   191		mutex_lock(&io_range_mutex);
   192		range = logic_pio_find_range_byaddr(newrange->fwnode,
   193				newrange->hw_start,
   194				newrange->hw_start + newrange->size - 1);
   195		if (range) {
   196			if (!IS_ERR(range))
   197				pr_info("the request IO range had been registered!\n");
   198			else
   199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
   200					&newrange->hw_start, &newrange->size);
   201			mutex_unlock(&io_range_mutex);
   202			return range;
   203		}
   204	
   205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
   206				newrange->size, align, &prev, &pio_alloc);
   207		if (err) {
   208			pr_err("can't find free %pa logical IO range!\n",
   209				&newrange->size);
   210			goto exitproc;
   211		}
   212	
   213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
   214			hwprev = &io_range_list;
   215		} else {
 > 216			newsect = to_pio_sect(prev);
 > 217			hwprev = &newsect->hwpeer->list;
   218		}
   219	
   220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);

---
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: 49584 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-01  5:58     ` kbuild test robot
  0 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  5:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
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 error/warnings (new ones prefixed by >>):

>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
                       ^~~~~~~~~~~~
>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
     [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:41:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:42:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
      ^
   lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
                 ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: error: array index in initializer not of integer type
     [PIO_INDIRECT] = {
      ^~~~~~~~~~~~
   lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:47:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
      ^
   lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:48:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
      ^
   lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:49:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
      ^
   lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^~~~~~~~~~~~
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^~~~~~~~~~~~~~
>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
     idle_start = root->sec_min;
                      ^~
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^~~~~~~~~~~~~~
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^~~~~~~~~~~~~~~~~~~~~~~
>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^

vim +/PIO_MAX_SECT +32 lib/logic_pio.c

    12	 * GNU General Public License for more details.
    13	 *
    14	 * You should have received a copy of the GNU General Public License
    15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16	 */
    17	
  > 18	#include <linux/of.h>
    19	#include <linux/io.h>
    20	#include <linux/mm.h>
    21	#include <linux/rculist.h>
    22	#include <linux/sizes.h>
    23	#include <linux/slab.h>
    24	
    25	/* The unique hardware address list. */
    26	static LIST_HEAD(io_range_list);
    27	static DEFINE_MUTEX(io_range_mutex);
    28	
    29	/*
    30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
    31	 */
  > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
    33	#ifdef CONFIG_INDIRECT_PIO
    34		/*
    35		 * At this moment, assign all the other logic PIO space to MMIO.
    36		 * If more elements added, please adjust the ending index and .sec_max;
    37		 * Please keep MMIO element started from index ZERO.
    38		 */
  > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
  > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
  > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
  > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
    43		},
    44	
    45		/* The last element */
    46		[PIO_INDIRECT] = {
    47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
    48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
    49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
    50		},
    51	#else
    52		[PIO_CPU_MMIO] = {
    53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
    54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
    55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
    56		},
    57	
    58	#endif
    59	};
    60	
    61	/*
    62	 * Search a io_range registered which match the fwnode and addr.
    63	 *
    64	 * @fwnode: the host fwnode which must be valid;
    65	 * @start: the start hardware address of this search;
    66	 * @end: the end hardware address of this search. can be equal to @start;
    67	 *
    68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
    69	 * valid virtual address represent a matched node was found.
    70	 */
    71	static struct logic_pio_hwaddr *
    72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
    73				resource_size_t start, resource_size_t end)
    74	{
    75		struct logic_pio_hwaddr *range;
    76	
  > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
    78			if (!range->pio_peer) {
    79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
    80					&range->hw_start);
    81				continue;
    82			}
    83			if (range->fwnode != fwnode)
    84				continue;
    85			/* without any overlap with current range */
    86			if (start >= range->hw_start + range->size ||
    87				end < range->hw_start)
    88				continue;
    89			/* overlap is not supported now. */
    90			if (start < range->hw_start ||
    91				end >= range->hw_start + range->size)
    92				return ERR_PTR(-EBUSY);
    93			/* had been registered. */
    94			return range;
    95		}
    96	
    97		return NULL;
    98	}
    99	
   100	
   101	static int logic_pio_alloc_range(struct logic_pio_root *root,
   102			resource_size_t size, unsigned long align,
   103			struct list_head **prev, resource_size_t *pio_alloc)
   104	{
   105		struct logic_pio_sect *entry;
   106		resource_size_t tmp_start;
   107		resource_size_t idle_start, idle_end;
   108	
 > 109		idle_start = root->sec_min;
   110		*prev = &root->sec_head;
   111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
   112			if (!entry->hwpeer ||
   113				idle_start > entry->io_start) {
   114				WARN(1, "skip an invalid io range during traversal!\n");
   115				goto nextentry;
   116			}
   117			/* set the end edge. */
   118			if (idle_start == entry->io_start) {
   119				struct logic_pio_sect *next;
   120	
   121				idle_start = entry->io_start + entry->hwpeer->size;
 > 122				next = list_next_or_null_rcu(&root->sec_head,
 > 123					&entry->list, struct logic_pio_sect, list);
   124				if (next) {
   125					entry = next;
   126				} else {
   127					*prev = &entry->list;
   128					break;
   129				}
   130			}
   131			idle_end = entry->io_start - 1;
   132	
   133			/* contiguous range... */
   134			if (idle_start > idle_end)
   135				goto nextentry;
   136	
   137			tmp_start = idle_start;
   138			idle_start = ALIGN(idle_start, align);
   139			if (idle_start >= tmp_start &&
   140				idle_start + size <= idle_end) {
   141				*prev = &entry->list;
   142				*pio_alloc = idle_start;
   143				return 0;
   144			}
   145	
   146	nextentry:
   147			idle_start = entry->io_start + entry->hwpeer->size;
   148			*prev = &entry->list;
   149		}
   150		/* check the last free gap... */
   151		idle_end = root->sec_max;
   152	
   153		tmp_start = idle_start;
   154		idle_start = ALIGN(idle_start, align);
   155		if (idle_start >= tmp_start &&
   156			idle_start + size <= idle_end) {
   157			*pio_alloc = idle_start;
   158			return 0;
   159		}
   160	
   161		return -EBUSY;
   162	}
   163	
   164	/*
   165	 * register a io range node in the io range list.
   166	 *
   167	 * @newrange: pointer to the io range to be registered.
   168	 *
   169	 * return 'newrange' when success, ERR_VALUE() is for failures.
   170	 * specially, return a valid pointer which is not equal to 'newrange' when
   171	 * the io range had been registered before.
   172	 */
   173	struct logic_pio_hwaddr
   174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
   175			unsigned long align)
   176	{
   177		struct logic_pio_hwaddr *range;
   178		struct logic_pio_sect *newsect;
   179		resource_size_t pio_alloc;
   180		struct list_head *prev, *hwprev;
   181		unsigned long sect_id;
   182		int err;
   183	
   184		if (!newrange || !newrange->fwnode || !newrange->size)
   185			return ERR_PTR(-EINVAL);
   186	
   187		sect_id = newrange->flags;
   188		if (sect_id >= PIO_MAX_SECT)
   189			return ERR_PTR(-EINVAL);
   190	
   191		mutex_lock(&io_range_mutex);
   192		range = logic_pio_find_range_byaddr(newrange->fwnode,
   193				newrange->hw_start,
   194				newrange->hw_start + newrange->size - 1);
   195		if (range) {
   196			if (!IS_ERR(range))
   197				pr_info("the request IO range had been registered!\n");
   198			else
   199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
   200					&newrange->hw_start, &newrange->size);
   201			mutex_unlock(&io_range_mutex);
   202			return range;
   203		}
   204	
   205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
   206				newrange->size, align, &prev, &pio_alloc);
   207		if (err) {
   208			pr_err("can't find free %pa logical IO range!\n",
   209				&newrange->size);
   210			goto exitproc;
   211		}
   212	
   213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
   214			hwprev = &io_range_list;
   215		} else {
 > 216			newsect = to_pio_sect(prev);
 > 217			hwprev = &newsect->hwpeer->list;
   218		}
   219	
   220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 49584 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170401/a8a24a37/attachment-0001.gz>

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
  2017-03-30 15:26   ` zhichang.yuan
  (?)
@ 2017-04-01  6:31     ` kbuild test robot
  -1 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  6:31 UTC (permalink / raw)
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, mark.rutland,
	brian.starkey, olof, lorenzo.pieralisi, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, minyard,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

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

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
config: m68k-m5475evb_defconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 4.9.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=m68k 

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

   lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^
   lib/logic_pio.c:52:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO] = {
      ^
   lib/logic_pio.c:52:2: error: array index in initializer not of integer type
     [PIO_CPU_MMIO] = {
     ^
   lib/logic_pio.c:52:2: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:53:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:53:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:54:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
   lib/logic_pio.c:55:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:55:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:55:3: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization from incompatible pointer type
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/pid.h:4:0,
                    from include/linux/sched.h:13,
                    from arch/m68k/include/asm/pgtable_mm.h:10,
                    from arch/m68k/include/asm/pgtable.h:4,
                    from include/linux/mm.h:68,
                    from lib/logic_pio.c:20:
   include/linux/rculist.h:352:7: error: dereferencing pointer to incomplete type
      &pos->member != (head); \
          ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, 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/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> lib/logic_pio.c:78:13: error: dereferencing pointer to incomplete type
      if (!range->pio_peer) {
                ^
   In file included from include/linux/kernel.h:13:0,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c:80:11: error: dereferencing pointer to incomplete type
        &range->hw_start);
              ^
   include/linux/printk.h:303:37: note: in definition of macro 'pr_warning'
     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
                                        ^
>> lib/logic_pio.c:79:4: note: in expansion of macro 'pr_warn'
       pr_warn("Invalid cpu addr node(%pa) in list!\n",
       ^
   lib/logic_pio.c:83:12: error: dereferencing pointer to incomplete type
      if (range->fwnode != fwnode)
               ^
   lib/logic_pio.c:86:21: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                        ^
   lib/logic_pio.c:86:39: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                                          ^
   lib/logic_pio.c:87:15: error: dereferencing pointer to incomplete type
       end < range->hw_start)
                  ^
   lib/logic_pio.c:90:20: error: dereferencing pointer to incomplete type
      if (start < range->hw_start ||
                       ^
   lib/logic_pio.c:91:16: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                   ^
   lib/logic_pio.c:91:34: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                                     ^
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
   lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type
     idle_start = root->sec_min;
                      ^
   lib/logic_pio.c:110:15: error: dereferencing pointer to incomplete type
     *prev = &root->sec_head;
                  ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^

vim +351 include/linux/rculist.h

3943f42c Andrey Utkin         2014-11-14  271   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  272   *
72c6a987 Jiri Pirko           2009-04-14  273   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  274   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  275   */
72c6a987 Jiri Pirko           2009-04-14  276  #define list_entry_rcu(ptr, type, member) \
8db70b13 Patrick Marlier      2015-09-11 @277  	container_of(lockless_dereference(ptr), type, member)
72c6a987 Jiri Pirko           2009-04-14  278  
72c6a987 Jiri Pirko           2009-04-14  279  /**
f88022a4 Michel Machado       2012-04-10  280   * Where are list_empty_rcu() and list_first_entry_rcu()?
f88022a4 Michel Machado       2012-04-10  281   *
f88022a4 Michel Machado       2012-04-10  282   * Implementing those functions following their counterparts list_empty() and
f88022a4 Michel Machado       2012-04-10  283   * list_first_entry() is not advisable because they lead to subtle race
f88022a4 Michel Machado       2012-04-10  284   * conditions as the following snippet shows:
f88022a4 Michel Machado       2012-04-10  285   *
f88022a4 Michel Machado       2012-04-10  286   * if (!list_empty_rcu(mylist)) {
f88022a4 Michel Machado       2012-04-10  287   *	struct foo *bar = list_first_entry_rcu(mylist, struct foo, list_member);
f88022a4 Michel Machado       2012-04-10  288   *	do_something(bar);
f88022a4 Michel Machado       2012-04-10  289   * }
f88022a4 Michel Machado       2012-04-10  290   *
f88022a4 Michel Machado       2012-04-10  291   * The list may not be empty when list_empty_rcu checks it, but it may be when
f88022a4 Michel Machado       2012-04-10  292   * list_first_entry_rcu rereads the ->next pointer.
f88022a4 Michel Machado       2012-04-10  293   *
f88022a4 Michel Machado       2012-04-10  294   * Rereading the ->next pointer is not a problem for list_empty() and
f88022a4 Michel Machado       2012-04-10  295   * list_first_entry() because they would be protected by a lock that blocks
f88022a4 Michel Machado       2012-04-10  296   * writers.
f88022a4 Michel Machado       2012-04-10  297   *
f88022a4 Michel Machado       2012-04-10  298   * See list_first_or_null_rcu for an alternative.
f88022a4 Michel Machado       2012-04-10  299   */
f88022a4 Michel Machado       2012-04-10  300  
f88022a4 Michel Machado       2012-04-10  301  /**
f88022a4 Michel Machado       2012-04-10  302   * list_first_or_null_rcu - get the first element from a list
72c6a987 Jiri Pirko           2009-04-14  303   * @ptr:        the list head to take the element from.
72c6a987 Jiri Pirko           2009-04-14  304   * @type:       the type of the struct this is embedded in.
3943f42c Andrey Utkin         2014-11-14  305   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  306   *
f88022a4 Michel Machado       2012-04-10  307   * Note that if the list is empty, it returns NULL.
72c6a987 Jiri Pirko           2009-04-14  308   *
72c6a987 Jiri Pirko           2009-04-14  309   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  310   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  311   */
f88022a4 Michel Machado       2012-04-10  312  #define list_first_or_null_rcu(ptr, type, member) \
0adab9b9 Joe Perches          2013-12-05  313  ({ \
0adab9b9 Joe Perches          2013-12-05  314  	struct list_head *__ptr = (ptr); \
7d0ae808 Paul E. McKenney     2015-03-03  315  	struct list_head *__next = READ_ONCE(__ptr->next); \
0adab9b9 Joe Perches          2013-12-05  316  	likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
f88022a4 Michel Machado       2012-04-10  317  })
72c6a987 Jiri Pirko           2009-04-14  318  
82524746 Franck Bui-Huu       2008-05-12  319  /**
ff3c44e6 Tom Herbert          2016-03-07  320   * list_next_or_null_rcu - get the first element from a list
ff3c44e6 Tom Herbert          2016-03-07  321   * @head:	the head for the list.
ff3c44e6 Tom Herbert          2016-03-07  322   * @ptr:        the list head to take the next element from.
ff3c44e6 Tom Herbert          2016-03-07  323   * @type:       the type of the struct this is embedded in.
ff3c44e6 Tom Herbert          2016-03-07  324   * @member:     the name of the list_head within the struct.
ff3c44e6 Tom Herbert          2016-03-07  325   *
ff3c44e6 Tom Herbert          2016-03-07  326   * Note that if the ptr is at the end of the list, NULL is returned.
ff3c44e6 Tom Herbert          2016-03-07  327   *
ff3c44e6 Tom Herbert          2016-03-07  328   * This primitive may safely run concurrently with the _rcu list-mutation
ff3c44e6 Tom Herbert          2016-03-07  329   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
ff3c44e6 Tom Herbert          2016-03-07  330   */
ff3c44e6 Tom Herbert          2016-03-07  331  #define list_next_or_null_rcu(head, ptr, type, member) \
ff3c44e6 Tom Herbert          2016-03-07  332  ({ \
ff3c44e6 Tom Herbert          2016-03-07  333  	struct list_head *__head = (head); \
ff3c44e6 Tom Herbert          2016-03-07  334  	struct list_head *__ptr = (ptr); \
ff3c44e6 Tom Herbert          2016-03-07  335  	struct list_head *__next = READ_ONCE(__ptr->next); \
ff3c44e6 Tom Herbert          2016-03-07  336  	likely(__next != __head) ? list_entry_rcu(__next, type, \
ff3c44e6 Tom Herbert          2016-03-07  337  						  member) : NULL; \
ff3c44e6 Tom Herbert          2016-03-07  338  })
ff3c44e6 Tom Herbert          2016-03-07  339  
ff3c44e6 Tom Herbert          2016-03-07  340  /**
82524746 Franck Bui-Huu       2008-05-12  341   * list_for_each_entry_rcu	-	iterate over rcu list of given type
82524746 Franck Bui-Huu       2008-05-12  342   * @pos:	the type * to use as a loop cursor.
82524746 Franck Bui-Huu       2008-05-12  343   * @head:	the head for your list.
3943f42c Andrey Utkin         2014-11-14  344   * @member:	the name of the list_head within the struct.
82524746 Franck Bui-Huu       2008-05-12  345   *
82524746 Franck Bui-Huu       2008-05-12  346   * This list-traversal primitive may safely run concurrently with
82524746 Franck Bui-Huu       2008-05-12  347   * the _rcu list-mutation primitives such as list_add_rcu()
82524746 Franck Bui-Huu       2008-05-12  348   * as long as the traversal is guarded by rcu_read_lock().
82524746 Franck Bui-Huu       2008-05-12  349   */
82524746 Franck Bui-Huu       2008-05-12  350  #define list_for_each_entry_rcu(pos, head, member) \
72c6a987 Jiri Pirko           2009-04-14 @351  	for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
e66eed65 Linus Torvalds       2011-05-19  352  		&pos->member != (head); \
72c6a987 Jiri Pirko           2009-04-14 @353  		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
82524746 Franck Bui-Huu       2008-05-12  354  
82524746 Franck Bui-Huu       2008-05-12  355  /**
69b90729 Alexey Kardashevskiy 2015-12-05  356   * list_entry_lockless - get the struct for this entry

:::::: The code at line 351 was first introduced by commit
:::::: 72c6a9870f901045f2464c3dc6ee8914bfdc07aa rculist.h: introduce list_entry_rcu() and list_first_entry_rcu()

:::::: TO: Jiri Pirko <jpirko@redhat.com>
:::::: CC: Ingo Molnar <mingo@elte.hu>

---
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: 6383 bytes --]

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-01  6:31     ` kbuild test robot
  0 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  6:31 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: kbuild-all, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, mark.rutland,
	brian.starkey, olof, lorenzo.pieralisi, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, minyard,
	zourongrong, john.garry, gabriele.paoloni, zhichang.yuan02,
	kantyzc, xuwei5, zhichang.yuan

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

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
config: m68k-m5475evb_defconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 4.9.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=m68k 

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

   lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^
   lib/logic_pio.c:52:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO] = {
      ^
   lib/logic_pio.c:52:2: error: array index in initializer not of integer type
     [PIO_CPU_MMIO] = {
     ^
   lib/logic_pio.c:52:2: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:53:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:53:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:54:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
   lib/logic_pio.c:55:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:55:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:55:3: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization from incompatible pointer type
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/pid.h:4:0,
                    from include/linux/sched.h:13,
                    from arch/m68k/include/asm/pgtable_mm.h:10,
                    from arch/m68k/include/asm/pgtable.h:4,
                    from include/linux/mm.h:68,
                    from lib/logic_pio.c:20:
   include/linux/rculist.h:352:7: error: dereferencing pointer to incomplete type
      &pos->member != (head); \
          ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, 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/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> lib/logic_pio.c:78:13: error: dereferencing pointer to incomplete type
      if (!range->pio_peer) {
                ^
   In file included from include/linux/kernel.h:13:0,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c:80:11: error: dereferencing pointer to incomplete type
        &range->hw_start);
              ^
   include/linux/printk.h:303:37: note: in definition of macro 'pr_warning'
     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
                                        ^
>> lib/logic_pio.c:79:4: note: in expansion of macro 'pr_warn'
       pr_warn("Invalid cpu addr node(%pa) in list!\n",
       ^
   lib/logic_pio.c:83:12: error: dereferencing pointer to incomplete type
      if (range->fwnode != fwnode)
               ^
   lib/logic_pio.c:86:21: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                        ^
   lib/logic_pio.c:86:39: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                                          ^
   lib/logic_pio.c:87:15: error: dereferencing pointer to incomplete type
       end < range->hw_start)
                  ^
   lib/logic_pio.c:90:20: error: dereferencing pointer to incomplete type
      if (start < range->hw_start ||
                       ^
   lib/logic_pio.c:91:16: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                   ^
   lib/logic_pio.c:91:34: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                                     ^
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
   lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type
     idle_start = root->sec_min;
                      ^
   lib/logic_pio.c:110:15: error: dereferencing pointer to incomplete type
     *prev = &root->sec_head;
                  ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^

vim +351 include/linux/rculist.h

3943f42c Andrey Utkin         2014-11-14  271   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  272   *
72c6a987 Jiri Pirko           2009-04-14  273   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  274   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  275   */
72c6a987 Jiri Pirko           2009-04-14  276  #define list_entry_rcu(ptr, type, member) \
8db70b13 Patrick Marlier      2015-09-11 @277  	container_of(lockless_dereference(ptr), type, member)
72c6a987 Jiri Pirko           2009-04-14  278  
72c6a987 Jiri Pirko           2009-04-14  279  /**
f88022a4 Michel Machado       2012-04-10  280   * Where are list_empty_rcu() and list_first_entry_rcu()?
f88022a4 Michel Machado       2012-04-10  281   *
f88022a4 Michel Machado       2012-04-10  282   * Implementing those functions following their counterparts list_empty() and
f88022a4 Michel Machado       2012-04-10  283   * list_first_entry() is not advisable because they lead to subtle race
f88022a4 Michel Machado       2012-04-10  284   * conditions as the following snippet shows:
f88022a4 Michel Machado       2012-04-10  285   *
f88022a4 Michel Machado       2012-04-10  286   * if (!list_empty_rcu(mylist)) {
f88022a4 Michel Machado       2012-04-10  287   *	struct foo *bar = list_first_entry_rcu(mylist, struct foo, list_member);
f88022a4 Michel Machado       2012-04-10  288   *	do_something(bar);
f88022a4 Michel Machado       2012-04-10  289   * }
f88022a4 Michel Machado       2012-04-10  290   *
f88022a4 Michel Machado       2012-04-10  291   * The list may not be empty when list_empty_rcu checks it, but it may be when
f88022a4 Michel Machado       2012-04-10  292   * list_first_entry_rcu rereads the ->next pointer.
f88022a4 Michel Machado       2012-04-10  293   *
f88022a4 Michel Machado       2012-04-10  294   * Rereading the ->next pointer is not a problem for list_empty() and
f88022a4 Michel Machado       2012-04-10  295   * list_first_entry() because they would be protected by a lock that blocks
f88022a4 Michel Machado       2012-04-10  296   * writers.
f88022a4 Michel Machado       2012-04-10  297   *
f88022a4 Michel Machado       2012-04-10  298   * See list_first_or_null_rcu for an alternative.
f88022a4 Michel Machado       2012-04-10  299   */
f88022a4 Michel Machado       2012-04-10  300  
f88022a4 Michel Machado       2012-04-10  301  /**
f88022a4 Michel Machado       2012-04-10  302   * list_first_or_null_rcu - get the first element from a list
72c6a987 Jiri Pirko           2009-04-14  303   * @ptr:        the list head to take the element from.
72c6a987 Jiri Pirko           2009-04-14  304   * @type:       the type of the struct this is embedded in.
3943f42c Andrey Utkin         2014-11-14  305   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  306   *
f88022a4 Michel Machado       2012-04-10  307   * Note that if the list is empty, it returns NULL.
72c6a987 Jiri Pirko           2009-04-14  308   *
72c6a987 Jiri Pirko           2009-04-14  309   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  310   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  311   */
f88022a4 Michel Machado       2012-04-10  312  #define list_first_or_null_rcu(ptr, type, member) \
0adab9b9 Joe Perches          2013-12-05  313  ({ \
0adab9b9 Joe Perches          2013-12-05  314  	struct list_head *__ptr = (ptr); \
7d0ae808 Paul E. McKenney     2015-03-03  315  	struct list_head *__next = READ_ONCE(__ptr->next); \
0adab9b9 Joe Perches          2013-12-05  316  	likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
f88022a4 Michel Machado       2012-04-10  317  })
72c6a987 Jiri Pirko           2009-04-14  318  
82524746 Franck Bui-Huu       2008-05-12  319  /**
ff3c44e6 Tom Herbert          2016-03-07  320   * list_next_or_null_rcu - get the first element from a list
ff3c44e6 Tom Herbert          2016-03-07  321   * @head:	the head for the list.
ff3c44e6 Tom Herbert          2016-03-07  322   * @ptr:        the list head to take the next element from.
ff3c44e6 Tom Herbert          2016-03-07  323   * @type:       the type of the struct this is embedded in.
ff3c44e6 Tom Herbert          2016-03-07  324   * @member:     the name of the list_head within the struct.
ff3c44e6 Tom Herbert          2016-03-07  325   *
ff3c44e6 Tom Herbert          2016-03-07  326   * Note that if the ptr is at the end of the list, NULL is returned.
ff3c44e6 Tom Herbert          2016-03-07  327   *
ff3c44e6 Tom Herbert          2016-03-07  328   * This primitive may safely run concurrently with the _rcu list-mutation
ff3c44e6 Tom Herbert          2016-03-07  329   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
ff3c44e6 Tom Herbert          2016-03-07  330   */
ff3c44e6 Tom Herbert          2016-03-07  331  #define list_next_or_null_rcu(head, ptr, type, member) \
ff3c44e6 Tom Herbert          2016-03-07  332  ({ \
ff3c44e6 Tom Herbert          2016-03-07  333  	struct list_head *__head = (head); \
ff3c44e6 Tom Herbert          2016-03-07  334  	struct list_head *__ptr = (ptr); \
ff3c44e6 Tom Herbert          2016-03-07  335  	struct list_head *__next = READ_ONCE(__ptr->next); \
ff3c44e6 Tom Herbert          2016-03-07  336  	likely(__next != __head) ? list_entry_rcu(__next, type, \
ff3c44e6 Tom Herbert          2016-03-07  337  						  member) : NULL; \
ff3c44e6 Tom Herbert          2016-03-07  338  })
ff3c44e6 Tom Herbert          2016-03-07  339  
ff3c44e6 Tom Herbert          2016-03-07  340  /**
82524746 Franck Bui-Huu       2008-05-12  341   * list_for_each_entry_rcu	-	iterate over rcu list of given type
82524746 Franck Bui-Huu       2008-05-12  342   * @pos:	the type * to use as a loop cursor.
82524746 Franck Bui-Huu       2008-05-12  343   * @head:	the head for your list.
3943f42c Andrey Utkin         2014-11-14  344   * @member:	the name of the list_head within the struct.
82524746 Franck Bui-Huu       2008-05-12  345   *
82524746 Franck Bui-Huu       2008-05-12  346   * This list-traversal primitive may safely run concurrently with
82524746 Franck Bui-Huu       2008-05-12  347   * the _rcu list-mutation primitives such as list_add_rcu()
82524746 Franck Bui-Huu       2008-05-12  348   * as long as the traversal is guarded by rcu_read_lock().
82524746 Franck Bui-Huu       2008-05-12  349   */
82524746 Franck Bui-Huu       2008-05-12  350  #define list_for_each_entry_rcu(pos, head, member) \
72c6a987 Jiri Pirko           2009-04-14 @351  	for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
e66eed65 Linus Torvalds       2011-05-19  352  		&pos->member != (head); \
72c6a987 Jiri Pirko           2009-04-14 @353  		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
82524746 Franck Bui-Huu       2008-05-12  354  
82524746 Franck Bui-Huu       2008-05-12  355  /**
69b90729 Alexey Kardashevskiy 2015-12-05  356   * list_entry_lockless - get the struct for this entry

:::::: The code at line 351 was first introduced by commit
:::::: 72c6a9870f901045f2464c3dc6ee8914bfdc07aa rculist.h: introduce list_entry_rcu() and list_first_entry_rcu()

:::::: TO: Jiri Pirko <jpirko@redhat.com>
:::::: CC: Ingo Molnar <mingo@elte.hu>

---
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: 6383 bytes --]

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-01  6:31     ` kbuild test robot
  0 siblings, 0 replies; 78+ messages in thread
From: kbuild test robot @ 2017-04-01  6:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
config: m68k-m5475evb_defconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 4.9.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=m68k 

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

   lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^
   lib/logic_pio.c:52:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO] = {
      ^
   lib/logic_pio.c:52:2: error: array index in initializer not of integer type
     [PIO_CPU_MMIO] = {
     ^
   lib/logic_pio.c:52:2: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:53:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:53:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:54:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
   lib/logic_pio.c:55:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:55:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:55:3: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization from incompatible pointer type
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/pid.h:4:0,
                    from include/linux/sched.h:13,
                    from arch/m68k/include/asm/pgtable_mm.h:10,
                    from arch/m68k/include/asm/pgtable.h:4,
                    from include/linux/mm.h:68,
                    from lib/logic_pio.c:20:
   include/linux/rculist.h:352:7: error: dereferencing pointer to incomplete type
      &pos->member != (head); \
          ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, 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/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> lib/logic_pio.c:78:13: error: dereferencing pointer to incomplete type
      if (!range->pio_peer) {
                ^
   In file included from include/linux/kernel.h:13:0,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c:80:11: error: dereferencing pointer to incomplete type
        &range->hw_start);
              ^
   include/linux/printk.h:303:37: note: in definition of macro 'pr_warning'
     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
                                        ^
>> lib/logic_pio.c:79:4: note: in expansion of macro 'pr_warn'
       pr_warn("Invalid cpu addr node(%pa) in list!\n",
       ^
   lib/logic_pio.c:83:12: error: dereferencing pointer to incomplete type
      if (range->fwnode != fwnode)
               ^
   lib/logic_pio.c:86:21: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                        ^
   lib/logic_pio.c:86:39: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                                          ^
   lib/logic_pio.c:87:15: error: dereferencing pointer to incomplete type
       end < range->hw_start)
                  ^
   lib/logic_pio.c:90:20: error: dereferencing pointer to incomplete type
      if (start < range->hw_start ||
                       ^
   lib/logic_pio.c:91:16: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                   ^
   lib/logic_pio.c:91:34: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                                     ^
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
   lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type
     idle_start = root->sec_min;
                      ^
   lib/logic_pio.c:110:15: error: dereferencing pointer to incomplete type
     *prev = &root->sec_head;
                  ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^

vim +351 include/linux/rculist.h

3943f42c Andrey Utkin         2014-11-14  271   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  272   *
72c6a987 Jiri Pirko           2009-04-14  273   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  274   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  275   */
72c6a987 Jiri Pirko           2009-04-14  276  #define list_entry_rcu(ptr, type, member) \
8db70b13 Patrick Marlier      2015-09-11 @277  	container_of(lockless_dereference(ptr), type, member)
72c6a987 Jiri Pirko           2009-04-14  278  
72c6a987 Jiri Pirko           2009-04-14  279  /**
f88022a4 Michel Machado       2012-04-10  280   * Where are list_empty_rcu() and list_first_entry_rcu()?
f88022a4 Michel Machado       2012-04-10  281   *
f88022a4 Michel Machado       2012-04-10  282   * Implementing those functions following their counterparts list_empty() and
f88022a4 Michel Machado       2012-04-10  283   * list_first_entry() is not advisable because they lead to subtle race
f88022a4 Michel Machado       2012-04-10  284   * conditions as the following snippet shows:
f88022a4 Michel Machado       2012-04-10  285   *
f88022a4 Michel Machado       2012-04-10  286   * if (!list_empty_rcu(mylist)) {
f88022a4 Michel Machado       2012-04-10  287   *	struct foo *bar = list_first_entry_rcu(mylist, struct foo, list_member);
f88022a4 Michel Machado       2012-04-10  288   *	do_something(bar);
f88022a4 Michel Machado       2012-04-10  289   * }
f88022a4 Michel Machado       2012-04-10  290   *
f88022a4 Michel Machado       2012-04-10  291   * The list may not be empty when list_empty_rcu checks it, but it may be when
f88022a4 Michel Machado       2012-04-10  292   * list_first_entry_rcu rereads the ->next pointer.
f88022a4 Michel Machado       2012-04-10  293   *
f88022a4 Michel Machado       2012-04-10  294   * Rereading the ->next pointer is not a problem for list_empty() and
f88022a4 Michel Machado       2012-04-10  295   * list_first_entry() because they would be protected by a lock that blocks
f88022a4 Michel Machado       2012-04-10  296   * writers.
f88022a4 Michel Machado       2012-04-10  297   *
f88022a4 Michel Machado       2012-04-10  298   * See list_first_or_null_rcu for an alternative.
f88022a4 Michel Machado       2012-04-10  299   */
f88022a4 Michel Machado       2012-04-10  300  
f88022a4 Michel Machado       2012-04-10  301  /**
f88022a4 Michel Machado       2012-04-10  302   * list_first_or_null_rcu - get the first element from a list
72c6a987 Jiri Pirko           2009-04-14  303   * @ptr:        the list head to take the element from.
72c6a987 Jiri Pirko           2009-04-14  304   * @type:       the type of the struct this is embedded in.
3943f42c Andrey Utkin         2014-11-14  305   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  306   *
f88022a4 Michel Machado       2012-04-10  307   * Note that if the list is empty, it returns NULL.
72c6a987 Jiri Pirko           2009-04-14  308   *
72c6a987 Jiri Pirko           2009-04-14  309   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  310   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  311   */
f88022a4 Michel Machado       2012-04-10  312  #define list_first_or_null_rcu(ptr, type, member) \
0adab9b9 Joe Perches          2013-12-05  313  ({ \
0adab9b9 Joe Perches          2013-12-05  314  	struct list_head *__ptr = (ptr); \
7d0ae808 Paul E. McKenney     2015-03-03  315  	struct list_head *__next = READ_ONCE(__ptr->next); \
0adab9b9 Joe Perches          2013-12-05  316  	likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
f88022a4 Michel Machado       2012-04-10  317  })
72c6a987 Jiri Pirko           2009-04-14  318  
82524746 Franck Bui-Huu       2008-05-12  319  /**
ff3c44e6 Tom Herbert          2016-03-07  320   * list_next_or_null_rcu - get the first element from a list
ff3c44e6 Tom Herbert          2016-03-07  321   * @head:	the head for the list.
ff3c44e6 Tom Herbert          2016-03-07  322   * @ptr:        the list head to take the next element from.
ff3c44e6 Tom Herbert          2016-03-07  323   * @type:       the type of the struct this is embedded in.
ff3c44e6 Tom Herbert          2016-03-07  324   * @member:     the name of the list_head within the struct.
ff3c44e6 Tom Herbert          2016-03-07  325   *
ff3c44e6 Tom Herbert          2016-03-07  326   * Note that if the ptr is at the end of the list, NULL is returned.
ff3c44e6 Tom Herbert          2016-03-07  327   *
ff3c44e6 Tom Herbert          2016-03-07  328   * This primitive may safely run concurrently with the _rcu list-mutation
ff3c44e6 Tom Herbert          2016-03-07  329   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
ff3c44e6 Tom Herbert          2016-03-07  330   */
ff3c44e6 Tom Herbert          2016-03-07  331  #define list_next_or_null_rcu(head, ptr, type, member) \
ff3c44e6 Tom Herbert          2016-03-07  332  ({ \
ff3c44e6 Tom Herbert          2016-03-07  333  	struct list_head *__head = (head); \
ff3c44e6 Tom Herbert          2016-03-07  334  	struct list_head *__ptr = (ptr); \
ff3c44e6 Tom Herbert          2016-03-07  335  	struct list_head *__next = READ_ONCE(__ptr->next); \
ff3c44e6 Tom Herbert          2016-03-07  336  	likely(__next != __head) ? list_entry_rcu(__next, type, \
ff3c44e6 Tom Herbert          2016-03-07  337  						  member) : NULL; \
ff3c44e6 Tom Herbert          2016-03-07  338  })
ff3c44e6 Tom Herbert          2016-03-07  339  
ff3c44e6 Tom Herbert          2016-03-07  340  /**
82524746 Franck Bui-Huu       2008-05-12  341   * list_for_each_entry_rcu	-	iterate over rcu list of given type
82524746 Franck Bui-Huu       2008-05-12  342   * @pos:	the type * to use as a loop cursor.
82524746 Franck Bui-Huu       2008-05-12  343   * @head:	the head for your list.
3943f42c Andrey Utkin         2014-11-14  344   * @member:	the name of the list_head within the struct.
82524746 Franck Bui-Huu       2008-05-12  345   *
82524746 Franck Bui-Huu       2008-05-12  346   * This list-traversal primitive may safely run concurrently with
82524746 Franck Bui-Huu       2008-05-12  347   * the _rcu list-mutation primitives such as list_add_rcu()
82524746 Franck Bui-Huu       2008-05-12  348   * as long as the traversal is guarded by rcu_read_lock().
82524746 Franck Bui-Huu       2008-05-12  349   */
82524746 Franck Bui-Huu       2008-05-12  350  #define list_for_each_entry_rcu(pos, head, member) \
72c6a987 Jiri Pirko           2009-04-14 @351  	for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
e66eed65 Linus Torvalds       2011-05-19  352  		&pos->member != (head); \
72c6a987 Jiri Pirko           2009-04-14 @353  		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
82524746 Franck Bui-Huu       2008-05-12  354  
82524746 Franck Bui-Huu       2008-05-12  355  /**
69b90729 Alexey Kardashevskiy 2015-12-05  356   * list_entry_lockless - get the struct for this entry

:::::: The code at line 351 was first introduced by commit
:::::: 72c6a9870f901045f2464c3dc6ee8914bfdc07aa rculist.h: introduce list_entry_rcu() and list_first_entry_rcu()

:::::: TO: Jiri Pirko <jpirko@redhat.com>
:::::: CC: Ingo Molnar <mingo@elte.hu>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 6383 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170401/965db37c/attachment-0001.gz>

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-04-01  2:16             ` zhichang.yuan
  (?)
  (?)
@ 2017-04-01  9:52               ` Rafael J. Wysocki
  -1 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-04-01  9:52 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, zhichang.yuan, Rafael J. Wysocki,
	Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, Arnd Bergmann, linux-arm-kernel, Mark Rutland,
	Brian Starkey, Olof Johansson, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List,
	ACPI Devel Maling List, linuxar

On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan <zhichang.yuan02@gmail.com> wrote:
>
>
> On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
>> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
>> <yuanzhichang@hisilicon.com> wrote:
>>> Hi, Rafael,
>>>
>>> Thanks for reviewing this!
>>>
>>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>>
>>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>>> starting the enumeration.
>>>>
>>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>>
>>> As you know currently for ARM architecture IO space is memory mapped and
>>> is only used by pci devices. The port number is dynamically allocated
>>> converting the device IO address into a PIO token: i.e.
>>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>>> This patch is meant to support a new class of IO host controller
>>> that are not PCI based and that still require to have the IO addresses
>>> be translated in the same PIO token space as the PCI controller
>>
>> IOW, this is ARM-specific, right?
>
> Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.

But the underlying mechanism is ARM-specific as well AFAICS.

> But, I think the handler driver is architecture dependent.

I guess you mean "independent"?  That doesn't matter.

If ARM64 is the only architecture to use it in foreseeable future
(which is the case for all I can say), it should go into acpi/arm64/
and please ask the maintainers thereof to review it.

Thanks,
Rafael

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-01  9:52               ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-04-01  9:52 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, zhichang.yuan, Rafael J. Wysocki,
	Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, Arnd Bergmann, linux-arm-kernel, Mark Rutland,
	Brian Starkey, Olof Johansson, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List,
	ACPI Devel Maling List, linuxarm, devicetree, Linux PCI,
	Corey Minyard, Zou Rongrong, John Garry, Gabriele Paoloni,
	kantyzc, xuwei5

On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan <zhichang.yuan02@gmail.com> wrote:
>
>
> On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
>> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
>> <yuanzhichang@hisilicon.com> wrote:
>>> Hi, Rafael,
>>>
>>> Thanks for reviewing this!
>>>
>>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>>
>>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>>> starting the enumeration.
>>>>
>>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>>
>>> As you know currently for ARM architecture IO space is memory mapped and
>>> is only used by pci devices. The port number is dynamically allocated
>>> converting the device IO address into a PIO token: i.e.
>>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>>> This patch is meant to support a new class of IO host controller
>>> that are not PCI based and that still require to have the IO addresses
>>> be translated in the same PIO token space as the PCI controller
>>
>> IOW, this is ARM-specific, right?
>
> Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.

But the underlying mechanism is ARM-specific as well AFAICS.

> But, I think the handler driver is architecture dependent.

I guess you mean "independent"?  That doesn't matter.

If ARM64 is the only architecture to use it in foreseeable future
(which is the case for all I can say), it should go into acpi/arm64/
and please ask the maintainers thereof to review it.

Thanks,
Rafael

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-01  9:52               ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-04-01  9:52 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Rafael J. Wysocki, zhichang.yuan, Rafael J. Wysocki,
	Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, Arnd Bergmann, linux-arm-kernel, Mark Rutland,
	Brian Starkey, Olof Johansson, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List,
	ACPI Devel Maling List, linuxarm, devicetree, Linux PCI,
	Corey Minyard, Zou Rongrong, John Garry, Gabriele Paoloni,
	kantyzc, xuwei5

On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan <zhichang.yuan02@gmail.com> wrote:
>
>
> On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
>> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
>> <yuanzhichang@hisilicon.com> wrote:
>>> Hi, Rafael,
>>>
>>> Thanks for reviewing this!
>>>
>>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>>
>>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>>> starting the enumeration.
>>>>
>>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>>
>>> As you know currently for ARM architecture IO space is memory mapped and
>>> is only used by pci devices. The port number is dynamically allocated
>>> converting the device IO address into a PIO token: i.e.
>>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>>> This patch is meant to support a new class of IO host controller
>>> that are not PCI based and that still require to have the IO addresses
>>> be translated in the same PIO token space as the PCI controller
>>
>> IOW, this is ARM-specific, right?
>
> Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.

But the underlying mechanism is ARM-specific as well AFAICS.

> But, I think the handler driver is architecture dependent.

I guess you mean "independent"?  That doesn't matter.

If ARM64 is the only architecture to use it in foreseeable future
(which is the case for all I can say), it should go into acpi/arm64/
and please ask the maintainers thereof to review it.

Thanks,
Rafael

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-01  9:52               ` Rafael J. Wysocki
  0 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2017-04-01  9:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan <zhichang.yuan02@gmail.com> wrote:
>
>
> On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
>> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
>> <yuanzhichang@hisilicon.com> wrote:
>>> Hi, Rafael,
>>>
>>> Thanks for reviewing this!
>>>
>>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
>>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
>>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>>>>> with some special host-local I/O ports known on x86. To access the I/O
>>>>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>>>>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>>>>> registered before probing the downstream devices and set up the I/O mapping.
>>>>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>>>>
>>>>> This patch introdueces a new ACPI handler for this device category. Through the
>>>>> handler attach callback, the indirect-IO hosts I/O registration is done and
>>>>> all peripherals' I/O resources are translated into logic/fake PIO before
>>>>> starting the enumeration.
>>>>
>>>> Can you explain to me briefly what exactly this code is expected to be doing?
>>>
>>> As you know currently for ARM architecture IO space is memory mapped and
>>> is only used by pci devices. The port number is dynamically allocated
>>> converting the device IO address into a PIO token: i.e.
>>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
>>> This patch is meant to support a new class of IO host controller
>>> that are not PCI based and that still require to have the IO addresses
>>> be translated in the same PIO token space as the PCI controller
>>
>> IOW, this is ARM-specific, right?
>
> Yes. The current host added in this patch with _HID "HISI0191" is on ARM64.

But the underlying mechanism is ARM-specific as well AFAICS.

> But, I think the handler driver is architecture dependent.

I guess you mean "independent"?  That doesn't matter.

If ARM64 is the only architecture to use it in foreseeable future
(which is the case for all I can say), it should go into acpi/arm64/
and please ask the maintainers thereof to review it.

Thanks,
Rafael

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

* RE: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-04-01  9:52               ` Rafael J. Wysocki
  (?)
  (?)
@ 2017-04-02 14:58                   ` Gabriele Paoloni
  -1 siblings, 0 replies; 78+ messages in thread
From: Gabriele Paoloni @ 2017-04-02 14:58 UTC (permalink / raw)
  To: Rafael J. Wysocki, zhichang.yuan
  Cc: Yuanzhichang, Rafael J. Wysocki, Catalin Marinas, Will Deacon,
	Rob Herring, Frank Rowand, Bjorn Helgaas, Arnd Bergmann,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mark Rutland,
	Brian Starkey, Olof Johansson, Lorenzo Pieralisi,
	Benjamin Herrenschmidt, Linux Kernel Mailing List,
	ACPI Devel Maling List, Linuxarm, devicetree-fy+rA21nqHI

Hi Rafael 
Many thanks for your reply

> -----Original Message-----
> From: rjwysocki@gmail.com [mailto:rjwysocki@gmail.com] On Behalf Of
> Rafael J. Wysocki
> Sent: 01 April 2017 10:52
> To: zhichang.yuan
> Cc: Rafael J. Wysocki; Yuanzhichang; Rafael J. Wysocki; Catalin
> Marinas; Will Deacon; Rob Herring; Frank Rowand; Bjorn Helgaas; Arnd
> Bergmann; linux-arm-kernel@lists.infradead.org; Mark Rutland; Brian
> Starkey; Olof Johansson; Lorenzo Pieralisi; Benjamin Herrenschmidt;
> Linux Kernel Mailing List; ACPI Devel Maling List; Linuxarm;
> devicetree@vger.kernel.org; Linux PCI; Corey Minyard; Zou Rongrong;
> John Garry; Gabriele Paoloni; kantyzc@163.com; xuwei (O)
> Subject: Re: [PATCH V8 5/6] ACPI: Support the probing on the devices
> which apply indirect-IO
> 
> On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan
> <zhichang.yuan02@gmail.com> wrote:
> >
> >
> > On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> >> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> >> <yuanzhichang@hisilicon.com> wrote:
> >>> Hi, Rafael,
> >>>
> >>> Thanks for reviewing this!
> >>>
> >>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> >>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> >>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC
> devices access I/O
> >>>>> with some special host-local I/O ports known on x86. To access
> the I/O
> >>>>> peripherals, an indirect-IO mechanism is introduced to mapped the
> host-local
> >>>>> I/O to system logical/fake PIO similar the PCI MMIO on
> architectures where no
> >>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range
> should be
> >>>>> registered before probing the downstream devices and set up the
> I/O mapping.
> >>>>> But current ACPI bus probing doesn't support these indirect-IO
> hosts/devices.
> >>>>>
> >>>>> This patch introdueces a new ACPI handler for this device
> category. Through the
> >>>>> handler attach callback, the indirect-IO hosts I/O registration
> is done and
> >>>>> all peripherals' I/O resources are translated into logic/fake PIO
> before
> >>>>> starting the enumeration.
> >>>>
> >>>> Can you explain to me briefly what exactly this code is expected
> to be doing?
> >>>
> >>> As you know currently for ARM architecture IO space is memory
> mapped and
> >>> is only used by pci devices. The port number is dynamically
> allocated
> >>> converting the device IO address into a PIO token: i.e.
> >>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> >>> This patch is meant to support a new class of IO host controller
> >>> that are not PCI based and that still require to have the IO
> addresses
> >>> be translated in the same PIO token space as the PCI controller
> >>
> >> IOW, this is ARM-specific, right?
> >
> > Yes. The current host added in this patch with _HID "HISI0191" is on
> ARM64.
> 
> But the underlying mechanism is ARM-specific as well AFAICS.
> 
> > But, I think the handler driver is architecture dependent.
> 
> I guess you mean "independent"?  That doesn't matter.
> 
> If ARM64 is the only architecture to use it in foreseeable future
> (which is the case for all I can say), it should go into acpi/arm64/
> and please ask the maintainers thereof to review it.

I guess this is the case for the foreseeable future.

So if my understanding is correct we should leave acpi_indirectio_scan_init()
call in acpi_scan_init() and move its definition under acpi/arm64/ right?

If in future other architectures needs non-pci IO controllers we may consider
to move this to acpi/...

Lorenzo what do you think? Could you have a look at the patchset?

Many thanks

Gab

> 
> Thanks,
> Rafael

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

* RE: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-02 14:58                   ` Gabriele Paoloni
  0 siblings, 0 replies; 78+ messages in thread
From: Gabriele Paoloni @ 2017-04-02 14:58 UTC (permalink / raw)
  To: Rafael J. Wysocki, zhichang.yuan, Lorenzo Pieralisi
  Cc: Yuanzhichang, Rafael J. Wysocki, Catalin Marinas, Will Deacon,
	Rob Herring, Frank Rowand, Bjorn Helgaas, Arnd Bergmann,
	linux-arm-kernel, Mark Rutland, Brian Starkey, Olof Johansson,
	Lorenzo Pieralisi, Benjamin Herrenschmidt,
	Linux Kernel Mailing List, ACPI Devel Maling List, Linuxarm,
	devicetree, Linux PCI, Corey Minyard, Zou Rongrong, John Garry,
	kantyzc, xuwei (O)

Hi Rafael 
Many thanks for your reply

> -----Original Message-----
> From: rjwysocki@gmail.com [mailto:rjwysocki@gmail.com] On Behalf Of
> Rafael J. Wysocki
> Sent: 01 April 2017 10:52
> To: zhichang.yuan
> Cc: Rafael J. Wysocki; Yuanzhichang; Rafael J. Wysocki; Catalin
> Marinas; Will Deacon; Rob Herring; Frank Rowand; Bjorn Helgaas; Arnd
> Bergmann; linux-arm-kernel@lists.infradead.org; Mark Rutland; Brian
> Starkey; Olof Johansson; Lorenzo Pieralisi; Benjamin Herrenschmidt;
> Linux Kernel Mailing List; ACPI Devel Maling List; Linuxarm;
> devicetree@vger.kernel.org; Linux PCI; Corey Minyard; Zou Rongrong;
> John Garry; Gabriele Paoloni; kantyzc@163.com; xuwei (O)
> Subject: Re: [PATCH V8 5/6] ACPI: Support the probing on the devices
> which apply indirect-IO
> 
> On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan
> <zhichang.yuan02@gmail.com> wrote:
> >
> >
> > On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> >> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> >> <yuanzhichang@hisilicon.com> wrote:
> >>> Hi, Rafael,
> >>>
> >>> Thanks for reviewing this!
> >>>
> >>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> >>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> >>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC
> devices access I/O
> >>>>> with some special host-local I/O ports known on x86. To access
> the I/O
> >>>>> peripherals, an indirect-IO mechanism is introduced to mapped the
> host-local
> >>>>> I/O to system logical/fake PIO similar the PCI MMIO on
> architectures where no
> >>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range
> should be
> >>>>> registered before probing the downstream devices and set up the
> I/O mapping.
> >>>>> But current ACPI bus probing doesn't support these indirect-IO
> hosts/devices.
> >>>>>
> >>>>> This patch introdueces a new ACPI handler for this device
> category. Through the
> >>>>> handler attach callback, the indirect-IO hosts I/O registration
> is done and
> >>>>> all peripherals' I/O resources are translated into logic/fake PIO
> before
> >>>>> starting the enumeration.
> >>>>
> >>>> Can you explain to me briefly what exactly this code is expected
> to be doing?
> >>>
> >>> As you know currently for ARM architecture IO space is memory
> mapped and
> >>> is only used by pci devices. The port number is dynamically
> allocated
> >>> converting the device IO address into a PIO token: i.e.
> >>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> >>> This patch is meant to support a new class of IO host controller
> >>> that are not PCI based and that still require to have the IO
> addresses
> >>> be translated in the same PIO token space as the PCI controller
> >>
> >> IOW, this is ARM-specific, right?
> >
> > Yes. The current host added in this patch with _HID "HISI0191" is on
> ARM64.
> 
> But the underlying mechanism is ARM-specific as well AFAICS.
> 
> > But, I think the handler driver is architecture dependent.
> 
> I guess you mean "independent"?  That doesn't matter.
> 
> If ARM64 is the only architecture to use it in foreseeable future
> (which is the case for all I can say), it should go into acpi/arm64/
> and please ask the maintainers thereof to review it.

I guess this is the case for the foreseeable future.

So if my understanding is correct we should leave acpi_indirectio_scan_init()
call in acpi_scan_init() and move its definition under acpi/arm64/ right?

If in future other architectures needs non-pci IO controllers we may consider
to move this to acpi/...

Lorenzo what do you think? Could you have a look at the patchset?

Many thanks

Gab

> 
> Thanks,
> Rafael

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

* RE: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-02 14:58                   ` Gabriele Paoloni
  0 siblings, 0 replies; 78+ messages in thread
From: Gabriele Paoloni @ 2017-04-02 14:58 UTC (permalink / raw)
  To: Rafael J. Wysocki, zhichang.yuan, Lorenzo Pieralisi
  Cc: Yuanzhichang, Rafael J. Wysocki, Catalin Marinas, Will Deacon,
	Rob Herring, Frank Rowand, Bjorn Helgaas, Arnd Bergmann,
	linux-arm-kernel, Mark Rutland, Brian Starkey, Olof Johansson,
	Lorenzo Pieralisi, Benjamin Herrenschmidt,
	Linux Kernel Mailing List, ACPI Devel Maling List, Linuxarm,
	devicetree, Linux PCI, Corey Minyard, Zou Rongrong, John Garry,
	kantyzc, xuwei (O)

SGkgUmFmYWVsIA0KTWFueSB0aGFua3MgZm9yIHlvdXIgcmVwbHkNCg0KPiAtLS0tLU9yaWdpbmFs
IE1lc3NhZ2UtLS0tLQ0KPiBGcm9tOiByand5c29ja2lAZ21haWwuY29tIFttYWlsdG86cmp3eXNv
Y2tpQGdtYWlsLmNvbV0gT24gQmVoYWxmIE9mDQo+IFJhZmFlbCBKLiBXeXNvY2tpDQo+IFNlbnQ6
IDAxIEFwcmlsIDIwMTcgMTA6NTINCj4gVG86IHpoaWNoYW5nLnl1YW4NCj4gQ2M6IFJhZmFlbCBK
LiBXeXNvY2tpOyBZdWFuemhpY2hhbmc7IFJhZmFlbCBKLiBXeXNvY2tpOyBDYXRhbGluDQo+IE1h
cmluYXM7IFdpbGwgRGVhY29uOyBSb2IgSGVycmluZzsgRnJhbmsgUm93YW5kOyBCam9ybiBIZWxn
YWFzOyBBcm5kDQo+IEJlcmdtYW5uOyBsaW51eC1hcm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5v
cmc7IE1hcmsgUnV0bGFuZDsgQnJpYW4NCj4gU3RhcmtleTsgT2xvZiBKb2hhbnNzb247IExvcmVu
em8gUGllcmFsaXNpOyBCZW5qYW1pbiBIZXJyZW5zY2htaWR0Ow0KPiBMaW51eCBLZXJuZWwgTWFp
bGluZyBMaXN0OyBBQ1BJIERldmVsIE1hbGluZyBMaXN0OyBMaW51eGFybTsNCj4gZGV2aWNldHJl
ZUB2Z2VyLmtlcm5lbC5vcmc7IExpbnV4IFBDSTsgQ29yZXkgTWlueWFyZDsgWm91IFJvbmdyb25n
Ow0KPiBKb2huIEdhcnJ5OyBHYWJyaWVsZSBQYW9sb25pOyBrYW50eXpjQDE2My5jb207IHh1d2Vp
IChPKQ0KPiBTdWJqZWN0OiBSZTogW1BBVENIIFY4IDUvNl0gQUNQSTogU3VwcG9ydCB0aGUgcHJv
YmluZyBvbiB0aGUgZGV2aWNlcw0KPiB3aGljaCBhcHBseSBpbmRpcmVjdC1JTw0KPiANCj4gT24g
U2F0LCBBcHIgMSwgMjAxNyBhdCA0OjE2IEFNLCB6aGljaGFuZy55dWFuDQo+IDx6aGljaGFuZy55
dWFuMDJAZ21haWwuY29tPiB3cm90ZToNCj4gPg0KPiA+DQo+ID4gT24gMDQvMDEvMjAxNyAwNzow
MiBBTSwgUmFmYWVsIEouIFd5c29ja2kgd3JvdGU6DQo+ID4+IE9uIEZyaSwgTWFyIDMxLCAyMDE3
IGF0IDg6NTIgQU0sIHpoaWNoYW5nLnl1YW4NCj4gPj4gPHl1YW56aGljaGFuZ0BoaXNpbGljb24u
Y29tPiB3cm90ZToNCj4gPj4+IEhpLCBSYWZhZWwsDQo+ID4+Pg0KPiA+Pj4gVGhhbmtzIGZvciBy
ZXZpZXdpbmcgdGhpcyENCj4gPj4+DQo+ID4+PiBPbiAyMDE3LzMvMzEgNDozMSwgUmFmYWVsIEou
IFd5c29ja2kgd3JvdGU6DQo+ID4+Pj4gT24gVGh1cnNkYXksIE1hcmNoIDMwLCAyMDE3IDExOjI2
OjU4IFBNIHpoaWNoYW5nLnl1YW4gd3JvdGU6DQo+ID4+Pj4+IE9uIHNvbWUgcGxhdGZvcm1zKHN1
Y2ggYXMgSGlwMDYvSGlwMDcpLCB0aGUgbGVnYWN5IElTQS9MUEMNCj4gZGV2aWNlcyBhY2Nlc3Mg
SS9PDQo+ID4+Pj4+IHdpdGggc29tZSBzcGVjaWFsIGhvc3QtbG9jYWwgSS9PIHBvcnRzIGtub3du
IG9uIHg4Ni4gVG8gYWNjZXNzDQo+IHRoZSBJL08NCj4gPj4+Pj4gcGVyaXBoZXJhbHMsIGFuIGlu
ZGlyZWN0LUlPIG1lY2hhbmlzbSBpcyBpbnRyb2R1Y2VkIHRvIG1hcHBlZCB0aGUNCj4gaG9zdC1s
b2NhbA0KPiA+Pj4+PiBJL08gdG8gc3lzdGVtIGxvZ2ljYWwvZmFrZSBQSU8gc2ltaWxhciB0aGUg
UENJIE1NSU8gb24NCj4gYXJjaGl0ZWN0dXJlcyB3aGVyZSBubw0KPiA+Pj4+PiBzZXBhcmF0ZSBJ
L08gc3BhY2UgZXhpc3RzLiBKdXN0IGFzIFBDSSBNTUlPLCB0aGUgaG9zdCBJL08gcmFuZ2UNCj4g
c2hvdWxkIGJlDQo+ID4+Pj4+IHJlZ2lzdGVyZWQgYmVmb3JlIHByb2JpbmcgdGhlIGRvd25zdHJl
YW0gZGV2aWNlcyBhbmQgc2V0IHVwIHRoZQ0KPiBJL08gbWFwcGluZy4NCj4gPj4+Pj4gQnV0IGN1
cnJlbnQgQUNQSSBidXMgcHJvYmluZyBkb2Vzbid0IHN1cHBvcnQgdGhlc2UgaW5kaXJlY3QtSU8N
Cj4gaG9zdHMvZGV2aWNlcy4NCj4gPj4+Pj4NCj4gPj4+Pj4gVGhpcyBwYXRjaCBpbnRyb2R1ZWNl
cyBhIG5ldyBBQ1BJIGhhbmRsZXIgZm9yIHRoaXMgZGV2aWNlDQo+IGNhdGVnb3J5LiBUaHJvdWdo
IHRoZQ0KPiA+Pj4+PiBoYW5kbGVyIGF0dGFjaCBjYWxsYmFjaywgdGhlIGluZGlyZWN0LUlPIGhv
c3RzIEkvTyByZWdpc3RyYXRpb24NCj4gaXMgZG9uZSBhbmQNCj4gPj4+Pj4gYWxsIHBlcmlwaGVy
YWxzJyBJL08gcmVzb3VyY2VzIGFyZSB0cmFuc2xhdGVkIGludG8gbG9naWMvZmFrZSBQSU8NCj4g
YmVmb3JlDQo+ID4+Pj4+IHN0YXJ0aW5nIHRoZSBlbnVtZXJhdGlvbi4NCj4gPj4+Pg0KPiA+Pj4+
IENhbiB5b3UgZXhwbGFpbiB0byBtZSBicmllZmx5IHdoYXQgZXhhY3RseSB0aGlzIGNvZGUgaXMg
ZXhwZWN0ZWQNCj4gdG8gYmUgZG9pbmc/DQo+ID4+Pg0KPiA+Pj4gQXMgeW91IGtub3cgY3VycmVu
dGx5IGZvciBBUk0gYXJjaGl0ZWN0dXJlIElPIHNwYWNlIGlzIG1lbW9yeQ0KPiBtYXBwZWQgYW5k
DQo+ID4+PiBpcyBvbmx5IHVzZWQgYnkgcGNpIGRldmljZXMuIFRoZSBwb3J0IG51bWJlciBpcyBk
eW5hbWljYWxseQ0KPiBhbGxvY2F0ZWQNCj4gPj4+IGNvbnZlcnRpbmcgdGhlIGRldmljZSBJTyBh
ZGRyZXNzIGludG8gYSBQSU8gdG9rZW46IGkuZS4NCj4gPj4+IGh0dHA6Ly9seHIuZnJlZS1lbGVj
dHJvbnMuY29tL3NvdXJjZS9kcml2ZXJzL2FjcGkvcGNpX3Jvb3QuYyNMNzQ1DQo+ID4+PiBUaGlz
IHBhdGNoIGlzIG1lYW50IHRvIHN1cHBvcnQgYSBuZXcgY2xhc3Mgb2YgSU8gaG9zdCBjb250cm9s
bGVyDQo+ID4+PiB0aGF0IGFyZSBub3QgUENJIGJhc2VkIGFuZCB0aGF0IHN0aWxsIHJlcXVpcmUg
dG8gaGF2ZSB0aGUgSU8NCj4gYWRkcmVzc2VzDQo+ID4+PiBiZSB0cmFuc2xhdGVkIGluIHRoZSBz
YW1lIFBJTyB0b2tlbiBzcGFjZSBhcyB0aGUgUENJIGNvbnRyb2xsZXINCj4gPj4NCj4gPj4gSU9X
LCB0aGlzIGlzIEFSTS1zcGVjaWZpYywgcmlnaHQ/DQo+ID4NCj4gPiBZZXMuIFRoZSBjdXJyZW50
IGhvc3QgYWRkZWQgaW4gdGhpcyBwYXRjaCB3aXRoIF9ISUQgIkhJU0kwMTkxIiBpcyBvbg0KPiBB
Uk02NC4NCj4gDQo+IEJ1dCB0aGUgdW5kZXJseWluZyBtZWNoYW5pc20gaXMgQVJNLXNwZWNpZmlj
IGFzIHdlbGwgQUZBSUNTLg0KPiANCj4gPiBCdXQsIEkgdGhpbmsgdGhlIGhhbmRsZXIgZHJpdmVy
IGlzIGFyY2hpdGVjdHVyZSBkZXBlbmRlbnQuDQo+IA0KPiBJIGd1ZXNzIHlvdSBtZWFuICJpbmRl
cGVuZGVudCI/ICBUaGF0IGRvZXNuJ3QgbWF0dGVyLg0KPiANCj4gSWYgQVJNNjQgaXMgdGhlIG9u
bHkgYXJjaGl0ZWN0dXJlIHRvIHVzZSBpdCBpbiBmb3Jlc2VlYWJsZSBmdXR1cmUNCj4gKHdoaWNo
IGlzIHRoZSBjYXNlIGZvciBhbGwgSSBjYW4gc2F5KSwgaXQgc2hvdWxkIGdvIGludG8gYWNwaS9h
cm02NC8NCj4gYW5kIHBsZWFzZSBhc2sgdGhlIG1haW50YWluZXJzIHRoZXJlb2YgdG8gcmV2aWV3
IGl0Lg0KDQpJIGd1ZXNzIHRoaXMgaXMgdGhlIGNhc2UgZm9yIHRoZSBmb3Jlc2VlYWJsZSBmdXR1
cmUuDQoNClNvIGlmIG15IHVuZGVyc3RhbmRpbmcgaXMgY29ycmVjdCB3ZSBzaG91bGQgbGVhdmUg
YWNwaV9pbmRpcmVjdGlvX3NjYW5faW5pdCgpDQpjYWxsIGluIGFjcGlfc2Nhbl9pbml0KCkgYW5k
IG1vdmUgaXRzIGRlZmluaXRpb24gdW5kZXIgYWNwaS9hcm02NC8gcmlnaHQ/DQoNCklmIGluIGZ1
dHVyZSBvdGhlciBhcmNoaXRlY3R1cmVzIG5lZWRzIG5vbi1wY2kgSU8gY29udHJvbGxlcnMgd2Ug
bWF5IGNvbnNpZGVyDQp0byBtb3ZlIHRoaXMgdG8gYWNwaS8uLi4NCg0KTG9yZW56byB3aGF0IGRv
IHlvdSB0aGluaz8gQ291bGQgeW91IGhhdmUgYSBsb29rIGF0IHRoZSBwYXRjaHNldD8NCg0KTWFu
eSB0aGFua3MNCg0KR2FiDQoNCj4gDQo+IFRoYW5rcywNCj4gUmFmYWVsDQo=

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-02 14:58                   ` Gabriele Paoloni
  0 siblings, 0 replies; 78+ messages in thread
From: Gabriele Paoloni @ 2017-04-02 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rafael 
Many thanks for your reply

> -----Original Message-----
> From: rjwysocki at gmail.com [mailto:rjwysocki at gmail.com] On Behalf Of
> Rafael J. Wysocki
> Sent: 01 April 2017 10:52
> To: zhichang.yuan
> Cc: Rafael J. Wysocki; Yuanzhichang; Rafael J. Wysocki; Catalin
> Marinas; Will Deacon; Rob Herring; Frank Rowand; Bjorn Helgaas; Arnd
> Bergmann; linux-arm-kernel at lists.infradead.org; Mark Rutland; Brian
> Starkey; Olof Johansson; Lorenzo Pieralisi; Benjamin Herrenschmidt;
> Linux Kernel Mailing List; ACPI Devel Maling List; Linuxarm;
> devicetree at vger.kernel.org; Linux PCI; Corey Minyard; Zou Rongrong;
> John Garry; Gabriele Paoloni; kantyzc at 163.com; xuwei (O)
> Subject: Re: [PATCH V8 5/6] ACPI: Support the probing on the devices
> which apply indirect-IO
> 
> On Sat, Apr 1, 2017 at 4:16 AM, zhichang.yuan
> <zhichang.yuan02@gmail.com> wrote:
> >
> >
> > On 04/01/2017 07:02 AM, Rafael J. Wysocki wrote:
> >> On Fri, Mar 31, 2017 at 8:52 AM, zhichang.yuan
> >> <yuanzhichang@hisilicon.com> wrote:
> >>> Hi, Rafael,
> >>>
> >>> Thanks for reviewing this!
> >>>
> >>> On 2017/3/31 4:31, Rafael J. Wysocki wrote:
> >>>> On Thursday, March 30, 2017 11:26:58 PM zhichang.yuan wrote:
> >>>>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC
> devices access I/O
> >>>>> with some special host-local I/O ports known on x86. To access
> the I/O
> >>>>> peripherals, an indirect-IO mechanism is introduced to mapped the
> host-local
> >>>>> I/O to system logical/fake PIO similar the PCI MMIO on
> architectures where no
> >>>>> separate I/O space exists. Just as PCI MMIO, the host I/O range
> should be
> >>>>> registered before probing the downstream devices and set up the
> I/O mapping.
> >>>>> But current ACPI bus probing doesn't support these indirect-IO
> hosts/devices.
> >>>>>
> >>>>> This patch introdueces a new ACPI handler for this device
> category. Through the
> >>>>> handler attach callback, the indirect-IO hosts I/O registration
> is done and
> >>>>> all peripherals' I/O resources are translated into logic/fake PIO
> before
> >>>>> starting the enumeration.
> >>>>
> >>>> Can you explain to me briefly what exactly this code is expected
> to be doing?
> >>>
> >>> As you know currently for ARM architecture IO space is memory
> mapped and
> >>> is only used by pci devices. The port number is dynamically
> allocated
> >>> converting the device IO address into a PIO token: i.e.
> >>> http://lxr.free-electrons.com/source/drivers/acpi/pci_root.c#L745
> >>> This patch is meant to support a new class of IO host controller
> >>> that are not PCI based and that still require to have the IO
> addresses
> >>> be translated in the same PIO token space as the PCI controller
> >>
> >> IOW, this is ARM-specific, right?
> >
> > Yes. The current host added in this patch with _HID "HISI0191" is on
> ARM64.
> 
> But the underlying mechanism is ARM-specific as well AFAICS.
> 
> > But, I think the handler driver is architecture dependent.
> 
> I guess you mean "independent"?  That doesn't matter.
> 
> If ARM64 is the only architecture to use it in foreseeable future
> (which is the case for all I can say), it should go into acpi/arm64/
> and please ask the maintainers thereof to review it.

I guess this is the case for the foreseeable future.

So if my understanding is correct we should leave acpi_indirectio_scan_init()
call in acpi_scan_init() and move its definition under acpi/arm64/ right?

If in future other architectures needs non-pci IO controllers we may consider
to move this to acpi/...

Lorenzo what do you think? Could you have a look at the patchset?

Many thanks

Gab

> 
> Thanks,
> Rafael

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
  2017-04-01  5:58     ` kbuild test robot
  (?)
@ 2017-04-05 12:18       ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-05 12:18 UTC (permalink / raw)
  To: kbuild test robot, fengguang.wu
  Cc: zhichang.yuan, kbuild-all, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	mark.rutland, brian.starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	minyard, zourongrong, john.garry, gabriele.paoloni, xuwei5

Hi,

Thanks for your report!

I am sorry for that!

This issue was caused by missing the '#include <linux/logic_pio.h>' in
logic_pio.c for some architectures where the 'asm-generic/io.h' wasn't been
included.

Will be fixed in the next V9.

Apologized for this!

-Zhichang


On 04/01/2017 01:58 PM, kbuild test robot wrote:
> Hi zhichang.yuan,
> 
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.11-rc4 next-20170331]
> [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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
> 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 error/warnings (new ones prefixed by >>):
> 
>>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
>     static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
>                                                      ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>       ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>                        ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>       ^~~~~~~~~~~~
>    lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
>       .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>       ^
>    lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:41:3: error: field name not in record or union initializer
>       .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>       ^
>    lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
>       .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>                  ^~~~~~~~~~~~
>    lib/logic_pio.c:42:3: error: field name not in record or union initializer
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>       ^
>    lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>                  ^~~~~~~~~~~~
>    lib/logic_pio.c:46:3: error: array index in initializer not of integer type
>      [PIO_INDIRECT] = {
>       ^~~~~~~~~~~~
>    lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:47:3: error: field name not in record or union initializer
>       .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
>       ^
>    lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:48:3: error: field name not in record or union initializer
>       .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
>       ^
>    lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:49:3: error: field name not in record or union initializer
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
>       ^
>    lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
>    In file included from include/linux/list.h:8:0,
>                     from include/linux/kobject.h:20,
>                     from include/linux/of.h:21,
>                     from lib/logic_pio.c:18:
>    lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
>      for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>    include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
>>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
>      container_of(lockless_dereference(ptr), type, member)
>      ^~~~~~~~~~~~
>>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
>>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
>      container_of(lockless_dereference(ptr), type, member)
>      ^~~~~~~~~~~~
>    include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
>       pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
>             ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>    lib/logic_pio.c: In function 'logic_pio_alloc_range':
>>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
>      idle_start = root->sec_min;
>                       ^~
>    In file included from include/linux/list.h:8:0,
>                     from include/linux/kobject.h:20,
>                     from include/linux/of.h:21,
>                     from lib/logic_pio.c:18:
>>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
>      for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>    lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(entry, &root->sec_head, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
> 
> vim +/PIO_MAX_SECT +32 lib/logic_pio.c
> 
>     12	 * GNU General Public License for more details.
>     13	 *
>     14	 * You should have received a copy of the GNU General Public License
>     15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>     16	 */
>     17	
>   > 18	#include <linux/of.h>
>     19	#include <linux/io.h>
>     20	#include <linux/mm.h>
>     21	#include <linux/rculist.h>
>     22	#include <linux/sizes.h>
>     23	#include <linux/slab.h>
>     24	
>     25	/* The unique hardware address list. */
>     26	static LIST_HEAD(io_range_list);
>     27	static DEFINE_MUTEX(io_range_mutex);
>     28	
>     29	/*
>     30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
>     31	 */
>   > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
>     33	#ifdef CONFIG_INDIRECT_PIO
>     34		/*
>     35		 * At this moment, assign all the other logic PIO space to MMIO.
>     36		 * If more elements added, please adjust the ending index and .sec_max;
>     37		 * Please keep MMIO element started from index ZERO.
>     38		 */
>   > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>   > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>   > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>   > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>     43		},
>     44	
>     45		/* The last element */
>     46		[PIO_INDIRECT] = {
>     47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
>     48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
>     49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
>     50		},
>     51	#else
>     52		[PIO_CPU_MMIO] = {
>     53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>     54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>     55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
>     56		},
>     57	
>     58	#endif
>     59	};
>     60	
>     61	/*
>     62	 * Search a io_range registered which match the fwnode and addr.
>     63	 *
>     64	 * @fwnode: the host fwnode which must be valid;
>     65	 * @start: the start hardware address of this search;
>     66	 * @end: the end hardware address of this search. can be equal to @start;
>     67	 *
>     68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
>     69	 * valid virtual address represent a matched node was found.
>     70	 */
>     71	static struct logic_pio_hwaddr *
>     72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
>     73				resource_size_t start, resource_size_t end)
>     74	{
>     75		struct logic_pio_hwaddr *range;
>     76	
>   > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
>     78			if (!range->pio_peer) {
>     79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
>     80					&range->hw_start);
>     81				continue;
>     82			}
>     83			if (range->fwnode != fwnode)
>     84				continue;
>     85			/* without any overlap with current range */
>     86			if (start >= range->hw_start + range->size ||
>     87				end < range->hw_start)
>     88				continue;
>     89			/* overlap is not supported now. */
>     90			if (start < range->hw_start ||
>     91				end >= range->hw_start + range->size)
>     92				return ERR_PTR(-EBUSY);
>     93			/* had been registered. */
>     94			return range;
>     95		}
>     96	
>     97		return NULL;
>     98	}
>     99	
>    100	
>    101	static int logic_pio_alloc_range(struct logic_pio_root *root,
>    102			resource_size_t size, unsigned long align,
>    103			struct list_head **prev, resource_size_t *pio_alloc)
>    104	{
>    105		struct logic_pio_sect *entry;
>    106		resource_size_t tmp_start;
>    107		resource_size_t idle_start, idle_end;
>    108	
>  > 109		idle_start = root->sec_min;
>    110		*prev = &root->sec_head;
>    111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
>    112			if (!entry->hwpeer ||
>    113				idle_start > entry->io_start) {
>    114				WARN(1, "skip an invalid io range during traversal!\n");
>    115				goto nextentry;
>    116			}
>    117			/* set the end edge. */
>    118			if (idle_start == entry->io_start) {
>    119				struct logic_pio_sect *next;
>    120	
>    121				idle_start = entry->io_start + entry->hwpeer->size;
>  > 122				next = list_next_or_null_rcu(&root->sec_head,
>  > 123					&entry->list, struct logic_pio_sect, list);
>    124				if (next) {
>    125					entry = next;
>    126				} else {
>    127					*prev = &entry->list;
>    128					break;
>    129				}
>    130			}
>    131			idle_end = entry->io_start - 1;
>    132	
>    133			/* contiguous range... */
>    134			if (idle_start > idle_end)
>    135				goto nextentry;
>    136	
>    137			tmp_start = idle_start;
>    138			idle_start = ALIGN(idle_start, align);
>    139			if (idle_start >= tmp_start &&
>    140				idle_start + size <= idle_end) {
>    141				*prev = &entry->list;
>    142				*pio_alloc = idle_start;
>    143				return 0;
>    144			}
>    145	
>    146	nextentry:
>    147			idle_start = entry->io_start + entry->hwpeer->size;
>    148			*prev = &entry->list;
>    149		}
>    150		/* check the last free gap... */
>    151		idle_end = root->sec_max;
>    152	
>    153		tmp_start = idle_start;
>    154		idle_start = ALIGN(idle_start, align);
>    155		if (idle_start >= tmp_start &&
>    156			idle_start + size <= idle_end) {
>    157			*pio_alloc = idle_start;
>    158			return 0;
>    159		}
>    160	
>    161		return -EBUSY;
>    162	}
>    163	
>    164	/*
>    165	 * register a io range node in the io range list.
>    166	 *
>    167	 * @newrange: pointer to the io range to be registered.
>    168	 *
>    169	 * return 'newrange' when success, ERR_VALUE() is for failures.
>    170	 * specially, return a valid pointer which is not equal to 'newrange' when
>    171	 * the io range had been registered before.
>    172	 */
>    173	struct logic_pio_hwaddr
>    174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
>    175			unsigned long align)
>    176	{
>    177		struct logic_pio_hwaddr *range;
>    178		struct logic_pio_sect *newsect;
>    179		resource_size_t pio_alloc;
>    180		struct list_head *prev, *hwprev;
>    181		unsigned long sect_id;
>    182		int err;
>    183	
>    184		if (!newrange || !newrange->fwnode || !newrange->size)
>    185			return ERR_PTR(-EINVAL);
>    186	
>    187		sect_id = newrange->flags;
>    188		if (sect_id >= PIO_MAX_SECT)
>    189			return ERR_PTR(-EINVAL);
>    190	
>    191		mutex_lock(&io_range_mutex);
>    192		range = logic_pio_find_range_byaddr(newrange->fwnode,
>    193				newrange->hw_start,
>    194				newrange->hw_start + newrange->size - 1);
>    195		if (range) {
>    196			if (!IS_ERR(range))
>    197				pr_info("the request IO range had been registered!\n");
>    198			else
>    199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
>    200					&newrange->hw_start, &newrange->size);
>    201			mutex_unlock(&io_range_mutex);
>    202			return range;
>    203		}
>    204	
>    205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
>    206				newrange->size, align, &prev, &pio_alloc);
>    207		if (err) {
>    208			pr_err("can't find free %pa logical IO range!\n",
>    209				&newrange->size);
>    210			goto exitproc;
>    211		}
>    212	
>    213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
>    214			hwprev = &io_range_list;
>    215		} else {
>  > 216			newsect = to_pio_sect(prev);
>  > 217			hwprev = &newsect->hwpeer->list;
>    218		}
>    219	
>    220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
> 

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

* Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-05 12:18       ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-05 12:18 UTC (permalink / raw)
  To: kbuild test robot, fengguang.wu
  Cc: mark.rutland, benh, gabriele.paoloni, rafael, linux-pci,
	will.deacon, linuxarm, frowand.list, lorenzo.pieralisi, arnd,
	xuwei5, linux-acpi, catalin.marinas, devicetree, minyard,
	john.garry, olof, robh+dt, bhelgaas, linux-arm-kernel,
	linux-kernel, zhichang.yuan, kbuild-all, zourongrong,
	brian.starkey

Hi,

Thanks for your report!

I am sorry for that!

This issue was caused by missing the '#include <linux/logic_pio.h>' in
logic_pio.c for some architectures where the 'asm-generic/io.h' wasn't been
included.

Will be fixed in the next V9.

Apologized for this!

-Zhichang


On 04/01/2017 01:58 PM, kbuild test robot wrote:
> Hi zhichang.yuan,
> 
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.11-rc4 next-20170331]
> [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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
> 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 error/warnings (new ones prefixed by >>):
> 
>>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
>     static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
>                                                      ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>       ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>                        ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>       ^~~~~~~~~~~~
>    lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
>       .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>       ^
>    lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:41:3: error: field name not in record or union initializer
>       .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>       ^
>    lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
>       .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>                  ^~~~~~~~~~~~
>    lib/logic_pio.c:42:3: error: field name not in record or union initializer
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>       ^
>    lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>                  ^~~~~~~~~~~~
>    lib/logic_pio.c:46:3: error: array index in initializer not of integer type
>      [PIO_INDIRECT] = {
>       ^~~~~~~~~~~~
>    lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:47:3: error: field name not in record or union initializer
>       .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
>       ^
>    lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:48:3: error: field name not in record or union initializer
>       .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
>       ^
>    lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:49:3: error: field name not in record or union initializer
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
>       ^
>    lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
>    In file included from include/linux/list.h:8:0,
>                     from include/linux/kobject.h:20,
>                     from include/linux/of.h:21,
>                     from lib/logic_pio.c:18:
>    lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
>      for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>    include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
>>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
>      container_of(lockless_dereference(ptr), type, member)
>      ^~~~~~~~~~~~
>>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
>>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
>      container_of(lockless_dereference(ptr), type, member)
>      ^~~~~~~~~~~~
>    include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
>       pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
>             ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>    lib/logic_pio.c: In function 'logic_pio_alloc_range':
>>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
>      idle_start = root->sec_min;
>                       ^~
>    In file included from include/linux/list.h:8:0,
>                     from include/linux/kobject.h:20,
>                     from include/linux/of.h:21,
>                     from lib/logic_pio.c:18:
>>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
>      for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>    lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(entry, &root->sec_head, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
> 
> vim +/PIO_MAX_SECT +32 lib/logic_pio.c
> 
>     12	 * GNU General Public License for more details.
>     13	 *
>     14	 * You should have received a copy of the GNU General Public License
>     15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>     16	 */
>     17	
>   > 18	#include <linux/of.h>
>     19	#include <linux/io.h>
>     20	#include <linux/mm.h>
>     21	#include <linux/rculist.h>
>     22	#include <linux/sizes.h>
>     23	#include <linux/slab.h>
>     24	
>     25	/* The unique hardware address list. */
>     26	static LIST_HEAD(io_range_list);
>     27	static DEFINE_MUTEX(io_range_mutex);
>     28	
>     29	/*
>     30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
>     31	 */
>   > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
>     33	#ifdef CONFIG_INDIRECT_PIO
>     34		/*
>     35		 * At this moment, assign all the other logic PIO space to MMIO.
>     36		 * If more elements added, please adjust the ending index and .sec_max;
>     37		 * Please keep MMIO element started from index ZERO.
>     38		 */
>   > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>   > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>   > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>   > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>     43		},
>     44	
>     45		/* The last element */
>     46		[PIO_INDIRECT] = {
>     47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
>     48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
>     49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
>     50		},
>     51	#else
>     52		[PIO_CPU_MMIO] = {
>     53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>     54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>     55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
>     56		},
>     57	
>     58	#endif
>     59	};
>     60	
>     61	/*
>     62	 * Search a io_range registered which match the fwnode and addr.
>     63	 *
>     64	 * @fwnode: the host fwnode which must be valid;
>     65	 * @start: the start hardware address of this search;
>     66	 * @end: the end hardware address of this search. can be equal to @start;
>     67	 *
>     68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
>     69	 * valid virtual address represent a matched node was found.
>     70	 */
>     71	static struct logic_pio_hwaddr *
>     72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
>     73				resource_size_t start, resource_size_t end)
>     74	{
>     75		struct logic_pio_hwaddr *range;
>     76	
>   > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
>     78			if (!range->pio_peer) {
>     79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
>     80					&range->hw_start);
>     81				continue;
>     82			}
>     83			if (range->fwnode != fwnode)
>     84				continue;
>     85			/* without any overlap with current range */
>     86			if (start >= range->hw_start + range->size ||
>     87				end < range->hw_start)
>     88				continue;
>     89			/* overlap is not supported now. */
>     90			if (start < range->hw_start ||
>     91				end >= range->hw_start + range->size)
>     92				return ERR_PTR(-EBUSY);
>     93			/* had been registered. */
>     94			return range;
>     95		}
>     96	
>     97		return NULL;
>     98	}
>     99	
>    100	
>    101	static int logic_pio_alloc_range(struct logic_pio_root *root,
>    102			resource_size_t size, unsigned long align,
>    103			struct list_head **prev, resource_size_t *pio_alloc)
>    104	{
>    105		struct logic_pio_sect *entry;
>    106		resource_size_t tmp_start;
>    107		resource_size_t idle_start, idle_end;
>    108	
>  > 109		idle_start = root->sec_min;
>    110		*prev = &root->sec_head;
>    111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
>    112			if (!entry->hwpeer ||
>    113				idle_start > entry->io_start) {
>    114				WARN(1, "skip an invalid io range during traversal!\n");
>    115				goto nextentry;
>    116			}
>    117			/* set the end edge. */
>    118			if (idle_start == entry->io_start) {
>    119				struct logic_pio_sect *next;
>    120	
>    121				idle_start = entry->io_start + entry->hwpeer->size;
>  > 122				next = list_next_or_null_rcu(&root->sec_head,
>  > 123					&entry->list, struct logic_pio_sect, list);
>    124				if (next) {
>    125					entry = next;
>    126				} else {
>    127					*prev = &entry->list;
>    128					break;
>    129				}
>    130			}
>    131			idle_end = entry->io_start - 1;
>    132	
>    133			/* contiguous range... */
>    134			if (idle_start > idle_end)
>    135				goto nextentry;
>    136	
>    137			tmp_start = idle_start;
>    138			idle_start = ALIGN(idle_start, align);
>    139			if (idle_start >= tmp_start &&
>    140				idle_start + size <= idle_end) {
>    141				*prev = &entry->list;
>    142				*pio_alloc = idle_start;
>    143				return 0;
>    144			}
>    145	
>    146	nextentry:
>    147			idle_start = entry->io_start + entry->hwpeer->size;
>    148			*prev = &entry->list;
>    149		}
>    150		/* check the last free gap... */
>    151		idle_end = root->sec_max;
>    152	
>    153		tmp_start = idle_start;
>    154		idle_start = ALIGN(idle_start, align);
>    155		if (idle_start >= tmp_start &&
>    156			idle_start + size <= idle_end) {
>    157			*pio_alloc = idle_start;
>    158			return 0;
>    159		}
>    160	
>    161		return -EBUSY;
>    162	}
>    163	
>    164	/*
>    165	 * register a io range node in the io range list.
>    166	 *
>    167	 * @newrange: pointer to the io range to be registered.
>    168	 *
>    169	 * return 'newrange' when success, ERR_VALUE() is for failures.
>    170	 * specially, return a valid pointer which is not equal to 'newrange' when
>    171	 * the io range had been registered before.
>    172	 */
>    173	struct logic_pio_hwaddr
>    174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
>    175			unsigned long align)
>    176	{
>    177		struct logic_pio_hwaddr *range;
>    178		struct logic_pio_sect *newsect;
>    179		resource_size_t pio_alloc;
>    180		struct list_head *prev, *hwprev;
>    181		unsigned long sect_id;
>    182		int err;
>    183	
>    184		if (!newrange || !newrange->fwnode || !newrange->size)
>    185			return ERR_PTR(-EINVAL);
>    186	
>    187		sect_id = newrange->flags;
>    188		if (sect_id >= PIO_MAX_SECT)
>    189			return ERR_PTR(-EINVAL);
>    190	
>    191		mutex_lock(&io_range_mutex);
>    192		range = logic_pio_find_range_byaddr(newrange->fwnode,
>    193				newrange->hw_start,
>    194				newrange->hw_start + newrange->size - 1);
>    195		if (range) {
>    196			if (!IS_ERR(range))
>    197				pr_info("the request IO range had been registered!\n");
>    198			else
>    199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
>    200					&newrange->hw_start, &newrange->size);
>    201			mutex_unlock(&io_range_mutex);
>    202			return range;
>    203		}
>    204	
>    205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
>    206				newrange->size, align, &prev, &pio_alloc);
>    207		if (err) {
>    208			pr_err("can't find free %pa logical IO range!\n",
>    209				&newrange->size);
>    210			goto exitproc;
>    211		}
>    212	
>    213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
>    214			hwprev = &io_range_list;
>    215		} else {
>  > 216			newsect = to_pio_sect(prev);
>  > 217			hwprev = &newsect->hwpeer->list;
>    218		}
>    219	
>    220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
@ 2017-04-05 12:18       ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-05 12:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Thanks for your report!

I am sorry for that!

This issue was caused by missing the '#include <linux/logic_pio.h>' in
logic_pio.c for some architectures where the 'asm-generic/io.h' wasn't been
included.

Will be fixed in the next V9.

Apologized for this!

-Zhichang


On 04/01/2017 01:58 PM, kbuild test robot wrote:
> Hi zhichang.yuan,
> 
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.11-rc4 next-20170331]
> [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/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
> 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 error/warnings (new ones prefixed by >>):
> 
>>> lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
>     static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
>                                                      ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>       ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function)
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>                        ^~~~~~~~~~~~
>>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type
>      [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>       ^~~~~~~~~~~~
>    lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:40:3: error: field name not in record or union initializer
>       .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>       ^
>    lib/logic_pio.c:40:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:41:3: error: field name not in record or union initializer
>       .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>       ^
>    lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
>       .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>                  ^~~~~~~~~~~~
>    lib/logic_pio.c:42:3: error: field name not in record or union initializer
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>       ^
>    lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list')
>>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>                  ^~~~~~~~~~~~
>    lib/logic_pio.c:46:3: error: array index in initializer not of integer type
>      [PIO_INDIRECT] = {
>       ^~~~~~~~~~~~
>    lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:47:3: error: field name not in record or union initializer
>       .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
>       ^
>    lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:48:3: error: field name not in record or union initializer
>       .sec_min = PIO_SECT_MIN(PIO_INDIRECT),
>       ^
>    lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list')
>    lib/logic_pio.c:49:3: error: field name not in record or union initializer
>       .sec_max = PIO_SECT_MAX(PIO_INDIRECT),
>       ^
>    lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_list')
>    In file included from include/linux/list.h:8:0,
>                     from include/linux/kobject.h:20,
>                     from include/linux/of.h:21,
>                     from lib/logic_pio.c:18:
>    lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr'
>      for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>    include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
>>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
>      container_of(lockless_dereference(ptr), type, member)
>      ^~~~~~~~~~~~
>>> include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
>>> include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
>      container_of(lockless_dereference(ptr), type, member)
>      ^~~~~~~~~~~~
>    include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
>       pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
>             ^~~~~~~~~~~~~~
>>> lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(range, &io_range_list, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>    lib/logic_pio.c: In function 'logic_pio_alloc_range':
>>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root'
>      idle_start = root->sec_min;
>                       ^~
>    In file included from include/linux/list.h:8:0,
>                     from include/linux/kobject.h:20,
>                     from include/linux/of.h:21,
>                     from lib/logic_pio.c:18:
>>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_sect'
>      for (pos = list_entry_rcu((head)->next, 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/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
>      for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
>                 ^~~~~~~~~~~~~~
>    lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
>      list_for_each_entry_rcu(entry, &root->sec_head, list) {
>      ^~~~~~~~~~~~~~~~~~~~~~~
>>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
>      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>                                                    ^
> 
> vim +/PIO_MAX_SECT +32 lib/logic_pio.c
> 
>     12	 * GNU General Public License for more details.
>     13	 *
>     14	 * You should have received a copy of the GNU General Public License
>     15	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>     16	 */
>     17	
>   > 18	#include <linux/of.h>
>     19	#include <linux/io.h>
>     20	#include <linux/mm.h>
>     21	#include <linux/rculist.h>
>     22	#include <linux/sizes.h>
>     23	#include <linux/slab.h>
>     24	
>     25	/* The unique hardware address list. */
>     26	static LIST_HEAD(io_range_list);
>     27	static DEFINE_MUTEX(io_range_mutex);
>     28	
>     29	/*
>     30	 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
>     31	 */
>   > 32	static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
>     33	#ifdef CONFIG_INDIRECT_PIO
>     34		/*
>     35		 * At this moment, assign all the other logic PIO space to MMIO.
>     36		 * If more elements added, please adjust the ending index and .sec_max;
>     37		 * Please keep MMIO element started from index ZERO.
>     38		 */
>   > 39		[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
>   > 40			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>   > 41			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>   > 42			.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
>     43		},
>     44	
>     45		/* The last element */
>     46		[PIO_INDIRECT] = {
>     47			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
>     48			.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
>     49			.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
>     50		},
>     51	#else
>     52		[PIO_CPU_MMIO] = {
>     53			.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
>     54			.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
>     55			.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
>     56		},
>     57	
>     58	#endif
>     59	};
>     60	
>     61	/*
>     62	 * Search a io_range registered which match the fwnode and addr.
>     63	 *
>     64	 * @fwnode: the host fwnode which must be valid;
>     65	 * @start: the start hardware address of this search;
>     66	 * @end: the end hardware address of this search. can be equal to @start;
>     67	 *
>     68	 * return NULL when there is no matched node; IS_ERR() means ERROR;
>     69	 * valid virtual address represent a matched node was found.
>     70	 */
>     71	static struct logic_pio_hwaddr *
>     72	logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
>     73				resource_size_t start, resource_size_t end)
>     74	{
>     75		struct logic_pio_hwaddr *range;
>     76	
>   > 77		list_for_each_entry_rcu(range, &io_range_list, list) {
>     78			if (!range->pio_peer) {
>     79				pr_warn("Invalid cpu addr node(%pa) in list!\n",
>     80					&range->hw_start);
>     81				continue;
>     82			}
>     83			if (range->fwnode != fwnode)
>     84				continue;
>     85			/* without any overlap with current range */
>     86			if (start >= range->hw_start + range->size ||
>     87				end < range->hw_start)
>     88				continue;
>     89			/* overlap is not supported now. */
>     90			if (start < range->hw_start ||
>     91				end >= range->hw_start + range->size)
>     92				return ERR_PTR(-EBUSY);
>     93			/* had been registered. */
>     94			return range;
>     95		}
>     96	
>     97		return NULL;
>     98	}
>     99	
>    100	
>    101	static int logic_pio_alloc_range(struct logic_pio_root *root,
>    102			resource_size_t size, unsigned long align,
>    103			struct list_head **prev, resource_size_t *pio_alloc)
>    104	{
>    105		struct logic_pio_sect *entry;
>    106		resource_size_t tmp_start;
>    107		resource_size_t idle_start, idle_end;
>    108	
>  > 109		idle_start = root->sec_min;
>    110		*prev = &root->sec_head;
>    111		list_for_each_entry_rcu(entry, &root->sec_head, list) {
>    112			if (!entry->hwpeer ||
>    113				idle_start > entry->io_start) {
>    114				WARN(1, "skip an invalid io range during traversal!\n");
>    115				goto nextentry;
>    116			}
>    117			/* set the end edge. */
>    118			if (idle_start == entry->io_start) {
>    119				struct logic_pio_sect *next;
>    120	
>    121				idle_start = entry->io_start + entry->hwpeer->size;
>  > 122				next = list_next_or_null_rcu(&root->sec_head,
>  > 123					&entry->list, struct logic_pio_sect, list);
>    124				if (next) {
>    125					entry = next;
>    126				} else {
>    127					*prev = &entry->list;
>    128					break;
>    129				}
>    130			}
>    131			idle_end = entry->io_start - 1;
>    132	
>    133			/* contiguous range... */
>    134			if (idle_start > idle_end)
>    135				goto nextentry;
>    136	
>    137			tmp_start = idle_start;
>    138			idle_start = ALIGN(idle_start, align);
>    139			if (idle_start >= tmp_start &&
>    140				idle_start + size <= idle_end) {
>    141				*prev = &entry->list;
>    142				*pio_alloc = idle_start;
>    143				return 0;
>    144			}
>    145	
>    146	nextentry:
>    147			idle_start = entry->io_start + entry->hwpeer->size;
>    148			*prev = &entry->list;
>    149		}
>    150		/* check the last free gap... */
>    151		idle_end = root->sec_max;
>    152	
>    153		tmp_start = idle_start;
>    154		idle_start = ALIGN(idle_start, align);
>    155		if (idle_start >= tmp_start &&
>    156			idle_start + size <= idle_end) {
>    157			*pio_alloc = idle_start;
>    158			return 0;
>    159		}
>    160	
>    161		return -EBUSY;
>    162	}
>    163	
>    164	/*
>    165	 * register a io range node in the io range list.
>    166	 *
>    167	 * @newrange: pointer to the io range to be registered.
>    168	 *
>    169	 * return 'newrange' when success, ERR_VALUE() is for failures.
>    170	 * specially, return a valid pointer which is not equal to 'newrange' when
>    171	 * the io range had been registered before.
>    172	 */
>    173	struct logic_pio_hwaddr
>    174	*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
>    175			unsigned long align)
>    176	{
>    177		struct logic_pio_hwaddr *range;
>    178		struct logic_pio_sect *newsect;
>    179		resource_size_t pio_alloc;
>    180		struct list_head *prev, *hwprev;
>    181		unsigned long sect_id;
>    182		int err;
>    183	
>    184		if (!newrange || !newrange->fwnode || !newrange->size)
>    185			return ERR_PTR(-EINVAL);
>    186	
>    187		sect_id = newrange->flags;
>    188		if (sect_id >= PIO_MAX_SECT)
>    189			return ERR_PTR(-EINVAL);
>    190	
>    191		mutex_lock(&io_range_mutex);
>    192		range = logic_pio_find_range_byaddr(newrange->fwnode,
>    193				newrange->hw_start,
>    194				newrange->hw_start + newrange->size - 1);
>    195		if (range) {
>    196			if (!IS_ERR(range))
>    197				pr_info("the request IO range had been registered!\n");
>    198			else
>    199				pr_err("registering IO[%pa - sz%pa) got failed!\n",
>    200					&newrange->hw_start, &newrange->size);
>    201			mutex_unlock(&io_range_mutex);
>    202			return range;
>    203		}
>    204	
>    205		err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
>    206				newrange->size, align, &prev, &pio_alloc);
>    207		if (err) {
>    208			pr_err("can't find free %pa logical IO range!\n",
>    209				&newrange->size);
>    210			goto exitproc;
>    211		}
>    212	
>    213		if (prev == &logic_pio_root_list[sect_id].sec_head) {
>    214			hwprev = &io_range_list;
>    215		} else {
>  > 216			newsect = to_pio_sect(prev);
>  > 217			hwprev = &newsect->hwpeer->list;
>    218		}
>    219	
>    220		newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-03-30 15:26   ` zhichang.yuan
  (?)
  (?)
@ 2017-04-20 20:57     ` dann frazier
  -1 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-04-20 20:57 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	Corey Minyard, Zou Rongrong, John Garry, Gabriele Paoloni

On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.
>
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  drivers/acpi/Makefile          |   1 +
>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>  drivers/acpi/internal.h        |   5 +
>  drivers/acpi/scan.c            |   1 +
>  4 files changed, 351 insertions(+)
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index a391bbc..10e5f2b 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y                         += acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>
>  # These are (potentially) separate modules
>
> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> new file mode 100644
> index 0000000..c8c80b5
> --- /dev/null
> +++ b/drivers/acpi/acpi_indirectio.c
> @@ -0,0 +1,344 @@
> +/*
> + * ACPI support for indirect-IO bus.
> + *
> + * 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.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/platform_device.h>
> +#include <linux/logic_pio.h>
> +
> +#include "internal.h"
> +
> +ACPI_MODULE_NAME("indirect IO");
> +
> +#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
> +
> +struct lpc_private_data {
> +       resource_size_t io_size;
> +       resource_size_t io_start;
> +};
> +
> +struct indirectio_device_desc {
> +       void *pdata; /* device relevant info data */
> +       int (*pre_setup)(struct acpi_device *adev, void *pdata);
> +};
> +
> +static struct lpc_private_data lpc_data = {
> +       .io_size = LPC_BUS_IO_SIZE,
> +       .io_start = LPC_MIN_BUS_RANGE,
> +};
> +
> +static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
> +                                          void *data)
> +{
> +       int *res_cnt = data;
> +
> +       if (acpi_logicio_supported_resource(res) &&
> +               !acpi_dev_filter_resource_type(res, IORESOURCE_IO))
> +               (*res_cnt)++;
> +
> +       return AE_OK;
> +}
> +
> +static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
> +               void *data)
> +{
> +       struct acpi_resource **resource = data;
> +
> +       if (acpi_logicio_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_logiciores_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_logiciores, &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);

(Seth Forshee noticed this issue, just passing it on)

Should this just allocate the full buffer->length? That would keep the
length attribute accurate (possibly avoiding an off-by-1 error later).
It's not clear what the trailing byte is needed for, but other drivers
allocate it as well (drivers/acpi/pci_link.c and
drivers/platform/x86/sony-laptop.c).

 -dann

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-20 20:57     ` dann frazier
  0 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-04-20 20:57 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, olof, lorenzo.pieralisi, benh,
	linux-kernel, linux-acpi, linuxarm, devicetree, linux-pci,
	Corey Minyard, Zou Rongrong, John Garry, Gabriele Paoloni,
	zhichang.yuan, kantyzc, xuwei5, Seth Forshee

On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.
>
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  drivers/acpi/Makefile          |   1 +
>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>  drivers/acpi/internal.h        |   5 +
>  drivers/acpi/scan.c            |   1 +
>  4 files changed, 351 insertions(+)
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index a391bbc..10e5f2b 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y                         += acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>
>  # These are (potentially) separate modules
>
> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> new file mode 100644
> index 0000000..c8c80b5
> --- /dev/null
> +++ b/drivers/acpi/acpi_indirectio.c
> @@ -0,0 +1,344 @@
> +/*
> + * ACPI support for indirect-IO bus.
> + *
> + * 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.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/platform_device.h>
> +#include <linux/logic_pio.h>
> +
> +#include "internal.h"
> +
> +ACPI_MODULE_NAME("indirect IO");
> +
> +#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
> +
> +struct lpc_private_data {
> +       resource_size_t io_size;
> +       resource_size_t io_start;
> +};
> +
> +struct indirectio_device_desc {
> +       void *pdata; /* device relevant info data */
> +       int (*pre_setup)(struct acpi_device *adev, void *pdata);
> +};
> +
> +static struct lpc_private_data lpc_data = {
> +       .io_size = LPC_BUS_IO_SIZE,
> +       .io_start = LPC_MIN_BUS_RANGE,
> +};
> +
> +static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
> +                                          void *data)
> +{
> +       int *res_cnt = data;
> +
> +       if (acpi_logicio_supported_resource(res) &&
> +               !acpi_dev_filter_resource_type(res, IORESOURCE_IO))
> +               (*res_cnt)++;
> +
> +       return AE_OK;
> +}
> +
> +static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
> +               void *data)
> +{
> +       struct acpi_resource **resource = data;
> +
> +       if (acpi_logicio_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_logiciores_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_logiciores, &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);

(Seth Forshee noticed this issue, just passing it on)

Should this just allocate the full buffer->length? That would keep the
length attribute accurate (possibly avoiding an off-by-1 error later).
It's not clear what the trailing byte is needed for, but other drivers
allocate it as well (drivers/acpi/pci_link.c and
drivers/platform/x86/sony-laptop.c).

 -dann

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-20 20:57     ` dann frazier
  0 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-04-20 20:57 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Mark Rutland, benh, Gabriele Paoloni, rafael, linux-pci,
	Will Deacon, linuxarm, Frank Rowand, lorenzo.pieralisi,
	Arnd Bergmann, xuwei5, linux-acpi, Catalin Marinas, devicetree,
	Corey Minyard, John Garry, Zou Rongrong, Rob Herring,
	Bjorn Helgaas, kantyzc, zhichang.yuan, linux-arm-kernel,
	Seth Forshee, linux-kernel, olof, Brian Starkey

On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.
>
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  drivers/acpi/Makefile          |   1 +
>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>  drivers/acpi/internal.h        |   5 +
>  drivers/acpi/scan.c            |   1 +
>  4 files changed, 351 insertions(+)
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index a391bbc..10e5f2b 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y                         += acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>
>  # These are (potentially) separate modules
>
> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> new file mode 100644
> index 0000000..c8c80b5
> --- /dev/null
> +++ b/drivers/acpi/acpi_indirectio.c
> @@ -0,0 +1,344 @@
> +/*
> + * ACPI support for indirect-IO bus.
> + *
> + * 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.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/platform_device.h>
> +#include <linux/logic_pio.h>
> +
> +#include "internal.h"
> +
> +ACPI_MODULE_NAME("indirect IO");
> +
> +#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
> +
> +struct lpc_private_data {
> +       resource_size_t io_size;
> +       resource_size_t io_start;
> +};
> +
> +struct indirectio_device_desc {
> +       void *pdata; /* device relevant info data */
> +       int (*pre_setup)(struct acpi_device *adev, void *pdata);
> +};
> +
> +static struct lpc_private_data lpc_data = {
> +       .io_size = LPC_BUS_IO_SIZE,
> +       .io_start = LPC_MIN_BUS_RANGE,
> +};
> +
> +static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
> +                                          void *data)
> +{
> +       int *res_cnt = data;
> +
> +       if (acpi_logicio_supported_resource(res) &&
> +               !acpi_dev_filter_resource_type(res, IORESOURCE_IO))
> +               (*res_cnt)++;
> +
> +       return AE_OK;
> +}
> +
> +static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
> +               void *data)
> +{
> +       struct acpi_resource **resource = data;
> +
> +       if (acpi_logicio_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_logiciores_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_logiciores, &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);

(Seth Forshee noticed this issue, just passing it on)

Should this just allocate the full buffer->length? That would keep the
length attribute accurate (possibly avoiding an off-by-1 error later).
It's not clear what the trailing byte is needed for, but other drivers
allocate it as well (drivers/acpi/pci_link.c and
drivers/platform/x86/sony-laptop.c).

 -dann

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-20 20:57     ` dann frazier
  0 siblings, 0 replies; 78+ messages in thread
From: dann frazier @ 2017-04-20 20:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
<yuanzhichang@hisilicon.com> wrote:
> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> with some special host-local I/O ports known on x86. To access the I/O
> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> registered before probing the downstream devices and set up the I/O mapping.
> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>
> This patch introdueces a new ACPI handler for this device category. Through the
> handler attach callback, the indirect-IO hosts I/O registration is done and
> all peripherals' I/O resources are translated into logic/fake PIO before
> starting the enumeration.
>
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  drivers/acpi/Makefile          |   1 +
>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>  drivers/acpi/internal.h        |   5 +
>  drivers/acpi/scan.c            |   1 +
>  4 files changed, 351 insertions(+)
>  create mode 100644 drivers/acpi/acpi_indirectio.c
>
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index a391bbc..10e5f2b 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y                         += acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>
>  # These are (potentially) separate modules
>
> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> new file mode 100644
> index 0000000..c8c80b5
> --- /dev/null
> +++ b/drivers/acpi/acpi_indirectio.c
> @@ -0,0 +1,344 @@
> +/*
> + * ACPI support for indirect-IO bus.
> + *
> + * 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.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/platform_device.h>
> +#include <linux/logic_pio.h>
> +
> +#include "internal.h"
> +
> +ACPI_MODULE_NAME("indirect IO");
> +
> +#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
> +
> +struct lpc_private_data {
> +       resource_size_t io_size;
> +       resource_size_t io_start;
> +};
> +
> +struct indirectio_device_desc {
> +       void *pdata; /* device relevant info data */
> +       int (*pre_setup)(struct acpi_device *adev, void *pdata);
> +};
> +
> +static struct lpc_private_data lpc_data = {
> +       .io_size = LPC_BUS_IO_SIZE,
> +       .io_start = LPC_MIN_BUS_RANGE,
> +};
> +
> +static inline bool acpi_logicio_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_logiciores(struct acpi_resource *res,
> +                                          void *data)
> +{
> +       int *res_cnt = data;
> +
> +       if (acpi_logicio_supported_resource(res) &&
> +               !acpi_dev_filter_resource_type(res, IORESOURCE_IO))
> +               (*res_cnt)++;
> +
> +       return AE_OK;
> +}
> +
> +static acpi_status acpi_read_one_logiciores(struct acpi_resource *res,
> +               void *data)
> +{
> +       struct acpi_resource **resource = data;
> +
> +       if (acpi_logicio_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_logiciores_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_logiciores, &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);

(Seth Forshee noticed this issue, just passing it on)

Should this just allocate the full buffer->length? That would keep the
length attribute accurate (possibly avoiding an off-by-1 error later).
It's not clear what the trailing byte is needed for, but other drivers
allocate it as well (drivers/acpi/pci_link.c and
drivers/platform/x86/sony-laptop.c).

 -dann

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-04-20 20:57     ` dann frazier
  (?)
  (?)
@ 2017-04-21  2:22       ` zhichang.yuan
  -1 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-21  2:22 UTC (permalink / raw)
  To: dann frazier, zhichang.yuan, lorenzo.pieralisi, hanjun.guo, sudeep.holla
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, Corey Minyard,
	Zou Rongrong, John Garry, Gabriele Paoloni

Hi, Dann,



On 04/21/2017 04:57 AM, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
>>
>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>> ---
>>  drivers/acpi/Makefile          |   1 +
>>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/acpi/internal.h        |   5 +
>>  drivers/acpi/scan.c            |   1 +
>>  4 files changed, 351 insertions(+)
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index a391bbc..10e5f2b 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>  acpi-y                         += acpi_lpat.o
>>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
>> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>>
>>  # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
>> new file mode 100644
>> index 0000000..c8c80b5
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_indirectio.c
>> @@ -0,0 +1,344 @@

[snip]

>> +acpi_build_logiciores_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_logiciores, &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);
> 
> (Seth Forshee noticed this issue, just passing it on)
> 
> Should this just allocate the full buffer->length? That would keep the
> length attribute accurate (possibly avoiding an off-by-1 error later).
> It's not clear what the trailing byte is needed for, but other drivers
> allocate it as well (drivers/acpi/pci_link.c and
> drivers/platform/x86/sony-laptop.c).

Thanks for your suggestion!

I also curious why this one appended byte is needed as it seems the later
acpi_set_current_resources() doesn't use this byte.
And I tested without setting the buffer->length as the length of resource list
directly, it seems ok.

But anyway, it looks more reasonable to allocate the memory with the
buffer->length rather than buffer->length - 1;

I was made the V9 patch-set, and I can add your suggestion there. But I also
awaiting for ARM64 ACPI maintainer's comment about this patch before really
sending V9. I wonder whether there is better way to make our indirect-IO devices
can be assigned the logic PIO before the enumeration...

Lorenzo, Hanjun, what do you think about this patch?

Thanks,
Zhichang

> 
>  -dann
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-21  2:22       ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-21  2:22 UTC (permalink / raw)
  To: dann frazier, zhichang.yuan, lorenzo.pieralisi, hanjun.guo, sudeep.holla
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, Corey Minyard,
	Zou Rongrong, John Garry, Gabriele Paoloni, kantyzc, xuwei5,
	Seth Forshee

Hi, Dann,



On 04/21/2017 04:57 AM, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
>>
>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>> ---
>>  drivers/acpi/Makefile          |   1 +
>>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/acpi/internal.h        |   5 +
>>  drivers/acpi/scan.c            |   1 +
>>  4 files changed, 351 insertions(+)
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index a391bbc..10e5f2b 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>  acpi-y                         += acpi_lpat.o
>>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
>> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>>
>>  # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
>> new file mode 100644
>> index 0000000..c8c80b5
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_indirectio.c
>> @@ -0,0 +1,344 @@

[snip]

>> +acpi_build_logiciores_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_logiciores, &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);
> 
> (Seth Forshee noticed this issue, just passing it on)
> 
> Should this just allocate the full buffer->length? That would keep the
> length attribute accurate (possibly avoiding an off-by-1 error later).
> It's not clear what the trailing byte is needed for, but other drivers
> allocate it as well (drivers/acpi/pci_link.c and
> drivers/platform/x86/sony-laptop.c).

Thanks for your suggestion!

I also curious why this one appended byte is needed as it seems the later
acpi_set_current_resources() doesn't use this byte.
And I tested without setting the buffer->length as the length of resource list
directly, it seems ok.

But anyway, it looks more reasonable to allocate the memory with the
buffer->length rather than buffer->length - 1;

I was made the V9 patch-set, and I can add your suggestion there. But I also
awaiting for ARM64 ACPI maintainer's comment about this patch before really
sending V9. I wonder whether there is better way to make our indirect-IO devices
can be assigned the logic PIO before the enumeration...

Lorenzo, Hanjun, what do you think about this patch?

Thanks,
Zhichang

> 
>  -dann
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-21  2:22       ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-21  2:22 UTC (permalink / raw)
  To: dann frazier, zhichang.yuan, lorenzo.pieralisi, hanjun.guo, sudeep.holla
  Cc: Mark Rutland, benh, Gabriele Paoloni, rafael, linux-pci,
	Will Deacon, linuxarm, Frank Rowand, Arnd Bergmann, xuwei5,
	linux-acpi, Catalin Marinas, devicetree, Corey Minyard,
	John Garry, Zou Rongrong, Rob Herring, Bjorn Helgaas, kantyzc,
	linux-arm-kernel, Seth Forshee, linux-kernel, olof,
	Brian Starkey

Hi, Dann,



On 04/21/2017 04:57 AM, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
>>
>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>> ---
>>  drivers/acpi/Makefile          |   1 +
>>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/acpi/internal.h        |   5 +
>>  drivers/acpi/scan.c            |   1 +
>>  4 files changed, 351 insertions(+)
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index a391bbc..10e5f2b 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>  acpi-y                         += acpi_lpat.o
>>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
>> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>>
>>  # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
>> new file mode 100644
>> index 0000000..c8c80b5
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_indirectio.c
>> @@ -0,0 +1,344 @@

[snip]

>> +acpi_build_logiciores_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_logiciores, &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);
> 
> (Seth Forshee noticed this issue, just passing it on)
> 
> Should this just allocate the full buffer->length? That would keep the
> length attribute accurate (possibly avoiding an off-by-1 error later).
> It's not clear what the trailing byte is needed for, but other drivers
> allocate it as well (drivers/acpi/pci_link.c and
> drivers/platform/x86/sony-laptop.c).

Thanks for your suggestion!

I also curious why this one appended byte is needed as it seems the later
acpi_set_current_resources() doesn't use this byte.
And I tested without setting the buffer->length as the length of resource list
directly, it seems ok.

But anyway, it looks more reasonable to allocate the memory with the
buffer->length rather than buffer->length - 1;

I was made the V9 patch-set, and I can add your suggestion there. But I also
awaiting for ARM64 ACPI maintainer's comment about this patch before really
sending V9. I wonder whether there is better way to make our indirect-IO devices
can be assigned the logic PIO before the enumeration...

Lorenzo, Hanjun, what do you think about this patch?

Thanks,
Zhichang

> 
>  -dann
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-21  2:22       ` zhichang.yuan
  0 siblings, 0 replies; 78+ messages in thread
From: zhichang.yuan @ 2017-04-21  2:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Dann,



On 04/21/2017 04:57 AM, dann frazier wrote:
> On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> <yuanzhichang@hisilicon.com> wrote:
>> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
>> with some special host-local I/O ports known on x86. To access the I/O
>> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
>> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
>> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
>> registered before probing the downstream devices and set up the I/O mapping.
>> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
>>
>> This patch introdueces a new ACPI handler for this device category. Through the
>> handler attach callback, the indirect-IO hosts I/O registration is done and
>> all peripherals' I/O resources are translated into logic/fake PIO before
>> starting the enumeration.
>>
>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>> ---
>>  drivers/acpi/Makefile          |   1 +
>>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/acpi/internal.h        |   5 +
>>  drivers/acpi/scan.c            |   1 +
>>  4 files changed, 351 insertions(+)
>>  create mode 100644 drivers/acpi/acpi_indirectio.c
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index a391bbc..10e5f2b 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>  acpi-y                         += acpi_lpat.o
>>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
>>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
>> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
>>
>>  # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
>> new file mode 100644
>> index 0000000..c8c80b5
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_indirectio.c
>> @@ -0,0 +1,344 @@

[snip]

>> +acpi_build_logiciores_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_logiciores, &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);
> 
> (Seth Forshee noticed this issue, just passing it on)
> 
> Should this just allocate the full buffer->length? That would keep the
> length attribute accurate (possibly avoiding an off-by-1 error later).
> It's not clear what the trailing byte is needed for, but other drivers
> allocate it as well (drivers/acpi/pci_link.c and
> drivers/platform/x86/sony-laptop.c).

Thanks for your suggestion!

I also curious why this one appended byte is needed as it seems the later
acpi_set_current_resources() doesn't use this byte.
And I tested without setting the buffer->length as the length of resource list
directly, it seems ok.

But anyway, it looks more reasonable to allocate the memory with the
buffer->length rather than buffer->length - 1;

I was made the V9 patch-set, and I can add your suggestion there. But I also
awaiting for ARM64 ACPI maintainer's comment about this patch before really
sending V9. I wonder whether there is better way to make our indirect-IO devices
can be assigned the logic PIO before the enumeration...

Lorenzo, Hanjun, what do you think about this patch?

Thanks,
Zhichang

> 
>  -dann
> 

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
  2017-04-21  2:22       ` zhichang.yuan
  (?)
  (?)
@ 2017-04-21 17:14         ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 78+ messages in thread
From: Lorenzo Pieralisi @ 2017-04-21 17:14 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Mark Rutland, Catalin Marinas, Gabriele Paoloni, rafael, benh,
	Will Deacon, linuxarm, Frank Rowand, Arnd Bergmann, dann frazier,
	xuwei5, linux-acpi, linux-pci, devicetree, Corey Minyard,
	John Garry, Zou Rongrong, Rob Herring, Bjorn Helgaas, kantyzc,
	linux-arm-kernel, Seth Forshee, linux-kernel, zhichang.yuan

On Fri, Apr 21, 2017 at 10:22:52AM +0800, zhichang.yuan wrote:
> Hi, Dann,
> 
> 
> 
> On 04/21/2017 04:57 AM, dann frazier wrote:
> > On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> > <yuanzhichang@hisilicon.com> wrote:
> >> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> >> with some special host-local I/O ports known on x86. To access the I/O
> >> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> >> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> >> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> >> registered before probing the downstream devices and set up the I/O mapping.
> >> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> >>
> >> This patch introdueces a new ACPI handler for this device category. Through the
> >> handler attach callback, the indirect-IO hosts I/O registration is done and
> >> all peripherals' I/O resources are translated into logic/fake PIO before
> >> starting the enumeration.
> >>
> >> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> >> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> >> ---
> >>  drivers/acpi/Makefile          |   1 +
> >>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
> >>  drivers/acpi/internal.h        |   5 +
> >>  drivers/acpi/scan.c            |   1 +
> >>  4 files changed, 351 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_indirectio.c
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index a391bbc..10e5f2b 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
> >>  acpi-y                         += acpi_lpat.o
> >>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
> >>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> >> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
> >>
> >>  # These are (potentially) separate modules
> >>
> >> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> >> new file mode 100644
> >> index 0000000..c8c80b5
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_indirectio.c
> >> @@ -0,0 +1,344 @@
> 
> [snip]
> 
> >> +acpi_build_logiciores_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_logiciores, &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);
> > 
> > (Seth Forshee noticed this issue, just passing it on)
> > 
> > Should this just allocate the full buffer->length? That would keep the
> > length attribute accurate (possibly avoiding an off-by-1 error later).
> > It's not clear what the trailing byte is needed for, but other drivers
> > allocate it as well (drivers/acpi/pci_link.c and
> > drivers/platform/x86/sony-laptop.c).
> 
> Thanks for your suggestion!
> 
> I also curious why this one appended byte is needed as it seems the later
> acpi_set_current_resources() doesn't use this byte.
> And I tested without setting the buffer->length as the length of resource list
> directly, it seems ok.
> 
> But anyway, it looks more reasonable to allocate the memory with the
> buffer->length rather than buffer->length - 1;
> 
> I was made the V9 patch-set, and I can add your suggestion there. But I also
> awaiting for ARM64 ACPI maintainer's comment about this patch before really
> sending V9. I wonder whether there is better way to make our indirect-IO devices
> can be assigned the logic PIO before the enumeration...
> 
> Lorenzo, Hanjun, what do you think about this patch?

I will get to it shortly, sorry for the delay.

Thanks,
Lorenzo

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-21 17:14         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 78+ messages in thread
From: Lorenzo Pieralisi @ 2017-04-21 17:14 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: dann frazier, zhichang.yuan, hanjun.guo, sudeep.holla,
	Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	Mark Rutland, Brian Starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, devicetree, linux-pci, Corey Minyard,
	Zou Rongrong, John Garry, Gabriele Paoloni, kantyzc, xuwei5,
	Seth Forshee

On Fri, Apr 21, 2017 at 10:22:52AM +0800, zhichang.yuan wrote:
> Hi, Dann,
> 
> 
> 
> On 04/21/2017 04:57 AM, dann frazier wrote:
> > On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> > <yuanzhichang@hisilicon.com> wrote:
> >> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> >> with some special host-local I/O ports known on x86. To access the I/O
> >> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> >> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> >> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> >> registered before probing the downstream devices and set up the I/O mapping.
> >> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> >>
> >> This patch introdueces a new ACPI handler for this device category. Through the
> >> handler attach callback, the indirect-IO hosts I/O registration is done and
> >> all peripherals' I/O resources are translated into logic/fake PIO before
> >> starting the enumeration.
> >>
> >> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> >> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> >> ---
> >>  drivers/acpi/Makefile          |   1 +
> >>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
> >>  drivers/acpi/internal.h        |   5 +
> >>  drivers/acpi/scan.c            |   1 +
> >>  4 files changed, 351 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_indirectio.c
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index a391bbc..10e5f2b 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
> >>  acpi-y                         += acpi_lpat.o
> >>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
> >>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> >> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
> >>
> >>  # These are (potentially) separate modules
> >>
> >> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> >> new file mode 100644
> >> index 0000000..c8c80b5
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_indirectio.c
> >> @@ -0,0 +1,344 @@
> 
> [snip]
> 
> >> +acpi_build_logiciores_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_logiciores, &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);
> > 
> > (Seth Forshee noticed this issue, just passing it on)
> > 
> > Should this just allocate the full buffer->length? That would keep the
> > length attribute accurate (possibly avoiding an off-by-1 error later).
> > It's not clear what the trailing byte is needed for, but other drivers
> > allocate it as well (drivers/acpi/pci_link.c and
> > drivers/platform/x86/sony-laptop.c).
> 
> Thanks for your suggestion!
> 
> I also curious why this one appended byte is needed as it seems the later
> acpi_set_current_resources() doesn't use this byte.
> And I tested without setting the buffer->length as the length of resource list
> directly, it seems ok.
> 
> But anyway, it looks more reasonable to allocate the memory with the
> buffer->length rather than buffer->length - 1;
> 
> I was made the V9 patch-set, and I can add your suggestion there. But I also
> awaiting for ARM64 ACPI maintainer's comment about this patch before really
> sending V9. I wonder whether there is better way to make our indirect-IO devices
> can be assigned the logic PIO before the enumeration...
> 
> Lorenzo, Hanjun, what do you think about this patch?

I will get to it shortly, sorry for the delay.

Thanks,
Lorenzo

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

* Re: [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-21 17:14         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 78+ messages in thread
From: Lorenzo Pieralisi @ 2017-04-21 17:14 UTC (permalink / raw)
  To: zhichang.yuan
  Cc: Mark Rutland, Catalin Marinas, Gabriele Paoloni, rafael, benh,
	Will Deacon, linuxarm, Frank Rowand, Arnd Bergmann, dann frazier,
	xuwei5, linux-acpi, linux-pci, devicetree, Corey Minyard,
	John Garry, Zou Rongrong, Rob Herring, Bjorn Helgaas, kantyzc,
	linux-arm-kernel, Seth Forshee, linux-kernel, zhichang.yuan,
	hanjun.guo, sudeep.holla, olof, Brian Starkey

On Fri, Apr 21, 2017 at 10:22:52AM +0800, zhichang.yuan wrote:
> Hi, Dann,
> 
> 
> 
> On 04/21/2017 04:57 AM, dann frazier wrote:
> > On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> > <yuanzhichang@hisilicon.com> wrote:
> >> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> >> with some special host-local I/O ports known on x86. To access the I/O
> >> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> >> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> >> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> >> registered before probing the downstream devices and set up the I/O mapping.
> >> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> >>
> >> This patch introdueces a new ACPI handler for this device category. Through the
> >> handler attach callback, the indirect-IO hosts I/O registration is done and
> >> all peripherals' I/O resources are translated into logic/fake PIO before
> >> starting the enumeration.
> >>
> >> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> >> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> >> ---
> >>  drivers/acpi/Makefile          |   1 +
> >>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
> >>  drivers/acpi/internal.h        |   5 +
> >>  drivers/acpi/scan.c            |   1 +
> >>  4 files changed, 351 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_indirectio.c
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index a391bbc..10e5f2b 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
> >>  acpi-y                         += acpi_lpat.o
> >>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
> >>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> >> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
> >>
> >>  # These are (potentially) separate modules
> >>
> >> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> >> new file mode 100644
> >> index 0000000..c8c80b5
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_indirectio.c
> >> @@ -0,0 +1,344 @@
> 
> [snip]
> 
> >> +acpi_build_logiciores_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_logiciores, &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);
> > 
> > (Seth Forshee noticed this issue, just passing it on)
> > 
> > Should this just allocate the full buffer->length? That would keep the
> > length attribute accurate (possibly avoiding an off-by-1 error later).
> > It's not clear what the trailing byte is needed for, but other drivers
> > allocate it as well (drivers/acpi/pci_link.c and
> > drivers/platform/x86/sony-laptop.c).
> 
> Thanks for your suggestion!
> 
> I also curious why this one appended byte is needed as it seems the later
> acpi_set_current_resources() doesn't use this byte.
> And I tested without setting the buffer->length as the length of resource list
> directly, it seems ok.
> 
> But anyway, it looks more reasonable to allocate the memory with the
> buffer->length rather than buffer->length - 1;
> 
> I was made the V9 patch-set, and I can add your suggestion there. But I also
> awaiting for ARM64 ACPI maintainer's comment about this patch before really
> sending V9. I wonder whether there is better way to make our indirect-IO devices
> can be assigned the logic PIO before the enumeration...
> 
> Lorenzo, Hanjun, what do you think about this patch?

I will get to it shortly, sorry for the delay.

Thanks,
Lorenzo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO
@ 2017-04-21 17:14         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 78+ messages in thread
From: Lorenzo Pieralisi @ 2017-04-21 17:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 21, 2017 at 10:22:52AM +0800, zhichang.yuan wrote:
> Hi, Dann,
> 
> 
> 
> On 04/21/2017 04:57 AM, dann frazier wrote:
> > On Thu, Mar 30, 2017 at 9:26 AM, zhichang.yuan
> > <yuanzhichang@hisilicon.com> wrote:
> >> On some platforms(such as Hip06/Hip07), the legacy ISA/LPC devices access I/O
> >> with some special host-local I/O ports known on x86. To access the I/O
> >> peripherals, an indirect-IO mechanism is introduced to mapped the host-local
> >> I/O to system logical/fake PIO similar the PCI MMIO on architectures where no
> >> separate I/O space exists. Just as PCI MMIO, the host I/O range should be
> >> registered before probing the downstream devices and set up the I/O mapping.
> >> But current ACPI bus probing doesn't support these indirect-IO hosts/devices.
> >>
> >> This patch introdueces a new ACPI handler for this device category. Through the
> >> handler attach callback, the indirect-IO hosts I/O registration is done and
> >> all peripherals' I/O resources are translated into logic/fake PIO before
> >> starting the enumeration.
> >>
> >> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> >> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> >> ---
> >>  drivers/acpi/Makefile          |   1 +
> >>  drivers/acpi/acpi_indirectio.c | 344 +++++++++++++++++++++++++++++++++++++++++
> >>  drivers/acpi/internal.h        |   5 +
> >>  drivers/acpi/scan.c            |   1 +
> >>  4 files changed, 351 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_indirectio.c
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index a391bbc..10e5f2b 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -57,6 +57,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
> >>  acpi-y                         += acpi_lpat.o
> >>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
> >>  acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
> >> +acpi-$(CONFIG_INDIRECT_PIO)    += acpi_indirectio.o
> >>
> >>  # These are (potentially) separate modules
> >>
> >> diff --git a/drivers/acpi/acpi_indirectio.c b/drivers/acpi/acpi_indirectio.c
> >> new file mode 100644
> >> index 0000000..c8c80b5
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_indirectio.c
> >> @@ -0,0 +1,344 @@
> 
> [snip]
> 
> >> +acpi_build_logiciores_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_logiciores, &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);
> > 
> > (Seth Forshee noticed this issue, just passing it on)
> > 
> > Should this just allocate the full buffer->length? That would keep the
> > length attribute accurate (possibly avoiding an off-by-1 error later).
> > It's not clear what the trailing byte is needed for, but other drivers
> > allocate it as well (drivers/acpi/pci_link.c and
> > drivers/platform/x86/sony-laptop.c).
> 
> Thanks for your suggestion!
> 
> I also curious why this one appended byte is needed as it seems the later
> acpi_set_current_resources() doesn't use this byte.
> And I tested without setting the buffer->length as the length of resource list
> directly, it seems ok.
> 
> But anyway, it looks more reasonable to allocate the memory with the
> buffer->length rather than buffer->length - 1;
> 
> I was made the V9 patch-set, and I can add your suggestion there. But I also
> awaiting for ARM64 ACPI maintainer's comment about this patch before really
> sending V9. I wonder whether there is better way to make our indirect-IO devices
> can be assigned the logic PIO before the enumeration...
> 
> Lorenzo, Hanjun, what do you think about this patch?

I will get to it shortly, sorry for the delay.

Thanks,
Lorenzo

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

end of thread, other threads:[~2017-04-21 18:08 UTC | newest]

Thread overview: 78+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-30 15:26 [PATCH V8 0/7] LPC: legacy ISA I/O support zhichang.yuan
2017-03-30 15:26 ` zhichang.yuan
2017-03-30 15:26 ` zhichang.yuan
2017-03-30 15:26 ` [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-04-01  5:58   ` kbuild test robot
2017-04-01  5:58     ` kbuild test robot
2017-04-01  5:58     ` kbuild test robot
2017-04-01  5:58     ` kbuild test robot
2017-04-05 12:18     ` zhichang.yuan
2017-04-05 12:18       ` zhichang.yuan
2017-04-05 12:18       ` zhichang.yuan
2017-04-01  6:31   ` kbuild test robot
2017-04-01  6:31     ` kbuild test robot
2017-04-01  6:31     ` kbuild test robot
2017-03-30 15:26 ` [PATCH V8 2/6] PCI: Apply the new generic I/O management on PCI IO hosts zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26 ` [PATCH V8 3/6] OF: Add missing I/O range exception for indirect-IO devices zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26 ` [PATCH V8 4/6] LPC: Support the device-tree LPC host on Hip06/Hip07 zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26 ` [PATCH V8 5/6] ACPI: Support the probing on the devices which apply indirect-IO zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
     [not found]   ` <1490887619-61732-6-git-send-email-yuanzhichang-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
2017-03-30 20:31     ` Rafael J. Wysocki
2017-03-30 20:31       ` Rafael J. Wysocki
2017-03-30 20:31       ` Rafael J. Wysocki
2017-03-30 20:31       ` Rafael J. Wysocki
2017-03-31  6:52       ` zhichang.yuan
2017-03-31  6:52         ` zhichang.yuan
2017-03-31  6:52         ` zhichang.yuan
2017-03-31  6:52         ` zhichang.yuan
2017-03-31 23:02         ` Rafael J. Wysocki
2017-03-31 23:02           ` Rafael J. Wysocki
2017-03-31 23:02           ` Rafael J. Wysocki
2017-03-31 23:02           ` Rafael J. Wysocki
2017-04-01  2:16           ` zhichang.yuan
2017-04-01  2:16             ` zhichang.yuan
2017-04-01  2:16             ` zhichang.yuan
2017-04-01  2:16             ` zhichang.yuan
2017-04-01  9:52             ` Rafael J. Wysocki
2017-04-01  9:52               ` Rafael J. Wysocki
2017-04-01  9:52               ` Rafael J. Wysocki
2017-04-01  9:52               ` Rafael J. Wysocki
     [not found]               ` <CAJZ5v0iYD=2HVP9D-2fBBDUzkOJLrzzH7Rwg1ALQ-kBx-iSeTg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-04-02 14:58                 ` Gabriele Paoloni
2017-04-02 14:58                   ` Gabriele Paoloni
2017-04-02 14:58                   ` Gabriele Paoloni
2017-04-02 14:58                   ` Gabriele Paoloni
2017-04-20 20:57   ` dann frazier
2017-04-20 20:57     ` dann frazier
2017-04-20 20:57     ` dann frazier
2017-04-20 20:57     ` dann frazier
2017-04-21  2:22     ` zhichang.yuan
2017-04-21  2:22       ` zhichang.yuan
2017-04-21  2:22       ` zhichang.yuan
2017-04-21  2:22       ` zhichang.yuan
2017-04-21 17:14       ` Lorenzo Pieralisi
2017-04-21 17:14         ` Lorenzo Pieralisi
2017-04-21 17:14         ` Lorenzo Pieralisi
2017-04-21 17:14         ` Lorenzo Pieralisi
2017-03-30 15:26 ` [PATCH V8 6/6] LPC: Add the ACPI LPC support zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 15:26   ` zhichang.yuan
2017-03-30 21:42 ` [PATCH V8 0/7] LPC: legacy ISA I/O support dann frazier
2017-03-30 21:42   ` dann frazier
2017-03-30 21:42   ` dann frazier
2017-03-30 21:42   ` dann frazier
2017-03-31  6:36   ` zhichang.yuan
2017-03-31  6:36     ` zhichang.yuan
2017-03-31  6:36     ` zhichang.yuan
2017-03-31  6:36     ` zhichang.yuan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.