All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-27 16:11 ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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 accessors are based
on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
specific accessors rather than MMIO.
To solve this issue and keep the relevant existing peripherals' drivers untouched,
this patchset:
   - introduces a generic I/O space management framework, LIBIO, to support I/O
     operations on host controllers operating either on MMIO buses or on buses
     requiring specific driver I/O accessors;
   - redefines the in/out accessors to provide a unified interface for both MMIO
     and driver specific I/O operations. Using LIBIO, th call of in/out() from
     the host children drivers, such as ipmi-si, will be redirected to the
     corresponding device-specific I/O hooks to perform 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.

 The whole patchset has been tested on Hip07 D05 board both using DTB and ACPI.

Changes from v9:
  - patch 2 has been split into 3 patches according to Bjorn comments on
    v9 thread
  - patch 1 has been reworked accordign to Bjorn comments on v9
  - now logic_pio_trans_hwaddr() has a sanity check to make sure the resource
    size fits into the assigned range
  - in patch 5 the MFD framework has been used to probe the LPC children
    according to the suggestion from Mika Westerberg
  - Maintaner has changed to Huawei Linuxarm mailing list

Changes from v8:
  - Simplified LIB IO framewrok
  - Moved INDIRECT PIO ACPI framework under acpi/arm64
  - Renamed occurrences of "lib io" and "indirect io" to "lib pio" and
    "indirect pio" to keep the patchset nomenclature consistent
  - Removed Alignment reuqirements
  - Moved LPC specific code out of ACPI common framework
  - Now PIO indirect HW ranges can overlap
  - Changed HiSilicon LPC driver maintainer (Gabriele Paoloni now) and split
    maintaner file modifications in a separate commit
  - Removed the commit with the DT nodes support for hip06 and hip07 (to be
    pushed separately)
  - Added a checking on ioport_map() not to break that function as Arnd points
    out in V7 review thread;
  - fixed the compile issues on alpha, m68k;

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;

V9 thread here: https://lkml.org/lkml/2017/5/25/263
V8 thread here: https://lkml.org/lkml/2017/3/30/619
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


Gabriele Paoloni (1):
  MANTAINERS: Add maintainer for HiSilicon LPC driver

gabriele paoloni (4):
  PCI: remove unused __weak attribute in pci_register_io_range()
  PCI: add fwnode handler as input param of pci_register_io_range()
  PCI: Apply the new generic I/O management on PCI IO hosts
  ACPI: Translate the I/O range of non-MMIO devices before scanning

zhichang.yuan (4):
  LIB: Introduce a generic PIO mapping method
  OF: Add missing I/O range exception for indirect-IO devices
  LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  LPC: Add the ACPI LPC support

 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  33 ++
 MAINTAINERS                                        |   7 +
 drivers/acpi/arm64/Makefile                        |   1 +
 drivers/acpi/arm64/acpi_indirectio.c               | 159 +++++
 drivers/acpi/arm64/acpi_indirectio.h               |  28 +
 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                             | 656 +++++++++++++++++++++
 drivers/of/address.c                               |  95 ++-
 drivers/pci/pci.c                                  |  98 +--
 include/asm-generic/io.h                           |  28 +-
 include/linux/logic_pio.h                          | 118 ++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  26 +
 lib/Makefile                                       |   2 +
 lib/logic_pio.c                                    | 286 +++++++++
 19 files changed, 1463 insertions(+), 101 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/acpi/arm64/acpi_indirectio.c
 create mode 100644 drivers/acpi/arm64/acpi_indirectio.h
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

-- 
2.7.4



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

* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-27 16:11 ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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 accessors are based
on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
specific accessors rather than MMIO.
To solve this issue and keep the relevant existing peripherals' drivers untouched,
this patchset:
   - introduces a generic I/O space management framework, LIBIO, to support I/O
     operations on host controllers operating either on MMIO buses or on buses
     requiring specific driver I/O accessors;
   - redefines the in/out accessors to provide a unified interface for both MMIO
     and driver specific I/O operations. Using LIBIO, th call of in/out() from
     the host children drivers, such as ipmi-si, will be redirected to the
     corresponding device-specific I/O hooks to perform 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.

 The whole patchset has been tested on Hip07 D05 board both using DTB and ACPI.

Changes from v9:
  - patch 2 has been split into 3 patches according to Bjorn comments on
    v9 thread
  - patch 1 has been reworked accordign to Bjorn comments on v9
  - now logic_pio_trans_hwaddr() has a sanity check to make sure the resource
    size fits into the assigned range
  - in patch 5 the MFD framework has been used to probe the LPC children
    according to the suggestion from Mika Westerberg
  - Maintaner has changed to Huawei Linuxarm mailing list

Changes from v8:
  - Simplified LIB IO framewrok
  - Moved INDIRECT PIO ACPI framework under acpi/arm64
  - Renamed occurrences of "lib io" and "indirect io" to "lib pio" and
    "indirect pio" to keep the patchset nomenclature consistent
  - Removed Alignment reuqirements
  - Moved LPC specific code out of ACPI common framework
  - Now PIO indirect HW ranges can overlap
  - Changed HiSilicon LPC driver maintainer (Gabriele Paoloni now) and split
    maintaner file modifications in a separate commit
  - Removed the commit with the DT nodes support for hip06 and hip07 (to be
    pushed separately)
  - Added a checking on ioport_map() not to break that function as Arnd points
    out in V7 review thread;
  - fixed the compile issues on alpha, m68k;

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;

V9 thread here: https://lkml.org/lkml/2017/5/25/263
V8 thread here: https://lkml.org/lkml/2017/3/30/619
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


Gabriele Paoloni (1):
  MANTAINERS: Add maintainer for HiSilicon LPC driver

gabriele paoloni (4):
  PCI: remove unused __weak attribute in pci_register_io_range()
  PCI: add fwnode handler as input param of pci_register_io_range()
  PCI: Apply the new generic I/O management on PCI IO hosts
  ACPI: Translate the I/O range of non-MMIO devices before scanning

zhichang.yuan (4):
  LIB: Introduce a generic PIO mapping method
  OF: Add missing I/O range exception for indirect-IO devices
  LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  LPC: Add the ACPI LPC support

 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  33 ++
 MAINTAINERS                                        |   7 +
 drivers/acpi/arm64/Makefile                        |   1 +
 drivers/acpi/arm64/acpi_indirectio.c               | 159 +++++
 drivers/acpi/arm64/acpi_indirectio.h               |  28 +
 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                             | 656 +++++++++++++++++++++
 drivers/of/address.c                               |  95 ++-
 drivers/pci/pci.c                                  |  98 +--
 include/asm-generic/io.h                           |  28 +-
 include/linux/logic_pio.h                          | 118 ++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  26 +
 lib/Makefile                                       |   2 +
 lib/logic_pio.c                                    | 286 +++++++++
 19 files changed, 1463 insertions(+), 101 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/acpi/arm64/acpi_indirectio.c
 create mode 100644 drivers/acpi/arm64/acpi_indirectio.h
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

-- 
2.7.4

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

* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-27 16:11 ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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 accessors are based
on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
specific accessors rather than MMIO.
To solve this issue and keep the relevant existing peripherals' drivers untouched,
this patchset:
   - introduces a generic I/O space management framework, LIBIO, to support I/O
     operations on host controllers operating either on MMIO buses or on buses
     requiring specific driver I/O accessors;
   - redefines the in/out accessors to provide a unified interface for both MMIO
     and driver specific I/O operations. Using LIBIO, th call of in/out() from
     the host children drivers, such as ipmi-si, will be redirected to the
     corresponding device-specific I/O hooks to perform 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.

 The whole patchset has been tested on Hip07 D05 board both using DTB and ACPI.

Changes from v9:
  - patch 2 has been split into 3 patches according to Bjorn comments on
    v9 thread
  - patch 1 has been reworked accordign to Bjorn comments on v9
  - now logic_pio_trans_hwaddr() has a sanity check to make sure the resource
    size fits into the assigned range
  - in patch 5 the MFD framework has been used to probe the LPC children
    according to the suggestion from Mika Westerberg
  - Maintaner has changed to Huawei Linuxarm mailing list

Changes from v8:
  - Simplified LIB IO framewrok
  - Moved INDIRECT PIO ACPI framework under acpi/arm64
  - Renamed occurrences of "lib io" and "indirect io" to "lib pio" and
    "indirect pio" to keep the patchset nomenclature consistent
  - Removed Alignment reuqirements
  - Moved LPC specific code out of ACPI common framework
  - Now PIO indirect HW ranges can overlap
  - Changed HiSilicon LPC driver maintainer (Gabriele Paoloni now) and split
    maintaner file modifications in a separate commit
  - Removed the commit with the DT nodes support for hip06 and hip07 (to be
    pushed separately)
  - Added a checking on ioport_map() not to break that function as Arnd points
    out in V7 review thread;
  - fixed the compile issues on alpha, m68k;

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;

V9 thread here: https://lkml.org/lkml/2017/5/25/263
V8 thread here: https://lkml.org/lkml/2017/3/30/619
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


Gabriele Paoloni (1):
  MANTAINERS: Add maintainer for HiSilicon LPC driver

gabriele paoloni (4):
  PCI: remove unused __weak attribute in pci_register_io_range()
  PCI: add fwnode handler as input param of pci_register_io_range()
  PCI: Apply the new generic I/O management on PCI IO hosts
  ACPI: Translate the I/O range of non-MMIO devices before scanning

zhichang.yuan (4):
  LIB: Introduce a generic PIO mapping method
  OF: Add missing I/O range exception for indirect-IO devices
  LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  LPC: Add the ACPI LPC support

 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  33 ++
 MAINTAINERS                                        |   7 +
 drivers/acpi/arm64/Makefile                        |   1 +
 drivers/acpi/arm64/acpi_indirectio.c               | 159 +++++
 drivers/acpi/arm64/acpi_indirectio.h               |  28 +
 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                             | 656 +++++++++++++++++++++
 drivers/of/address.c                               |  95 ++-
 drivers/pci/pci.c                                  |  98 +--
 include/asm-generic/io.h                           |  28 +-
 include/linux/logic_pio.h                          | 118 ++++
 include/linux/pci.h                                |   3 +-
 lib/Kconfig                                        |  26 +
 lib/Makefile                                       |   2 +
 lib/logic_pio.c                                    | 286 +++++++++
 19 files changed, 1463 insertions(+), 101 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/acpi/arm64/acpi_indirectio.c
 create mode 100644 drivers/acpi/arm64/acpi_indirectio.h
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

-- 
2.7.4

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

* [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

In commit 41f8bba7f555 ("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  |  26 +++++
 include/linux/logic_pio.h | 118 +++++++++++++++++++
 lib/Kconfig               |  26 +++++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 286 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 458 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..334e5db 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
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..f0a6f15
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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_LOGIC_PIO_H
+#define __LINUX_LOGIC_PIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/fwnode.h>
+
+#define PIO_INDIRECT		0x01UL /* indirect IO flag */
+#define PIO_CPU_MMIO		0x00UL /* memory mapped io flag */
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t io_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+
+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
+u8 logic_inb(unsigned long addr);
+void logic_outb(u8 value, unsigned long addr);
+void logic_outw(u16 value, unsigned long addr);
+void logic_outl(u32 value, unsigned long addr);
+u16 logic_inw(unsigned long addr);
+u32 logic_inl(unsigned long addr);
+void logic_outb(u8 value, unsigned long addr);
+void logic_outw(u16 value, unsigned long addr);
+void logic_outl(u32 value, unsigned long addr);
+void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+void logic_outsb(unsigned long addr, const void *buffer, unsigned int count);
+void logic_outsw(unsigned long addr, const void *buffer, unsigned int count);
+void logic_outsl(unsigned long addr, const void *buffer, unsigned int count);
+
+#define insb logic_insb
+#define insw logic_insw
+#define insl logic_insl
+#define outsb logic_outsb
+#define outsw logic_outsw
+#define outsl logic_outsl
+
+/*
+ * Below we reserve 0x4000 bytes for Indirect IO as so far this library is only
+ * used by Hisilicon LPC Host. If needed in future we may reserve a wider IO
+ * area by redefining the macro below.
+ */
+#define PIO_INDIRECT_SIZE 0x4000
+#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
+#else
+#define MMIO_UPPER_LIMIT IO_SPACE_LIMIT
+#endif
+
+#ifdef CONFIG_LOGIC_PIO
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr, resource_size_t size);
+
+int logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+#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, resource_size_t size);
+{
+	return -1;
+}
+
+static inline struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+{
+	return NULL;
+}
+#endif
+
+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_LOGIC_PIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 6762529..d7443a6 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 40c1837..e0246ad 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..f8427cb
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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/logic_pio.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);
+
+/*
+ * register a new io range node in the io range list.
+ *
+ * @newrange: pointer to the io range to be registered.
+ *
+ * returns 0 on success, the error code in case of failure
+ */
+int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
+{
+	struct logic_pio_hwaddr *range;
+	int ret = 0;
+	resource_size_t start = new_range->hw_start;
+	resource_size_t end = new_range->hw_start + new_range->size;
+	resource_size_t allocated_mmio_size = 0;
+	resource_size_t allocated_iio_size = MMIO_UPPER_LIMIT;
+
+	if (!new_range || !new_range->fwnode || !new_range->size)
+		return -EINVAL;
+
+	mutex_lock(&io_range_mutex);
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+
+		if (range->fwnode == new_range->fwnode) {
+			/* range already there */
+			ret = -EFAULT;
+			goto end_register;
+		}
+		if (range->flags == PIO_CPU_MMIO &&
+				new_range->flags == PIO_CPU_MMIO) {
+			/* for MMIO ranges we need to check for overlap */
+			if (start >= range->hw_start + range->size ||
+				end < range->hw_start)
+				allocated_mmio_size += range->size;
+			else {
+				ret = -EFAULT;
+				goto end_register;
+			}
+		} else if (range->flags == PIO_INDIRECT &&
+				new_range->flags == PIO_INDIRECT) {
+			allocated_iio_size += range->size;
+		}
+	}
+
+	/* range not registered yet, check for available space */
+	if (new_range->flags == PIO_CPU_MMIO) {
+
+		if (allocated_mmio_size + new_range->size - 1 >
+			MMIO_UPPER_LIMIT) {
+			/* if it's too big check if 64K space can be reserved */
+			if (allocated_mmio_size + SZ_64K - 1 >
+			MMIO_UPPER_LIMIT) {
+				ret = -E2BIG;
+				goto end_register;
+			}
+			new_range->size = SZ_64K;
+			pr_warn("Requested IO range too big, new size set to 64K\n");
+		}
+
+		new_range->io_start = allocated_mmio_size;
+
+	} else if (new_range->flags == PIO_INDIRECT) {
+
+		if (allocated_iio_size + new_range->size - 1 >
+		IO_SPACE_LIMIT) {
+			ret = -E2BIG;
+			goto end_register;
+		}
+		new_range->io_start = allocated_iio_size;
+
+	} else {
+		/* invalid flag */
+		ret = -EINVAL;
+		goto end_register;
+	}
+
+	list_add_tail_rcu(&new_range->list, &io_range_list);
+
+end_register:
+	mutex_unlock(&io_range_mutex);
+	return ret;
+}
+
+/*
+ * 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;
+}
+
+/* return a registered range given an input PIO token */
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (pio >= range->io_start &&
+				pio < range->io_start + range->size)
+			return range;
+	}
+	pr_err("PIO entry token invalid\n");
+	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_hwaddr *range;
+	resource_size_t hwaddr = -1;
+
+	range = find_io_range(pio);
+	if (range)
+		hwaddr = range->hw_start + pio - range->io_start;
+
+	return hwaddr;
+}
+
+/*
+ * 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,
+		       resource_size_t size)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = find_io_range_by_fwnode(fwnode);
+	if (!range || range->flags == PIO_CPU_MMIO) {
+		pr_err("range not found or invalid\n");
+		return -1;
+	}
+	if (range->size < size) {
+		pr_err("resource size 0x%llx cannot fit in IO range size 0x%llx\n",
+		       size, range->size);
+		return -1;
+	}
+	return addr - range->hw_start + range->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->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->io_start;
+	}
+	pr_err("addr not registered in io_range_list\n");
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	type ret = -1;							\
+									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		ret = read##bw(PCI_IOBASE + addr);			\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			ret = entry->ops->pfin(entry->devpara,		\
+					addr, sizeof(type));		\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+	return ret;							\
+}									\
+									\
+void logic_out##bw(type value, unsigned long addr)			\
+{									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		write##bw(value, PCI_IOBASE + addr);			\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfout(entry->devpara,		\
+					addr, value, sizeof(type));	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+}									\
+									\
+void logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		reads##bw(PCI_IOBASE + addr, buffer, count);		\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfins(entry->devpara,		\
+				addr, buffer, sizeof(type), count);	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+									\
+}									\
+									\
+void logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	if (addr < MMIO_UPPER_LIMIT)					\
+		writes##bw(PCI_IOBASE + addr, buffer, count);		\
+	else {								\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfouts(entry->devpara,		\
+				addr, buffer, sizeof(type), count);	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+}
+
+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 */
-- 
2.7.4



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

* [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

In commit 41f8bba7f555 ("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  |  26 +++++
 include/linux/logic_pio.h | 118 +++++++++++++++++++
 lib/Kconfig               |  26 +++++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 286 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 458 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..334e5db 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
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..f0a6f15
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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_LOGIC_PIO_H
+#define __LINUX_LOGIC_PIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/fwnode.h>
+
+#define PIO_INDIRECT		0x01UL /* indirect IO flag */
+#define PIO_CPU_MMIO		0x00UL /* memory mapped io flag */
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t io_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+
+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
+u8 logic_inb(unsigned long addr);
+void logic_outb(u8 value, unsigned long addr);
+void logic_outw(u16 value, unsigned long addr);
+void logic_outl(u32 value, unsigned long addr);
+u16 logic_inw(unsigned long addr);
+u32 logic_inl(unsigned long addr);
+void logic_outb(u8 value, unsigned long addr);
+void logic_outw(u16 value, unsigned long addr);
+void logic_outl(u32 value, unsigned long addr);
+void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+void logic_outsb(unsigned long addr, const void *buffer, unsigned int count);
+void logic_outsw(unsigned long addr, const void *buffer, unsigned int count);
+void logic_outsl(unsigned long addr, const void *buffer, unsigned int count);
+
+#define insb logic_insb
+#define insw logic_insw
+#define insl logic_insl
+#define outsb logic_outsb
+#define outsw logic_outsw
+#define outsl logic_outsl
+
+/*
+ * Below we reserve 0x4000 bytes for Indirect IO as so far this library is only
+ * used by Hisilicon LPC Host. If needed in future we may reserve a wider IO
+ * area by redefining the macro below.
+ */
+#define PIO_INDIRECT_SIZE 0x4000
+#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
+#else
+#define MMIO_UPPER_LIMIT IO_SPACE_LIMIT
+#endif
+
+#ifdef CONFIG_LOGIC_PIO
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr, resource_size_t size);
+
+int logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+#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, resource_size_t size);
+{
+	return -1;
+}
+
+static inline struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+{
+	return NULL;
+}
+#endif
+
+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_LOGIC_PIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 6762529..d7443a6 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 40c1837..e0246ad 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..f8427cb
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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/logic_pio.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);
+
+/*
+ * register a new io range node in the io range list.
+ *
+ * @newrange: pointer to the io range to be registered.
+ *
+ * returns 0 on success, the error code in case of failure
+ */
+int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
+{
+	struct logic_pio_hwaddr *range;
+	int ret = 0;
+	resource_size_t start = new_range->hw_start;
+	resource_size_t end = new_range->hw_start + new_range->size;
+	resource_size_t allocated_mmio_size = 0;
+	resource_size_t allocated_iio_size = MMIO_UPPER_LIMIT;
+
+	if (!new_range || !new_range->fwnode || !new_range->size)
+		return -EINVAL;
+
+	mutex_lock(&io_range_mutex);
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+
+		if (range->fwnode == new_range->fwnode) {
+			/* range already there */
+			ret = -EFAULT;
+			goto end_register;
+		}
+		if (range->flags == PIO_CPU_MMIO &&
+				new_range->flags == PIO_CPU_MMIO) {
+			/* for MMIO ranges we need to check for overlap */
+			if (start >= range->hw_start + range->size ||
+				end < range->hw_start)
+				allocated_mmio_size += range->size;
+			else {
+				ret = -EFAULT;
+				goto end_register;
+			}
+		} else if (range->flags == PIO_INDIRECT &&
+				new_range->flags == PIO_INDIRECT) {
+			allocated_iio_size += range->size;
+		}
+	}
+
+	/* range not registered yet, check for available space */
+	if (new_range->flags == PIO_CPU_MMIO) {
+
+		if (allocated_mmio_size + new_range->size - 1 >
+			MMIO_UPPER_LIMIT) {
+			/* if it's too big check if 64K space can be reserved */
+			if (allocated_mmio_size + SZ_64K - 1 >
+			MMIO_UPPER_LIMIT) {
+				ret = -E2BIG;
+				goto end_register;
+			}
+			new_range->size = SZ_64K;
+			pr_warn("Requested IO range too big, new size set to 64K\n");
+		}
+
+		new_range->io_start = allocated_mmio_size;
+
+	} else if (new_range->flags == PIO_INDIRECT) {
+
+		if (allocated_iio_size + new_range->size - 1 >
+		IO_SPACE_LIMIT) {
+			ret = -E2BIG;
+			goto end_register;
+		}
+		new_range->io_start = allocated_iio_size;
+
+	} else {
+		/* invalid flag */
+		ret = -EINVAL;
+		goto end_register;
+	}
+
+	list_add_tail_rcu(&new_range->list, &io_range_list);
+
+end_register:
+	mutex_unlock(&io_range_mutex);
+	return ret;
+}
+
+/*
+ * 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;
+}
+
+/* return a registered range given an input PIO token */
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (pio >= range->io_start &&
+				pio < range->io_start + range->size)
+			return range;
+	}
+	pr_err("PIO entry token invalid\n");
+	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_hwaddr *range;
+	resource_size_t hwaddr = -1;
+
+	range = find_io_range(pio);
+	if (range)
+		hwaddr = range->hw_start + pio - range->io_start;
+
+	return hwaddr;
+}
+
+/*
+ * 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,
+		       resource_size_t size)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = find_io_range_by_fwnode(fwnode);
+	if (!range || range->flags == PIO_CPU_MMIO) {
+		pr_err("range not found or invalid\n");
+		return -1;
+	}
+	if (range->size < size) {
+		pr_err("resource size 0x%llx cannot fit in IO range size 0x%llx\n",
+		       size, range->size);
+		return -1;
+	}
+	return addr - range->hw_start + range->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->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->io_start;
+	}
+	pr_err("addr not registered in io_range_list\n");
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	type ret = -1;							\
+									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		ret = read##bw(PCI_IOBASE + addr);			\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			ret = entry->ops->pfin(entry->devpara,		\
+					addr, sizeof(type));		\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+	return ret;							\
+}									\
+									\
+void logic_out##bw(type value, unsigned long addr)			\
+{									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		write##bw(value, PCI_IOBASE + addr);			\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfout(entry->devpara,		\
+					addr, value, sizeof(type));	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+}									\
+									\
+void logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		reads##bw(PCI_IOBASE + addr, buffer, count);		\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfins(entry->devpara,		\
+				addr, buffer, sizeof(type), count);	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+									\
+}									\
+									\
+void logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	if (addr < MMIO_UPPER_LIMIT)					\
+		writes##bw(PCI_IOBASE + addr, buffer, count);		\
+	else {								\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfouts(entry->devpara,		\
+				addr, buffer, sizeof(type), count);	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+}
+
+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 */
-- 
2.7.4

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

* [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

In commit 41f8bba7f555 ("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  |  26 +++++
 include/linux/logic_pio.h | 118 +++++++++++++++++++
 lib/Kconfig               |  26 +++++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 286 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 458 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..334e5db 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
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..f0a6f15
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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_LOGIC_PIO_H
+#define __LINUX_LOGIC_PIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/fwnode.h>
+
+#define PIO_INDIRECT		0x01UL /* indirect IO flag */
+#define PIO_CPU_MMIO		0x00UL /* memory mapped io flag */
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t io_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+
+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
+u8 logic_inb(unsigned long addr);
+void logic_outb(u8 value, unsigned long addr);
+void logic_outw(u16 value, unsigned long addr);
+void logic_outl(u32 value, unsigned long addr);
+u16 logic_inw(unsigned long addr);
+u32 logic_inl(unsigned long addr);
+void logic_outb(u8 value, unsigned long addr);
+void logic_outw(u16 value, unsigned long addr);
+void logic_outl(u32 value, unsigned long addr);
+void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+void logic_outsb(unsigned long addr, const void *buffer, unsigned int count);
+void logic_outsw(unsigned long addr, const void *buffer, unsigned int count);
+void logic_outsl(unsigned long addr, const void *buffer, unsigned int count);
+
+#define insb logic_insb
+#define insw logic_insw
+#define insl logic_insl
+#define outsb logic_outsb
+#define outsw logic_outsw
+#define outsl logic_outsl
+
+/*
+ * Below we reserve 0x4000 bytes for Indirect IO as so far this library is only
+ * used by Hisilicon LPC Host. If needed in future we may reserve a wider IO
+ * area by redefining the macro below.
+ */
+#define PIO_INDIRECT_SIZE 0x4000
+#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
+#else
+#define MMIO_UPPER_LIMIT IO_SPACE_LIMIT
+#endif
+
+#ifdef CONFIG_LOGIC_PIO
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr, resource_size_t size);
+
+int logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+#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, resource_size_t size);
+{
+	return -1;
+}
+
+static inline struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+{
+	return NULL;
+}
+#endif
+
+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_LOGIC_PIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 6762529..d7443a6 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 40c1837..e0246ad 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..f8427cb
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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/logic_pio.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);
+
+/*
+ * register a new io range node in the io range list.
+ *
+ * @newrange: pointer to the io range to be registered.
+ *
+ * returns 0 on success, the error code in case of failure
+ */
+int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
+{
+	struct logic_pio_hwaddr *range;
+	int ret = 0;
+	resource_size_t start = new_range->hw_start;
+	resource_size_t end = new_range->hw_start + new_range->size;
+	resource_size_t allocated_mmio_size = 0;
+	resource_size_t allocated_iio_size = MMIO_UPPER_LIMIT;
+
+	if (!new_range || !new_range->fwnode || !new_range->size)
+		return -EINVAL;
+
+	mutex_lock(&io_range_mutex);
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+
+		if (range->fwnode == new_range->fwnode) {
+			/* range already there */
+			ret = -EFAULT;
+			goto end_register;
+		}
+		if (range->flags == PIO_CPU_MMIO &&
+				new_range->flags == PIO_CPU_MMIO) {
+			/* for MMIO ranges we need to check for overlap */
+			if (start >= range->hw_start + range->size ||
+				end < range->hw_start)
+				allocated_mmio_size += range->size;
+			else {
+				ret = -EFAULT;
+				goto end_register;
+			}
+		} else if (range->flags == PIO_INDIRECT &&
+				new_range->flags == PIO_INDIRECT) {
+			allocated_iio_size += range->size;
+		}
+	}
+
+	/* range not registered yet, check for available space */
+	if (new_range->flags == PIO_CPU_MMIO) {
+
+		if (allocated_mmio_size + new_range->size - 1 >
+			MMIO_UPPER_LIMIT) {
+			/* if it's too big check if 64K space can be reserved */
+			if (allocated_mmio_size + SZ_64K - 1 >
+			MMIO_UPPER_LIMIT) {
+				ret = -E2BIG;
+				goto end_register;
+			}
+			new_range->size = SZ_64K;
+			pr_warn("Requested IO range too big, new size set to 64K\n");
+		}
+
+		new_range->io_start = allocated_mmio_size;
+
+	} else if (new_range->flags == PIO_INDIRECT) {
+
+		if (allocated_iio_size + new_range->size - 1 >
+		IO_SPACE_LIMIT) {
+			ret = -E2BIG;
+			goto end_register;
+		}
+		new_range->io_start = allocated_iio_size;
+
+	} else {
+		/* invalid flag */
+		ret = -EINVAL;
+		goto end_register;
+	}
+
+	list_add_tail_rcu(&new_range->list, &io_range_list);
+
+end_register:
+	mutex_unlock(&io_range_mutex);
+	return ret;
+}
+
+/*
+ * 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;
+}
+
+/* return a registered range given an input PIO token */
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (pio >= range->io_start &&
+				pio < range->io_start + range->size)
+			return range;
+	}
+	pr_err("PIO entry token invalid\n");
+	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_hwaddr *range;
+	resource_size_t hwaddr = -1;
+
+	range = find_io_range(pio);
+	if (range)
+		hwaddr = range->hw_start + pio - range->io_start;
+
+	return hwaddr;
+}
+
+/*
+ * 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,
+		       resource_size_t size)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = find_io_range_by_fwnode(fwnode);
+	if (!range || range->flags == PIO_CPU_MMIO) {
+		pr_err("range not found or invalid\n");
+		return -1;
+	}
+	if (range->size < size) {
+		pr_err("resource size 0x%llx cannot fit in IO range size 0x%llx\n",
+		       size, range->size);
+		return -1;
+	}
+	return addr - range->hw_start + range->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->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->io_start;
+	}
+	pr_err("addr not registered in io_range_list\n");
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	type ret = -1;							\
+									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		ret = read##bw(PCI_IOBASE + addr);			\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			ret = entry->ops->pfin(entry->devpara,		\
+					addr, sizeof(type));		\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+	return ret;							\
+}									\
+									\
+void logic_out##bw(type value, unsigned long addr)			\
+{									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		write##bw(value, PCI_IOBASE + addr);			\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfout(entry->devpara,		\
+					addr, value, sizeof(type));	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+}									\
+									\
+void logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	if (addr < MMIO_UPPER_LIMIT) {					\
+		reads##bw(PCI_IOBASE + addr, buffer, count);		\
+	} else {							\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfins(entry->devpara,		\
+				addr, buffer, sizeof(type), count);	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+									\
+}									\
+									\
+void logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	if (addr < MMIO_UPPER_LIMIT)					\
+		writes##bw(PCI_IOBASE + addr, buffer, count);		\
+	else {								\
+		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
+									\
+		if (entry && entry->ops)				\
+			entry->ops->pfouts(entry->devpara,		\
+				addr, buffer, sizeof(type), count);	\
+		else							\
+			WARN_ON_ONCE(1);				\
+	}								\
+}
+
+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 */
-- 
2.7.4

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

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

Currently pci_register_io_range() has only one definition;
therefore there is no use of the __weak attribute.

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/pci/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index af0cc34..eee967c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
  * 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(phys_addr_t addr, resource_size_t size)
 {
 	int err = 0;
 
-- 
2.7.4

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

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

Currently pci_register_io_range() has only one definition;
therefore there is no use of the __weak attribute.

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/pci/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index af0cc34..eee967c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
  * 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(phys_addr_t addr, resource_size_t size)
 {
 	int err = 0;
 
-- 
2.7.4

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

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: gabriele paoloni <gabriele.paoloni@huawei.com>

Currently pci_register_io_range() has only one definition;
therefore there is no use of the __weak attribute.

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/pci/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index af0cc34..eee967c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
  * 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(phys_addr_t addr, resource_size_t size)
 {
 	int err = 0;
 
-- 
2.7.4

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

* [PATCH v10 3/9] PCI: add fwnode handler as input param of pci_register_io_range()
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

In preparation for having the PCI MMIO helpers to use the new generic
I/O space management(LOGIC_PIO) we need to add the fwnode handler as
extra input parameter.
This patch changes the signature of pci_register_io_range() and of
its callers as needed.

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/acpi/pci_root.c | 8 +++++---
 drivers/of/address.c    | 4 +++-
 drivers/pci/pci.c       | 3 ++-
 include/linux/pci.h     | 3 ++-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 9eec309..40164e3 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -729,7 +729,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;
@@ -738,7 +739,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);
@@ -780,7 +781,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 580bbf6..9d3ba07 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,6 +2,7 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
@@ -323,7 +324,8 @@ int of_pci_range_to_resource(struct of_pci_range *range,
 
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long port;
-		err = pci_register_io_range(range->cpu_addr, range->size);
+		err = pci_register_io_range(&np->fwnode, range->cpu_addr,
+				range->size);
 		if (err)
 			goto invalid_range;
 		port = pci_address_to_pio(range->cpu_addr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index eee967c..bcecb47 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3270,7 +3270,8 @@ static DEFINE_SPINLOCK(io_range_lock);
  * Record the PCI IO range (expressed as CPU physical address + size).
  * Return a negative value if an error has occured, zero otherwise
  */
-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)
 {
 	int err = 0;
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4869e66..1d958d7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1205,7 +1205,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);
-- 
2.7.4

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

* [PATCH v10 3/9] PCI: add fwnode handler as input param of pci_register_io_range()
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

In preparation for having the PCI MMIO helpers to use the new generic
I/O space management(LOGIC_PIO) we need to add the fwnode handler as
extra input parameter.
This patch changes the signature of pci_register_io_range() and of
its callers as needed.

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/acpi/pci_root.c | 8 +++++---
 drivers/of/address.c    | 4 +++-
 drivers/pci/pci.c       | 3 ++-
 include/linux/pci.h     | 3 ++-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 9eec309..40164e3 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -729,7 +729,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;
@@ -738,7 +739,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);
@@ -780,7 +781,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 580bbf6..9d3ba07 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,6 +2,7 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
@@ -323,7 +324,8 @@ int of_pci_range_to_resource(struct of_pci_range *range,
 
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long port;
-		err = pci_register_io_range(range->cpu_addr, range->size);
+		err = pci_register_io_range(&np->fwnode, range->cpu_addr,
+				range->size);
 		if (err)
 			goto invalid_range;
 		port = pci_address_to_pio(range->cpu_addr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index eee967c..bcecb47 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3270,7 +3270,8 @@ static DEFINE_SPINLOCK(io_range_lock);
  * Record the PCI IO range (expressed as CPU physical address + size).
  * Return a negative value if an error has occured, zero otherwise
  */
-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)
 {
 	int err = 0;
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4869e66..1d958d7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1205,7 +1205,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);
-- 
2.7.4

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

* [PATCH v10 3/9] PCI: add fwnode handler as input param of pci_register_io_range()
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: gabriele paoloni <gabriele.paoloni@huawei.com>

In preparation for having the PCI MMIO helpers to use the new generic
I/O space management(LOGIC_PIO) we need to add the fwnode handler as
extra input parameter.
This patch changes the signature of pci_register_io_range() and of
its callers as needed.

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/acpi/pci_root.c | 8 +++++---
 drivers/of/address.c    | 4 +++-
 drivers/pci/pci.c       | 3 ++-
 include/linux/pci.h     | 3 ++-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 9eec309..40164e3 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -729,7 +729,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;
@@ -738,7 +739,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);
@@ -780,7 +781,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 580bbf6..9d3ba07 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -2,6 +2,7 @@
 #define pr_fmt(fmt)	"OF: " fmt
 
 #include <linux/device.h>
+#include <linux/fwnode.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
@@ -323,7 +324,8 @@ int of_pci_range_to_resource(struct of_pci_range *range,
 
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long port;
-		err = pci_register_io_range(range->cpu_addr, range->size);
+		err = pci_register_io_range(&np->fwnode, range->cpu_addr,
+				range->size);
 		if (err)
 			goto invalid_range;
 		port = pci_address_to_pio(range->cpu_addr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index eee967c..bcecb47 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3270,7 +3270,8 @@ static DEFINE_SPINLOCK(io_range_lock);
  * Record the PCI IO range (expressed as CPU physical address + size).
  * Return a negative value if an error has occured, zero otherwise
  */
-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)
 {
 	int err = 0;
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4869e66..1d958d7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1205,7 +1205,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);
-- 
2.7.4

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

* [PATCH v10 4/9] PCI: Apply the new generic I/O management on PCI IO hosts
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>        #earlier draft
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/pci/pci.c        | 95 +++++++++---------------------------------------
 include/asm-generic/io.h |  2 +-
 2 files changed, 18 insertions(+), 79 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index bcecb47..a1ae4d3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/log2.h>
+#include <linux/logic_pio.h>
 #include <linux/pci-aspm.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
@@ -3255,17 +3256,6 @@ 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
@@ -3273,51 +3263,28 @@ static DEFINE_SPINLOCK(io_range_lock);
 int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
 			resource_size_t	size)
 {
-	int err = 0;
-
+	int ret = 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;
-	}
+	struct logic_pio_hwaddr *range;
 
-	/* 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;
-		}
-
-		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;
-	}
+	if (!range)
+		return -ENOMEM;
 
-	range->start = addr;
+	range->fwnode = fwnode;
 	range->size = size;
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
 
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	ret = logic_pio_register_range(range);
+	if (ret)
+		kfree(range);
 #endif
 
-	return err;
+	return ret;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3325,21 +3292,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 >= MMIO_UPPER_LIMIT)
 		return address;
 
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (pio >= allocated_size && pio < allocated_size + range->size) {
-			address = range->start + pio - allocated_size;
-			break;
-		}
-		allocated_size += range->size;
-	}
-	spin_unlock(&io_range_lock);
+	address = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3348,25 +3304,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/asm-generic/io.h b/include/asm-generic/io.h
index 334e5db..3980577 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -925,7 +925,7 @@ static inline void iounmap(void __iomem *addr)
 #define ioport_map ioport_map
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
-	return PCI_IOBASE + (port & IO_SPACE_LIMIT);
+	return PCI_IOBASE + (port & MMIO_UPPER_LIMIT);
 }
 #endif
 
-- 
2.7.4



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

* [PATCH v10 4/9] PCI: Apply the new generic I/O management on PCI IO hosts
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>        #earlier draft
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/pci/pci.c        | 95 +++++++++---------------------------------------
 include/asm-generic/io.h |  2 +-
 2 files changed, 18 insertions(+), 79 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index bcecb47..a1ae4d3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/log2.h>
+#include <linux/logic_pio.h>
 #include <linux/pci-aspm.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
@@ -3255,17 +3256,6 @@ 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
@@ -3273,51 +3263,28 @@ static DEFINE_SPINLOCK(io_range_lock);
 int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
 			resource_size_t	size)
 {
-	int err = 0;
-
+	int ret = 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;
-	}
+	struct logic_pio_hwaddr *range;
 
-	/* 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;
-		}
-
-		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;
-	}
+	if (!range)
+		return -ENOMEM;
 
-	range->start = addr;
+	range->fwnode = fwnode;
 	range->size = size;
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
 
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	ret = logic_pio_register_range(range);
+	if (ret)
+		kfree(range);
 #endif
 
-	return err;
+	return ret;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3325,21 +3292,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 >= MMIO_UPPER_LIMIT)
 		return address;
 
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (pio >= allocated_size && pio < allocated_size + range->size) {
-			address = range->start + pio - allocated_size;
-			break;
-		}
-		allocated_size += range->size;
-	}
-	spin_unlock(&io_range_lock);
+	address = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3348,25 +3304,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/asm-generic/io.h b/include/asm-generic/io.h
index 334e5db..3980577 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -925,7 +925,7 @@ static inline void iounmap(void __iomem *addr)
 #define ioport_map ioport_map
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
-	return PCI_IOBASE + (port & IO_SPACE_LIMIT);
+	return PCI_IOBASE + (port & MMIO_UPPER_LIMIT);
 }
 #endif
 
-- 
2.7.4

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

* [PATCH v10 4/9] PCI: Apply the new generic I/O management on PCI IO hosts
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>        #earlier draft
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
---
 drivers/pci/pci.c        | 95 +++++++++---------------------------------------
 include/asm-generic/io.h |  2 +-
 2 files changed, 18 insertions(+), 79 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index bcecb47..a1ae4d3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/log2.h>
+#include <linux/logic_pio.h>
 #include <linux/pci-aspm.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
@@ -3255,17 +3256,6 @@ 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
@@ -3273,51 +3263,28 @@ static DEFINE_SPINLOCK(io_range_lock);
 int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
 			resource_size_t	size)
 {
-	int err = 0;
-
+	int ret = 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;
-	}
+	struct logic_pio_hwaddr *range;
 
-	/* 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;
-		}
-
-		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;
-	}
+	if (!range)
+		return -ENOMEM;
 
-	range->start = addr;
+	range->fwnode = fwnode;
 	range->size = size;
+	range->hw_start = addr;
+	range->flags = PIO_CPU_MMIO;
 
-	list_add_tail(&range->list, &io_range_list);
-
-end_register:
-	spin_unlock(&io_range_lock);
+	ret = logic_pio_register_range(range);
+	if (ret)
+		kfree(range);
 #endif
 
-	return err;
+	return ret;
 }
 
 phys_addr_t pci_pio_to_address(unsigned long pio)
@@ -3325,21 +3292,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 >= MMIO_UPPER_LIMIT)
 		return address;
 
-	spin_lock(&io_range_lock);
-	list_for_each_entry(range, &io_range_list, list) {
-		if (pio >= allocated_size && pio < allocated_size + range->size) {
-			address = range->start + pio - allocated_size;
-			break;
-		}
-		allocated_size += range->size;
-	}
-	spin_unlock(&io_range_lock);
+	address = logic_pio_to_hwaddr(pio);
 #endif
 
 	return address;
@@ -3348,25 +3304,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/asm-generic/io.h b/include/asm-generic/io.h
index 334e5db..3980577 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -925,7 +925,7 @@ static inline void iounmap(void __iomem *addr)
 #define ioport_map ioport_map
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
-	return PCI_IOBASE + (port & IO_SPACE_LIMIT);
+	return PCI_IOBASE + (port & MMIO_UPPER_LIMIT);
 }
 #endif
 
-- 
2.7.4

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

* [PATCH v10 5/9] OF: Add missing I/O range exception for indirect-IO devices
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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 | 91 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 75 insertions(+), 16 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 9d3ba07..323ee56 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -551,9 +551,14 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
  * that translation is impossible (that is we are not dealing with a value
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
+ *
+ * Whenever the translation fails, the *host pointer will be set to the
+ * device that had registered logical PIO mapping, and the return code is
+ * relative to that node.
  */
 static u64 __of_translate_address(struct device_node *dev,
-				  const __be32 *in_addr, const char *rprop)
+				  const __be32 *in_addr, const char *rprop,
+				  struct device_node **host)
 {
 	struct device_node *parent = NULL;
 	struct of_bus *bus, *pbus;
@@ -566,6 +571,7 @@ static u64 __of_translate_address(struct device_node *dev,
 	/* Increase refcount at current level */
 	of_node_get(dev);
 
+	*host = NULL;
 	/* Get parent & match bus type */
 	parent = of_get_parent(dev);
 	if (parent == NULL)
@@ -586,6 +592,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -598,6 +606,19 @@ static u64 __of_translate_address(struct device_node *dev,
 			break;
 		}
 
+		/*
+		 * For indirectIO device which has no ranges property, get
+		 * the address from reg directly.
+		 */
+		iorange = find_io_range_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);
@@ -630,13 +651,32 @@ static u64 __of_translate_address(struct device_node *dev,
 
 u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "ranges", &host);
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_address);
 
 u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "dma-ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "dma-ranges", &host);
+
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_dma_address);
 
@@ -678,29 +718,48 @@ 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 size)
+{
+	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, size);
+		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, size);
+	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;
 
-- 
2.7.4

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

* [PATCH v10 5/9] OF: Add missing I/O range exception for indirect-IO devices
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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 | 91 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 75 insertions(+), 16 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 9d3ba07..323ee56 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -551,9 +551,14 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
  * that translation is impossible (that is we are not dealing with a value
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
+ *
+ * Whenever the translation fails, the *host pointer will be set to the
+ * device that had registered logical PIO mapping, and the return code is
+ * relative to that node.
  */
 static u64 __of_translate_address(struct device_node *dev,
-				  const __be32 *in_addr, const char *rprop)
+				  const __be32 *in_addr, const char *rprop,
+				  struct device_node **host)
 {
 	struct device_node *parent = NULL;
 	struct of_bus *bus, *pbus;
@@ -566,6 +571,7 @@ static u64 __of_translate_address(struct device_node *dev,
 	/* Increase refcount at current level */
 	of_node_get(dev);
 
+	*host = NULL;
 	/* Get parent & match bus type */
 	parent = of_get_parent(dev);
 	if (parent == NULL)
@@ -586,6 +592,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -598,6 +606,19 @@ static u64 __of_translate_address(struct device_node *dev,
 			break;
 		}
 
+		/*
+		 * For indirectIO device which has no ranges property, get
+		 * the address from reg directly.
+		 */
+		iorange = find_io_range_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);
@@ -630,13 +651,32 @@ static u64 __of_translate_address(struct device_node *dev,
 
 u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "ranges", &host);
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_address);
 
 u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "dma-ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "dma-ranges", &host);
+
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_dma_address);
 
@@ -678,29 +718,48 @@ 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 size)
+{
+	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, size);
+		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, size);
+	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;
 
-- 
2.7.4

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

* [PATCH v10 5/9] OF: Add missing I/O range exception for indirect-IO devices
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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 | 91 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 75 insertions(+), 16 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 9d3ba07..323ee56 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -551,9 +551,14 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
  * that translation is impossible (that is we are not dealing with a value
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
+ *
+ * Whenever the translation fails, the *host pointer will be set to the
+ * device that had registered logical PIO mapping, and the return code is
+ * relative to that node.
  */
 static u64 __of_translate_address(struct device_node *dev,
-				  const __be32 *in_addr, const char *rprop)
+				  const __be32 *in_addr, const char *rprop,
+				  struct device_node **host)
 {
 	struct device_node *parent = NULL;
 	struct of_bus *bus, *pbus;
@@ -566,6 +571,7 @@ static u64 __of_translate_address(struct device_node *dev,
 	/* Increase refcount at current level */
 	of_node_get(dev);
 
+	*host = NULL;
 	/* Get parent & match bus type */
 	parent = of_get_parent(dev);
 	if (parent == NULL)
@@ -586,6 +592,8 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	/* Translate */
 	for (;;) {
+		struct logic_pio_hwaddr *iorange;
+
 		/* Switch to parent bus */
 		of_node_put(dev);
 		dev = parent;
@@ -598,6 +606,19 @@ static u64 __of_translate_address(struct device_node *dev,
 			break;
 		}
 
+		/*
+		 * For indirectIO device which has no ranges property, get
+		 * the address from reg directly.
+		 */
+		iorange = find_io_range_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);
@@ -630,13 +651,32 @@ static u64 __of_translate_address(struct device_node *dev,
 
 u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "ranges", &host);
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_address);
 
 u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 {
-	return __of_translate_address(dev, in_addr, "dma-ranges");
+	struct device_node *host;
+	u64 ret;
+
+	ret = __of_translate_address(dev, in_addr, "dma-ranges", &host);
+
+	if (host) {
+		of_node_put(host);
+		return OF_BAD_ADDR;
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(of_translate_dma_address);
 
@@ -678,29 +718,48 @@ 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 size)
+{
+	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, size);
+		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, size);
+	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;
 
-- 
2.7.4

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

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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: Zou Rongrong <zourongrong@huawei.com>
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 ++
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 526 +++++++++++++++++++++
 4 files changed, 569 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/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 2408ea3..358eed3 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..c885483
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,526 @@
+/*
+ * 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/slab.h>
+
+#define LPC_MIN_BUS_RANGE	0x0
+
+/*
+ * The default maximal IO size for Hip06/Hip07 LPC bus.
+ * Defining the I/O range size as 0x4000 here should be sufficient for
+ * all peripherals under the bus.
+ */
+#define LPC_BUS_IO_SIZE		0x4000
+
+/*
+ * 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->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;
+	unsigned char rd_data = 0;
+	unsigned long ptaddr;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		return -1;
+
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, &rd_data, dlen);
+	if (ret)
+		return -1;
+
+	return le32_to_cpu((u32)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.
+ *
+ * when succeed, the data read back is stored in buffer pointed by inbuf.
+ * Returns 0 on success, -errno otherwise
+ *
+ */
+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 = inbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		int ret;
+
+		loopcnt = min_t(unsigned int, 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 = outbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		loopcnt = min_t(unsigned int, 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;
+	struct logic_pio_hwaddr *range;
+	int ret = 0;
+
+	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 */
+	range = devm_kzalloc(dev, 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret) {
+		kfree(range);
+		dev_err(dev, "OF: register IO range FAIL!\n");
+		return -ret;
+	}
+	lpcdev->io_host = range;
+	lpcdev->io_host->devpara = lpcdev;
+	lpcdev->io_host->ops = &hisi_lpc_ops;
+
+	/*
+	 * 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.
+	 */
+	dev_info(dev, " calling of_platform_populate");
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret) {
+		/*
+		 * When LPC probing is not completely successful, set 'devpara'
+		 * as NULL. This will make all the LPC I/O return failure
+		 * directly without any hardware operations. It will prevent
+		 * some peripherals which had not finished the initialization to
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
+			ret);
+		return ret;
+	}
+
+	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+		&lpcdev->io_host->io_start,
+		&lpcdev->io_host->size);
+
+	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);
-- 
2.7.4



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

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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: Zou Rongrong <zourongrong@huawei.com>
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 ++
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 526 +++++++++++++++++++++
 4 files changed, 569 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/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 2408ea3..358eed3 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..c885483
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,526 @@
+/*
+ * 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/slab.h>
+
+#define LPC_MIN_BUS_RANGE	0x0
+
+/*
+ * The default maximal IO size for Hip06/Hip07 LPC bus.
+ * Defining the I/O range size as 0x4000 here should be sufficient for
+ * all peripherals under the bus.
+ */
+#define LPC_BUS_IO_SIZE		0x4000
+
+/*
+ * 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->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;
+	unsigned char rd_data = 0;
+	unsigned long ptaddr;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		return -1;
+
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, &rd_data, dlen);
+	if (ret)
+		return -1;
+
+	return le32_to_cpu((u32)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.
+ *
+ * when succeed, the data read back is stored in buffer pointed by inbuf.
+ * Returns 0 on success, -errno otherwise
+ *
+ */
+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 = inbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		int ret;
+
+		loopcnt = min_t(unsigned int, 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 = outbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		loopcnt = min_t(unsigned int, 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;
+	struct logic_pio_hwaddr *range;
+	int ret = 0;
+
+	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 */
+	range = devm_kzalloc(dev, 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret) {
+		kfree(range);
+		dev_err(dev, "OF: register IO range FAIL!\n");
+		return -ret;
+	}
+	lpcdev->io_host = range;
+	lpcdev->io_host->devpara = lpcdev;
+	lpcdev->io_host->ops = &hisi_lpc_ops;
+
+	/*
+	 * 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.
+	 */
+	dev_info(dev, " calling of_platform_populate");
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret) {
+		/*
+		 * When LPC probing is not completely successful, set 'devpara'
+		 * as NULL. This will make all the LPC I/O return failure
+		 * directly without any hardware operations. It will prevent
+		 * some peripherals which had not finished the initialization to
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
+			ret);
+		return ret;
+	}
+
+	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+		&lpcdev->io_host->io_start,
+		&lpcdev->io_host->size);
+
+	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);
-- 
2.7.4

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

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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: Zou Rongrong <zourongrong@huawei.com>
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 ++
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/hisi_lpc.c                             | 526 +++++++++++++++++++++
 4 files changed, 569 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/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 2408ea3..358eed3 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..c885483
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,526 @@
+/*
+ * 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/slab.h>
+
+#define LPC_MIN_BUS_RANGE	0x0
+
+/*
+ * The default maximal IO size for Hip06/Hip07 LPC bus.
+ * Defining the I/O range size as 0x4000 here should be sufficient for
+ * all peripherals under the bus.
+ */
+#define LPC_BUS_IO_SIZE		0x4000
+
+/*
+ * 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->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;
+	unsigned char rd_data = 0;
+	unsigned long ptaddr;
+	struct lpc_cycle_para iopara;
+	struct hisilpc_dev *lpcdev = devobj;
+
+	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
+		return -1;
+
+	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	iopara.csize = dlen;
+
+	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, &rd_data, dlen);
+	if (ret)
+		return -1;
+
+	return le32_to_cpu((u32)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.
+ *
+ * when succeed, the data read back is stored in buffer pointed by inbuf.
+ * Returns 0 on success, -errno otherwise
+ *
+ */
+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 = inbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		int ret;
+
+		loopcnt = min_t(unsigned int, 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 = outbuf;
+	/*
+	 * ensure data stream whose length is multiple of dlen to be processed
+	 * each IO input
+	 */
+	cntleft = count * dlen;
+	do {
+		loopcnt = min_t(unsigned int, 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;
+	struct logic_pio_hwaddr *range;
+	int ret = 0;
+
+	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 */
+	range = devm_kzalloc(dev, 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret) {
+		kfree(range);
+		dev_err(dev, "OF: register IO range FAIL!\n");
+		return -ret;
+	}
+	lpcdev->io_host = range;
+	lpcdev->io_host->devpara = lpcdev;
+	lpcdev->io_host->ops = &hisi_lpc_ops;
+
+	/*
+	 * 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.
+	 */
+	dev_info(dev, " calling of_platform_populate");
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret) {
+		/*
+		 * When LPC probing is not completely successful, set 'devpara'
+		 * as NULL. This will make all the LPC I/O return failure
+		 * directly without any hardware operations. It will prevent
+		 * some peripherals which had not finished the initialization to
+		 * manipulate I/O for safety.
+		 */
+		lpcdev->io_host->devpara = NULL;
+		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
+			ret);
+		return ret;
+	}
+
+	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
+		&lpcdev->io_host->io_start,
+		&lpcdev->io_host->size);
+
+	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);
-- 
2.7.4

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

* [PATCH v10 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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. As their I/O space
are not memory mapped like PCI/PCIE MMIO host bridges, this patch is meant
to support a new class of I/O host controllers where the local IO ports of
the children devices are translated into the Indirect I/O address space.

Through the handler attach callback, all the I/O translations are done
before starting the enumeration on children devices and the translated
addresses are replaced in the children resources.

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

diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 1017def..6a33ac6 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ACPI_IORT) 	+= iort.o
 obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o
+obj-$(CONFIG_INDIRECT_PIO)     += acpi_indirectio.o
diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
new file mode 100644
index 0000000..013db6f
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -0,0 +1,156 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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 "acpi_indirectio.h"
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
+
+static int acpi_translate_logiciores(struct acpi_device *adev,
+		struct acpi_device *host, struct resource *resource)
+{
+	unsigned long sys_port;
+	struct device *dev = &adev->dev;
+	resource_size_t length = resource->end - resource->start;
+
+	sys_port = logic_pio_trans_hwaddr(&host->fwnode, resource->start,
+					length);
+
+	if (sys_port == -1) {
+		dev_err(dev, "translate bus-addr(0x%llx) fail!\n",
+			resource->start);
+		return -EFAULT;
+	}
+
+	resource->start = sys_port;
+	resource->end = sys_port + length;
+
+	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.
+ *
+ * @child: the device node to be updated the I/O resource;
+ * @hostdev: the device node where 'adev' is attached, which can be not
+ *  the parent of 'adev';
+ * @res: double pointer to be set to the address of the updated resources
+ * @num_res: address of the variable to contain the number of updated resources
+ *
+ * return 0 when successful, negative is for failure.
+ */
+int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev, const struct resource **res,
+		int *num_res)
+{
+	struct acpi_device *adev;
+	struct acpi_device *host;
+	struct resource_entry *rentry;
+	LIST_HEAD(resource_list);
+	struct resource *resources = NULL;
+	int count;
+	int i;
+	int ret = -EIO;
+
+	if (!child || !hostdev)
+		return -EINVAL;
+
+	host = to_acpi_device(hostdev);
+	adev = to_acpi_device(child);
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(child, "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;
+	}
+
+	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+	if (count <= 0) {
+		dev_err(&adev->dev, "failed to get ACPI resources\n");
+		return count ? count : -EIO;
+	}
+
+	resources = kcalloc(count, sizeof(struct resource), GFP_KERNEL);
+	if (!resources) {
+		dev_err(&adev->dev, "No memory for resources\n");
+		acpi_dev_free_resource_list(&resource_list);
+		return -ENOMEM;
+	}
+	count = 0;
+	list_for_each_entry(rentry, &resource_list, node)
+		resources[count++] = *rentry->res;
+
+	acpi_dev_free_resource_list(&resource_list);
+
+	/* translate the I/O resources */
+	for (i = 0; i < count; i++) {
+		if (resources[i].flags & IORESOURCE_IO) {
+			ret = acpi_translate_logiciores(adev, host,
+							&resources[i]);
+			if (ret) {
+				kfree(resources);
+				dev_err(child, "Translate I/O range FAIL!\n");
+				return ret;
+			}
+		}
+	}
+	*res = resources;
+	*num_res = count;
+
+	return ret;
+}
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_host_id[] = {
+	{""},
+};
+
+static int acpi_indirectio_attach(struct acpi_device *adev,
+				const struct acpi_device_id *id)
+{
+	struct indirectio_device_desc *hostdata;
+	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 < 0)
+		return ret;
+
+	return 1;
+}
+
+
+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/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
new file mode 100644
index 0000000..8102ea0
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -0,0 +1,24 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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.
+ */
+
+#ifndef _ACPI_INDIRECTIO_H
+#define _ACPI_INDIRECTIO_H
+
+struct indirectio_device_desc {
+	void *pdata; /* device relevant info data */
+	int (*pre_setup)(struct acpi_device *adev, void *pdata);
+};
+
+int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev, const struct resource **res,
+		int *num_res);
+#endif
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 9531d32..36da45c 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@ void acpi_processor_init(void);
 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 3389729..14d6126 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2041,6 +2041,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);
 
-- 
2.7.4



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

* [PATCH v10 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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. As their I/O space
are not memory mapped like PCI/PCIE MMIO host bridges, this patch is meant
to support a new class of I/O host controllers where the local IO ports of
the children devices are translated into the Indirect I/O address space.

Through the handler attach callback, all the I/O translations are done
before starting the enumeration on children devices and the translated
addresses are replaced in the children resources.

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

diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 1017def..6a33ac6 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ACPI_IORT) 	+= iort.o
 obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o
+obj-$(CONFIG_INDIRECT_PIO)     += acpi_indirectio.o
diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
new file mode 100644
index 0000000..013db6f
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -0,0 +1,156 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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 "acpi_indirectio.h"
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
+
+static int acpi_translate_logiciores(struct acpi_device *adev,
+		struct acpi_device *host, struct resource *resource)
+{
+	unsigned long sys_port;
+	struct device *dev = &adev->dev;
+	resource_size_t length = resource->end - resource->start;
+
+	sys_port = logic_pio_trans_hwaddr(&host->fwnode, resource->start,
+					length);
+
+	if (sys_port == -1) {
+		dev_err(dev, "translate bus-addr(0x%llx) fail!\n",
+			resource->start);
+		return -EFAULT;
+	}
+
+	resource->start = sys_port;
+	resource->end = sys_port + length;
+
+	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.
+ *
+ * @child: the device node to be updated the I/O resource;
+ * @hostdev: the device node where 'adev' is attached, which can be not
+ *  the parent of 'adev';
+ * @res: double pointer to be set to the address of the updated resources
+ * @num_res: address of the variable to contain the number of updated resources
+ *
+ * return 0 when successful, negative is for failure.
+ */
+int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev, const struct resource **res,
+		int *num_res)
+{
+	struct acpi_device *adev;
+	struct acpi_device *host;
+	struct resource_entry *rentry;
+	LIST_HEAD(resource_list);
+	struct resource *resources = NULL;
+	int count;
+	int i;
+	int ret = -EIO;
+
+	if (!child || !hostdev)
+		return -EINVAL;
+
+	host = to_acpi_device(hostdev);
+	adev = to_acpi_device(child);
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(child, "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;
+	}
+
+	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+	if (count <= 0) {
+		dev_err(&adev->dev, "failed to get ACPI resources\n");
+		return count ? count : -EIO;
+	}
+
+	resources = kcalloc(count, sizeof(struct resource), GFP_KERNEL);
+	if (!resources) {
+		dev_err(&adev->dev, "No memory for resources\n");
+		acpi_dev_free_resource_list(&resource_list);
+		return -ENOMEM;
+	}
+	count = 0;
+	list_for_each_entry(rentry, &resource_list, node)
+		resources[count++] = *rentry->res;
+
+	acpi_dev_free_resource_list(&resource_list);
+
+	/* translate the I/O resources */
+	for (i = 0; i < count; i++) {
+		if (resources[i].flags & IORESOURCE_IO) {
+			ret = acpi_translate_logiciores(adev, host,
+							&resources[i]);
+			if (ret) {
+				kfree(resources);
+				dev_err(child, "Translate I/O range FAIL!\n");
+				return ret;
+			}
+		}
+	}
+	*res = resources;
+	*num_res = count;
+
+	return ret;
+}
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_host_id[] = {
+	{""},
+};
+
+static int acpi_indirectio_attach(struct acpi_device *adev,
+				const struct acpi_device_id *id)
+{
+	struct indirectio_device_desc *hostdata;
+	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 < 0)
+		return ret;
+
+	return 1;
+}
+
+
+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/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
new file mode 100644
index 0000000..8102ea0
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -0,0 +1,24 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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.
+ */
+
+#ifndef _ACPI_INDIRECTIO_H
+#define _ACPI_INDIRECTIO_H
+
+struct indirectio_device_desc {
+	void *pdata; /* device relevant info data */
+	int (*pre_setup)(struct acpi_device *adev, void *pdata);
+};
+
+int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev, const struct resource **res,
+		int *num_res);
+#endif
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 9531d32..36da45c 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@ void acpi_processor_init(void);
 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 3389729..14d6126 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2041,6 +2041,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);
 
-- 
2.7.4

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

* [PATCH v10 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: gabriele paoloni <gabriele.paoloni@huawei.com>

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. As their I/O space
are not memory mapped like PCI/PCIE MMIO host bridges, this patch is meant
to support a new class of I/O host controllers where the local IO ports of
the children devices are translated into the Indirect I/O address space.

Through the handler attach callback, all the I/O translations are done
before starting the enumeration on children devices and the translated
addresses are replaced in the children resources.

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

diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 1017def..6a33ac6 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ACPI_IORT) 	+= iort.o
 obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o
+obj-$(CONFIG_INDIRECT_PIO)     += acpi_indirectio.o
diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
new file mode 100644
index 0000000..013db6f
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -0,0 +1,156 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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 "acpi_indirectio.h"
+
+ACPI_MODULE_NAME("indirect IO");
+
+#define INDIRECT_IO_INFO(desc) ((unsigned long)&desc)
+
+static int acpi_translate_logiciores(struct acpi_device *adev,
+		struct acpi_device *host, struct resource *resource)
+{
+	unsigned long sys_port;
+	struct device *dev = &adev->dev;
+	resource_size_t length = resource->end - resource->start;
+
+	sys_port = logic_pio_trans_hwaddr(&host->fwnode, resource->start,
+					length);
+
+	if (sys_port == -1) {
+		dev_err(dev, "translate bus-addr(0x%llx) fail!\n",
+			resource->start);
+		return -EFAULT;
+	}
+
+	resource->start = sys_port;
+	resource->end = sys_port + length;
+
+	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.
+ *
+ * @child: the device node to be updated the I/O resource;
+ * @hostdev: the device node where 'adev' is attached, which can be not
+ *  the parent of 'adev';
+ * @res: double pointer to be set to the address of the updated resources
+ * @num_res: address of the variable to contain the number of updated resources
+ *
+ * return 0 when successful, negative is for failure.
+ */
+int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev, const struct resource **res,
+		int *num_res)
+{
+	struct acpi_device *adev;
+	struct acpi_device *host;
+	struct resource_entry *rentry;
+	LIST_HEAD(resource_list);
+	struct resource *resources = NULL;
+	int count;
+	int i;
+	int ret = -EIO;
+
+	if (!child || !hostdev)
+		return -EINVAL;
+
+	host = to_acpi_device(hostdev);
+	adev = to_acpi_device(child);
+
+	/* check the device state */
+	if (!adev->status.present) {
+		dev_info(child, "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;
+	}
+
+	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+	if (count <= 0) {
+		dev_err(&adev->dev, "failed to get ACPI resources\n");
+		return count ? count : -EIO;
+	}
+
+	resources = kcalloc(count, sizeof(struct resource), GFP_KERNEL);
+	if (!resources) {
+		dev_err(&adev->dev, "No memory for resources\n");
+		acpi_dev_free_resource_list(&resource_list);
+		return -ENOMEM;
+	}
+	count = 0;
+	list_for_each_entry(rentry, &resource_list, node)
+		resources[count++] = *rentry->res;
+
+	acpi_dev_free_resource_list(&resource_list);
+
+	/* translate the I/O resources */
+	for (i = 0; i < count; i++) {
+		if (resources[i].flags & IORESOURCE_IO) {
+			ret = acpi_translate_logiciores(adev, host,
+							&resources[i]);
+			if (ret) {
+				kfree(resources);
+				dev_err(child, "Translate I/O range FAIL!\n");
+				return ret;
+			}
+		}
+	}
+	*res = resources;
+	*num_res = count;
+
+	return ret;
+}
+
+/* All the host devices which apply indirect-IO can be listed here. */
+static const struct acpi_device_id acpi_indirect_host_id[] = {
+	{""},
+};
+
+static int acpi_indirectio_attach(struct acpi_device *adev,
+				const struct acpi_device_id *id)
+{
+	struct indirectio_device_desc *hostdata;
+	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 < 0)
+		return ret;
+
+	return 1;
+}
+
+
+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/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
new file mode 100644
index 0000000..8102ea0
--- /dev/null
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -0,0 +1,24 @@
+/*
+ * ACPI support for indirect-IO bus.
+ *
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
+ * 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.
+ */
+
+#ifndef _ACPI_INDIRECTIO_H
+#define _ACPI_INDIRECTIO_H
+
+struct indirectio_device_desc {
+	void *pdata; /* device relevant info data */
+	int (*pre_setup)(struct acpi_device *adev, void *pdata);
+};
+
+int acpi_set_logicio_resource(struct device *child,
+		struct device *hostdev, const struct resource **res,
+		int *num_res);
+#endif
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 9531d32..36da45c 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,11 @@ void acpi_processor_init(void);
 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 3389729..14d6126 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2041,6 +2041,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);
 
-- 
2.7.4

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

* [PATCH v10 8/9] LPC: Add the ACPI LPC support
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Tested-by: dann frazier <dann.frazier@canonical.com>
---
 drivers/acpi/arm64/acpi_indirectio.c |   3 +
 drivers/acpi/arm64/acpi_indirectio.h |   4 +
 drivers/bus/hisi_lpc.c               | 164 +++++++++++++++++++++++++++++++----
 3 files changed, 154 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
index 013db6f..424f3bd 100644
--- a/drivers/acpi/arm64/acpi_indirectio.c
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -123,6 +123,9 @@ int acpi_set_logicio_resource(struct device *child,
 
 /* All the host devices which apply indirect-IO can be listed here. */
 static const struct acpi_device_id acpi_indirect_host_id[] = {
+#ifdef CONFIG_HISILICON_LPC
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+#endif
 	{""},
 };
 
diff --git a/drivers/acpi/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
index 8102ea0..1b18590 100644
--- a/drivers/acpi/arm64/acpi_indirectio.h
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -18,6 +18,10 @@ struct indirectio_device_desc {
 	int (*pre_setup)(struct acpi_device *adev, void *pdata);
 };
 
+#ifdef CONFIG_HISILICON_LPC
+extern const struct indirectio_device_desc lpc_host_desc;
+#endif
+
 int acpi_set_logicio_resource(struct device *child,
 		struct device *hostdev, const struct resource **res,
 		int *num_res);
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index c885483..26043f7 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -438,7 +438,6 @@ static int hisilpc_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct hisilpc_dev *lpcdev;
-	struct logic_pio_hwaddr *range;
 	int ret = 0;
 
 	lpcdev = devm_kzalloc(dev, sizeof(struct hisilpc_dev), GFP_KERNEL);
@@ -460,21 +459,32 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	range = devm_kzalloc(dev, 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;
-
-	ret = logic_pio_register_range(range);
-	if (ret) {
-		kfree(range);
-		dev_err(dev, "OF: register IO range FAIL!\n");
-		return -ret;
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+		if (!lpcdev->io_host) {
+			dev_err(dev, "HiSilicon LPC range not registered!\n");
+			return -EFAULT;
+		}
+	} else {
+		struct logic_pio_hwaddr *range;
+
+		range = devm_kzalloc(dev, 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;
+
+		ret = logic_pio_register_range(range);
+		if (ret) {
+			kfree(range);
+			dev_err(dev, "OF: register IO range FAIL!\n");
+			return -ret;
+		}
+		lpcdev->io_host = range;
 	}
-	lpcdev->io_host = range;
+
 	lpcdev->io_host->devpara = lpcdev;
 	lpcdev->io_host->ops = &hisi_lpc_ops;
 
@@ -486,8 +496,11 @@ static int hisilpc_probe(struct platform_device *pdev)
 	 * to avoid some children which complete the scanning trigger the
 	 * MMIO accesses which will probably cause panic.
 	 */
-	dev_info(dev, " calling of_platform_populate");
-	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (!has_acpi_companion(dev)) {
+		dev_info(dev, " calling of_platform_populate");
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	}
+
 	if (ret) {
 		/*
 		 * When LPC probing is not completely successful, set 'devpara'
@@ -515,10 +528,127 @@ static const struct of_device_id hisilpc_of_match[] = {
 	{},
 };
 
+#ifdef CONFIG_ACPI
+#include "../acpi/arm64/acpi_indirectio.h"
+#include <linux/mfd/core.h>
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static struct mfd_cell_acpi_match hisi_lpc_ipmi_acpi_match = {
+	.pnpid = "IPI0001",
+};
+
+static const char *hisi_lpc_ipmi_name = "hisi_lpc_ipmi";
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	int ret;
+	struct platform_device *pdev;
+	struct mfd_cell *ipmi_devs;
+	struct logic_pio_hwaddr *range;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+	int ipmi_dev_num = 0;
+
+	lpc_private = 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret)
+		goto free_range;
+
+	/* count the ipmi children first */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child)))
+			ipmi_dev_num++;
+	}
+
+	/* allocate the mfd cells */
+	ipmi_devs = kcalloc(ipmi_dev_num, sizeof(*ipmi_devs), GFP_KERNEL);
+	if (!ipmi_devs) {
+		dev_err(&adev->dev, "ipmi_devs kzalloc failed!\n");
+		ret = -ENOMEM;
+		goto free_range;
+	}
+
+	ipmi_dev_num = 0;
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child))) {
+			ipmi_devs[ipmi_dev_num].name = hisi_lpc_ipmi_name;
+			ipmi_devs[ipmi_dev_num].acpi_match =
+					&hisi_lpc_ipmi_acpi_match;
+			ret = acpi_set_logicio_resource(&child->dev, &adev->dev,
+					&ipmi_devs[ipmi_dev_num].resources,
+					&ipmi_devs[ipmi_dev_num].num_resources);
+			if (ret) {
+				dev_err(&child->dev, "set resource failed..\n");
+				goto free_ipmi_devs;
+			}
+			ipmi_dev_num++;
+		}
+	}
+
+	pdev = acpi_create_platform_device(adev, NULL);
+	if (IS_ERR_OR_NULL(pdev)) {
+		dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+		ret = -EFAULT;
+		goto free_ipmi_devs;
+	}
+	acpi_device_set_enumerated(adev);
+
+	ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+			ipmi_devs, ipmi_dev_num, NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add ipmi mfd cell\n");
+		goto free_ipmi_devs;
+	}
+
+	return ret;
+
+free_ipmi_devs:
+	while (ipmi_dev_num--)
+		kfree(ipmi_devs[ipmi_dev_num].resources);
+	kfree(ipmi_devs);
+free_range:
+	kfree(range);
+
+	return ret;
+}
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+	{"HISI0191", },
+	{},
+};
+
+const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+#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,
 };
-- 
2.7.4

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

* [PATCH v10 8/9] LPC: Add the ACPI LPC support
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5, zhichang.yuan

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Tested-by: dann frazier <dann.frazier@canonical.com>
---
 drivers/acpi/arm64/acpi_indirectio.c |   3 +
 drivers/acpi/arm64/acpi_indirectio.h |   4 +
 drivers/bus/hisi_lpc.c               | 164 +++++++++++++++++++++++++++++++----
 3 files changed, 154 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
index 013db6f..424f3bd 100644
--- a/drivers/acpi/arm64/acpi_indirectio.c
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -123,6 +123,9 @@ int acpi_set_logicio_resource(struct device *child,
 
 /* All the host devices which apply indirect-IO can be listed here. */
 static const struct acpi_device_id acpi_indirect_host_id[] = {
+#ifdef CONFIG_HISILICON_LPC
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+#endif
 	{""},
 };
 
diff --git a/drivers/acpi/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
index 8102ea0..1b18590 100644
--- a/drivers/acpi/arm64/acpi_indirectio.h
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -18,6 +18,10 @@ struct indirectio_device_desc {
 	int (*pre_setup)(struct acpi_device *adev, void *pdata);
 };
 
+#ifdef CONFIG_HISILICON_LPC
+extern const struct indirectio_device_desc lpc_host_desc;
+#endif
+
 int acpi_set_logicio_resource(struct device *child,
 		struct device *hostdev, const struct resource **res,
 		int *num_res);
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index c885483..26043f7 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -438,7 +438,6 @@ static int hisilpc_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct hisilpc_dev *lpcdev;
-	struct logic_pio_hwaddr *range;
 	int ret = 0;
 
 	lpcdev = devm_kzalloc(dev, sizeof(struct hisilpc_dev), GFP_KERNEL);
@@ -460,21 +459,32 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	range = devm_kzalloc(dev, 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;
-
-	ret = logic_pio_register_range(range);
-	if (ret) {
-		kfree(range);
-		dev_err(dev, "OF: register IO range FAIL!\n");
-		return -ret;
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+		if (!lpcdev->io_host) {
+			dev_err(dev, "HiSilicon LPC range not registered!\n");
+			return -EFAULT;
+		}
+	} else {
+		struct logic_pio_hwaddr *range;
+
+		range = devm_kzalloc(dev, 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;
+
+		ret = logic_pio_register_range(range);
+		if (ret) {
+			kfree(range);
+			dev_err(dev, "OF: register IO range FAIL!\n");
+			return -ret;
+		}
+		lpcdev->io_host = range;
 	}
-	lpcdev->io_host = range;
+
 	lpcdev->io_host->devpara = lpcdev;
 	lpcdev->io_host->ops = &hisi_lpc_ops;
 
@@ -486,8 +496,11 @@ static int hisilpc_probe(struct platform_device *pdev)
 	 * to avoid some children which complete the scanning trigger the
 	 * MMIO accesses which will probably cause panic.
 	 */
-	dev_info(dev, " calling of_platform_populate");
-	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (!has_acpi_companion(dev)) {
+		dev_info(dev, " calling of_platform_populate");
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	}
+
 	if (ret) {
 		/*
 		 * When LPC probing is not completely successful, set 'devpara'
@@ -515,10 +528,127 @@ static const struct of_device_id hisilpc_of_match[] = {
 	{},
 };
 
+#ifdef CONFIG_ACPI
+#include "../acpi/arm64/acpi_indirectio.h"
+#include <linux/mfd/core.h>
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static struct mfd_cell_acpi_match hisi_lpc_ipmi_acpi_match = {
+	.pnpid = "IPI0001",
+};
+
+static const char *hisi_lpc_ipmi_name = "hisi_lpc_ipmi";
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	int ret;
+	struct platform_device *pdev;
+	struct mfd_cell *ipmi_devs;
+	struct logic_pio_hwaddr *range;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+	int ipmi_dev_num = 0;
+
+	lpc_private = 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret)
+		goto free_range;
+
+	/* count the ipmi children first */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child)))
+			ipmi_dev_num++;
+	}
+
+	/* allocate the mfd cells */
+	ipmi_devs = kcalloc(ipmi_dev_num, sizeof(*ipmi_devs), GFP_KERNEL);
+	if (!ipmi_devs) {
+		dev_err(&adev->dev, "ipmi_devs kzalloc failed!\n");
+		ret = -ENOMEM;
+		goto free_range;
+	}
+
+	ipmi_dev_num = 0;
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child))) {
+			ipmi_devs[ipmi_dev_num].name = hisi_lpc_ipmi_name;
+			ipmi_devs[ipmi_dev_num].acpi_match =
+					&hisi_lpc_ipmi_acpi_match;
+			ret = acpi_set_logicio_resource(&child->dev, &adev->dev,
+					&ipmi_devs[ipmi_dev_num].resources,
+					&ipmi_devs[ipmi_dev_num].num_resources);
+			if (ret) {
+				dev_err(&child->dev, "set resource failed..\n");
+				goto free_ipmi_devs;
+			}
+			ipmi_dev_num++;
+		}
+	}
+
+	pdev = acpi_create_platform_device(adev, NULL);
+	if (IS_ERR_OR_NULL(pdev)) {
+		dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+		ret = -EFAULT;
+		goto free_ipmi_devs;
+	}
+	acpi_device_set_enumerated(adev);
+
+	ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+			ipmi_devs, ipmi_dev_num, NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add ipmi mfd cell\n");
+		goto free_ipmi_devs;
+	}
+
+	return ret;
+
+free_ipmi_devs:
+	while (ipmi_dev_num--)
+		kfree(ipmi_devs[ipmi_dev_num].resources);
+	kfree(ipmi_devs);
+free_range:
+	kfree(range);
+
+	return ret;
+}
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+	{"HISI0191", },
+	{},
+};
+
+const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+#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,
 };
-- 
2.7.4

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

* [PATCH v10 8/9] LPC: Add the ACPI LPC support
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, minyard, gabriele.paoloni, benh, john.garry,
	linux-kernel, xuwei5, linuxarm, linux-acpi, zhichang.yuan,
	linux-pci, olof, brian.starkey

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Tested-by: dann frazier <dann.frazier@canonical.com>
---
 drivers/acpi/arm64/acpi_indirectio.c |   3 +
 drivers/acpi/arm64/acpi_indirectio.h |   4 +
 drivers/bus/hisi_lpc.c               | 164 +++++++++++++++++++++++++++++++----
 3 files changed, 154 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
index 013db6f..424f3bd 100644
--- a/drivers/acpi/arm64/acpi_indirectio.c
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -123,6 +123,9 @@ int acpi_set_logicio_resource(struct device *child,
 
 /* All the host devices which apply indirect-IO can be listed here. */
 static const struct acpi_device_id acpi_indirect_host_id[] = {
+#ifdef CONFIG_HISILICON_LPC
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+#endif
 	{""},
 };
 
diff --git a/drivers/acpi/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
index 8102ea0..1b18590 100644
--- a/drivers/acpi/arm64/acpi_indirectio.h
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -18,6 +18,10 @@ struct indirectio_device_desc {
 	int (*pre_setup)(struct acpi_device *adev, void *pdata);
 };
 
+#ifdef CONFIG_HISILICON_LPC
+extern const struct indirectio_device_desc lpc_host_desc;
+#endif
+
 int acpi_set_logicio_resource(struct device *child,
 		struct device *hostdev, const struct resource **res,
 		int *num_res);
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index c885483..26043f7 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -438,7 +438,6 @@ static int hisilpc_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct hisilpc_dev *lpcdev;
-	struct logic_pio_hwaddr *range;
 	int ret = 0;
 
 	lpcdev = devm_kzalloc(dev, sizeof(struct hisilpc_dev), GFP_KERNEL);
@@ -460,21 +459,32 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	range = devm_kzalloc(dev, 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;
-
-	ret = logic_pio_register_range(range);
-	if (ret) {
-		kfree(range);
-		dev_err(dev, "OF: register IO range FAIL!\n");
-		return -ret;
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+		if (!lpcdev->io_host) {
+			dev_err(dev, "HiSilicon LPC range not registered!\n");
+			return -EFAULT;
+		}
+	} else {
+		struct logic_pio_hwaddr *range;
+
+		range = devm_kzalloc(dev, 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;
+
+		ret = logic_pio_register_range(range);
+		if (ret) {
+			kfree(range);
+			dev_err(dev, "OF: register IO range FAIL!\n");
+			return -ret;
+		}
+		lpcdev->io_host = range;
 	}
-	lpcdev->io_host = range;
+
 	lpcdev->io_host->devpara = lpcdev;
 	lpcdev->io_host->ops = &hisi_lpc_ops;
 
@@ -486,8 +496,11 @@ static int hisilpc_probe(struct platform_device *pdev)
 	 * to avoid some children which complete the scanning trigger the
 	 * MMIO accesses which will probably cause panic.
 	 */
-	dev_info(dev, " calling of_platform_populate");
-	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (!has_acpi_companion(dev)) {
+		dev_info(dev, " calling of_platform_populate");
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	}
+
 	if (ret) {
 		/*
 		 * When LPC probing is not completely successful, set 'devpara'
@@ -515,10 +528,127 @@ static const struct of_device_id hisilpc_of_match[] = {
 	{},
 };
 
+#ifdef CONFIG_ACPI
+#include "../acpi/arm64/acpi_indirectio.h"
+#include <linux/mfd/core.h>
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static struct mfd_cell_acpi_match hisi_lpc_ipmi_acpi_match = {
+	.pnpid = "IPI0001",
+};
+
+static const char *hisi_lpc_ipmi_name = "hisi_lpc_ipmi";
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	int ret;
+	struct platform_device *pdev;
+	struct mfd_cell *ipmi_devs;
+	struct logic_pio_hwaddr *range;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+	int ipmi_dev_num = 0;
+
+	lpc_private = 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret)
+		goto free_range;
+
+	/* count the ipmi children first */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child)))
+			ipmi_dev_num++;
+	}
+
+	/* allocate the mfd cells */
+	ipmi_devs = kcalloc(ipmi_dev_num, sizeof(*ipmi_devs), GFP_KERNEL);
+	if (!ipmi_devs) {
+		dev_err(&adev->dev, "ipmi_devs kzalloc failed!\n");
+		ret = -ENOMEM;
+		goto free_range;
+	}
+
+	ipmi_dev_num = 0;
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child))) {
+			ipmi_devs[ipmi_dev_num].name = hisi_lpc_ipmi_name;
+			ipmi_devs[ipmi_dev_num].acpi_match =
+					&hisi_lpc_ipmi_acpi_match;
+			ret = acpi_set_logicio_resource(&child->dev, &adev->dev,
+					&ipmi_devs[ipmi_dev_num].resources,
+					&ipmi_devs[ipmi_dev_num].num_resources);
+			if (ret) {
+				dev_err(&child->dev, "set resource failed..\n");
+				goto free_ipmi_devs;
+			}
+			ipmi_dev_num++;
+		}
+	}
+
+	pdev = acpi_create_platform_device(adev, NULL);
+	if (IS_ERR_OR_NULL(pdev)) {
+		dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+		ret = -EFAULT;
+		goto free_ipmi_devs;
+	}
+	acpi_device_set_enumerated(adev);
+
+	ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+			ipmi_devs, ipmi_dev_num, NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add ipmi mfd cell\n");
+		goto free_ipmi_devs;
+	}
+
+	return ret;
+
+free_ipmi_devs:
+	while (ipmi_dev_num--)
+		kfree(ipmi_devs[ipmi_dev_num].resources);
+	kfree(ipmi_devs);
+free_range:
+	kfree(range);
+
+	return ret;
+}
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+	{"HISI0191", },
+	{},
+};
+
+const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+#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,
 };
-- 
2.7.4



_______________________________________________
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] 89+ messages in thread

* [PATCH v10 8/9] LPC: Add the ACPI LPC support
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

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>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Tested-by: dann frazier <dann.frazier@canonical.com>
---
 drivers/acpi/arm64/acpi_indirectio.c |   3 +
 drivers/acpi/arm64/acpi_indirectio.h |   4 +
 drivers/bus/hisi_lpc.c               | 164 +++++++++++++++++++++++++++++++----
 3 files changed, 154 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/arm64/acpi_indirectio.c b/drivers/acpi/arm64/acpi_indirectio.c
index 013db6f..424f3bd 100644
--- a/drivers/acpi/arm64/acpi_indirectio.c
+++ b/drivers/acpi/arm64/acpi_indirectio.c
@@ -123,6 +123,9 @@ int acpi_set_logicio_resource(struct device *child,
 
 /* All the host devices which apply indirect-IO can be listed here. */
 static const struct acpi_device_id acpi_indirect_host_id[] = {
+#ifdef CONFIG_HISILICON_LPC
+	{"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+#endif
 	{""},
 };
 
diff --git a/drivers/acpi/arm64/acpi_indirectio.h b/drivers/acpi/arm64/acpi_indirectio.h
index 8102ea0..1b18590 100644
--- a/drivers/acpi/arm64/acpi_indirectio.h
+++ b/drivers/acpi/arm64/acpi_indirectio.h
@@ -18,6 +18,10 @@ struct indirectio_device_desc {
 	int (*pre_setup)(struct acpi_device *adev, void *pdata);
 };
 
+#ifdef CONFIG_HISILICON_LPC
+extern const struct indirectio_device_desc lpc_host_desc;
+#endif
+
 int acpi_set_logicio_resource(struct device *child,
 		struct device *hostdev, const struct resource **res,
 		int *num_res);
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index c885483..26043f7 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -438,7 +438,6 @@ static int hisilpc_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct hisilpc_dev *lpcdev;
-	struct logic_pio_hwaddr *range;
 	int ret = 0;
 
 	lpcdev = devm_kzalloc(dev, sizeof(struct hisilpc_dev), GFP_KERNEL);
@@ -460,21 +459,32 @@ static int hisilpc_probe(struct platform_device *pdev)
 	}
 
 	/* register the LPC host PIO resources */
-	range = devm_kzalloc(dev, 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;
-
-	ret = logic_pio_register_range(range);
-	if (ret) {
-		kfree(range);
-		dev_err(dev, "OF: register IO range FAIL!\n");
-		return -ret;
+	if (has_acpi_companion(dev)) {
+		lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+		if (!lpcdev->io_host) {
+			dev_err(dev, "HiSilicon LPC range not registered!\n");
+			return -EFAULT;
+		}
+	} else {
+		struct logic_pio_hwaddr *range;
+
+		range = devm_kzalloc(dev, 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;
+
+		ret = logic_pio_register_range(range);
+		if (ret) {
+			kfree(range);
+			dev_err(dev, "OF: register IO range FAIL!\n");
+			return -ret;
+		}
+		lpcdev->io_host = range;
 	}
-	lpcdev->io_host = range;
+
 	lpcdev->io_host->devpara = lpcdev;
 	lpcdev->io_host->ops = &hisi_lpc_ops;
 
@@ -486,8 +496,11 @@ static int hisilpc_probe(struct platform_device *pdev)
 	 * to avoid some children which complete the scanning trigger the
 	 * MMIO accesses which will probably cause panic.
 	 */
-	dev_info(dev, " calling of_platform_populate");
-	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (!has_acpi_companion(dev)) {
+		dev_info(dev, " calling of_platform_populate");
+		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	}
+
 	if (ret) {
 		/*
 		 * When LPC probing is not completely successful, set 'devpara'
@@ -515,10 +528,127 @@ static const struct of_device_id hisilpc_of_match[] = {
 	{},
 };
 
+#ifdef CONFIG_ACPI
+#include "../acpi/arm64/acpi_indirectio.h"
+#include <linux/mfd/core.h>
+
+struct lpc_private_data {
+	resource_size_t io_size;
+	resource_size_t io_start;
+};
+
+static struct lpc_private_data lpc_data = {
+	.io_size = LPC_BUS_IO_SIZE,
+	.io_start = LPC_MIN_BUS_RANGE,
+};
+
+static struct mfd_cell_acpi_match hisi_lpc_ipmi_acpi_match = {
+	.pnpid = "IPI0001",
+};
+
+static const char *hisi_lpc_ipmi_name = "hisi_lpc_ipmi";
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+	int ret;
+	struct platform_device *pdev;
+	struct mfd_cell *ipmi_devs;
+	struct logic_pio_hwaddr *range;
+	struct lpc_private_data *lpc_private;
+	struct acpi_device *child;
+	int ipmi_dev_num = 0;
+
+	lpc_private = 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;
+
+	ret = logic_pio_register_range(range);
+	if (ret)
+		goto free_range;
+
+	/* count the ipmi children first */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child)))
+			ipmi_dev_num++;
+	}
+
+	/* allocate the mfd cells */
+	ipmi_devs = kcalloc(ipmi_dev_num, sizeof(*ipmi_devs), GFP_KERNEL);
+	if (!ipmi_devs) {
+		dev_err(&adev->dev, "ipmi_devs kzalloc failed!\n");
+		ret = -ENOMEM;
+		goto free_range;
+	}
+
+	ipmi_dev_num = 0;
+	/* For hisilpc, only care about the sons of host. */
+	list_for_each_entry(child, &adev->children, node) {
+		if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+			    acpi_device_hid(child))) {
+			ipmi_devs[ipmi_dev_num].name = hisi_lpc_ipmi_name;
+			ipmi_devs[ipmi_dev_num].acpi_match =
+					&hisi_lpc_ipmi_acpi_match;
+			ret = acpi_set_logicio_resource(&child->dev, &adev->dev,
+					&ipmi_devs[ipmi_dev_num].resources,
+					&ipmi_devs[ipmi_dev_num].num_resources);
+			if (ret) {
+				dev_err(&child->dev, "set resource failed..\n");
+				goto free_ipmi_devs;
+			}
+			ipmi_dev_num++;
+		}
+	}
+
+	pdev = acpi_create_platform_device(adev, NULL);
+	if (IS_ERR_OR_NULL(pdev)) {
+		dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+		ret = -EFAULT;
+		goto free_ipmi_devs;
+	}
+	acpi_device_set_enumerated(adev);
+
+	ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+			ipmi_devs, ipmi_dev_num, NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add ipmi mfd cell\n");
+		goto free_ipmi_devs;
+	}
+
+	return ret;
+
+free_ipmi_devs:
+	while (ipmi_dev_num--)
+		kfree(ipmi_devs[ipmi_dev_num].resources);
+	kfree(ipmi_devs);
+free_range:
+	kfree(range);
+
+	return ret;
+}
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+	{"HISI0191", },
+	{},
+};
+
+const struct indirectio_device_desc lpc_host_desc = {
+	.pdata = &lpc_data,
+	.pre_setup = lpc_host_io_setup,
+};
+
+#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,
 };
-- 
2.7.4

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

* [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-10-27 16:11   ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

Added maintainer for drivers/bus/hisi_lpc.c

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f66488d..b49d4c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
 F:	net/802/hippi.c
 F:	drivers/net/hippi/
 
+HISILICON LPC BUS DRIVER
+L:	linuxarm@huawei.com
+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>
-- 
2.7.4

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

* [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: gabriele.paoloni, mark.rutland, brian.starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, minyard,
	john.garry, xuwei5

Added maintainer for drivers/bus/hisi_lpc.c

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f66488d..b49d4c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
 F:	net/802/hippi.c
 F:	drivers/net/hippi/
 
+HISILICON LPC BUS DRIVER
+L:	linuxarm@huawei.com
+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>
-- 
2.7.4

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

* [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-10-27 16:11   ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-27 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

Added maintainer for drivers/bus/hisi_lpc.c

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f66488d..b49d4c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
 F:	net/802/hippi.c
 F:	drivers/net/hippi/
 
+HISILICON LPC BUS DRIVER
+L:	linuxarm at huawei.com
+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>
-- 
2.7.4

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

* Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  2017-10-27 16:11   ` Gabriele Paoloni
  (?)
  (?)
@ 2017-10-27 16:44     ` Randy Dunlap
  -1 siblings, 0 replies; 89+ messages in thread
From: Randy Dunlap @ 2017-10-27 16:44 UTC (permalink / raw)
  To: Gabriele Paoloni, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, minyard, benh, john.garry, linux-kernel, xuwei5,
	linuxarm, linux-acpi, zhichang.yuan, linux-pci, olof,
	brian.starkey

On 10/27/17 09:11, Gabriele Paoloni wrote:
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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

Hi,

Why bool? why not tristate?

-- 
~Randy

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

* Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-27 16:44     ` Randy Dunlap
  0 siblings, 0 replies; 89+ messages in thread
From: Randy Dunlap @ 2017-10-27 16:44 UTC (permalink / raw)
  To: Gabriele Paoloni, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, linux-pci, minyard, john.garry, xuwei5,
	zhichang.yuan

On 10/27/17 09:11, Gabriele Paoloni wrote:
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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

Hi,

Why bool? why not tristate?

-- 
~Randy

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

* Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-27 16:44     ` Randy Dunlap
  0 siblings, 0 replies; 89+ messages in thread
From: Randy Dunlap @ 2017-10-27 16:44 UTC (permalink / raw)
  To: Gabriele Paoloni, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, minyard, benh, john.garry, linux-kernel, xuwei5,
	linuxarm, linux-acpi, zhichang.yuan, linux-pci, olof,
	brian.starkey

On 10/27/17 09:11, Gabriele Paoloni wrote:
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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

Hi,

Why bool? why not tristate?

-- 
~Randy

_______________________________________________
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] 89+ messages in thread

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-27 16:44     ` Randy Dunlap
  0 siblings, 0 replies; 89+ messages in thread
From: Randy Dunlap @ 2017-10-27 16:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/27/17 09:11, Gabriele Paoloni wrote:
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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

Hi,

Why bool? why not tristate?

-- 
~Randy

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
  (?)
@ 2017-10-27 16:45   ` David Laight
  -1 siblings, 0 replies; 89+ messages in thread
From: David Laight @ 2017-10-27 16:45 UTC (permalink / raw)
  To: 'Gabriele Paoloni',
	catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, linux-pci, minyard, john.garry, xuwei5

From: Gabriele Paoloni
> Sent: 27 October 2017 17:11
> 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 accessors are based
> on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
> specific accessors rather than MMIO.
> To solve this issue and keep the relevant existing peripherals' drivers untouched,
> this patchset:
>    - introduces a generic I/O space management framework, LIBIO, to support I/O
>      operations on host controllers operating either on MMIO buses or on buses
>      requiring specific driver I/O accessors;
>    - redefines the in/out accessors to provide a unified interface for both MMIO
>      and driver specific I/O operations. Using LIBIO, th call of in/out() from
>      the host children drivers, such as ipmi-si, will be redirected to the
>      corresponding device-specific I/O hooks to perform 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.

FWIW my thoughts on this are WTF!

Looks to me horribly over complicated and over generalised.

Surely is it could be done the same way that x86 does IO cycles?
So you encode the information into the 'address' the driver passes
to ioread16() (etc) to allow it to do either a normal bus cycle or
the indirect cycle onto the external bus.

So you have one kernel option that makes these real functions.

	David

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-27 16:45   ` David Laight
  0 siblings, 0 replies; 89+ messages in thread
From: David Laight @ 2017-10-27 16:45 UTC (permalink / raw)
  To: 'Gabriele Paoloni',
	catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, linux-pci, minyard, john.garry, xuwei5

From: Gabriele Paoloni
> Sent: 27 October 2017 17:11
> 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 accessors are based
> on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
> specific accessors rather than MMIO.
> To solve this issue and keep the relevant existing peripherals' drivers untouched,
> this patchset:
>    - introduces a generic I/O space management framework, LIBIO, to support I/O
>      operations on host controllers operating either on MMIO buses or on buses
>      requiring specific driver I/O accessors;
>    - redefines the in/out accessors to provide a unified interface for both MMIO
>      and driver specific I/O operations. Using LIBIO, th call of in/out() from
>      the host children drivers, such as ipmi-si, will be redirected to the
>      corresponding device-specific I/O hooks to perform 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.

FWIW my thoughts on this are WTF!

Looks to me horribly over complicated and over generalised.

Surely is it could be done the same way that x86 does IO cycles?
So you encode the information into the 'address' the driver passes
to ioread16() (etc) to allow it to do either a normal bus cycle or
the indirect cycle onto the external bus.

So you have one kernel option that makes these real functions.

	David

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-27 16:45   ` David Laight
  0 siblings, 0 replies; 89+ messages in thread
From: David Laight @ 2017-10-27 16:45 UTC (permalink / raw)
  To: 'Gabriele Paoloni',
	catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, minyard, benh, john.garry, linux-kernel, xuwei5,
	linuxarm, linux-acpi, linux-pci, olof, brian.starkey

From: Gabriele Paoloni
> Sent: 27 October 2017 17:11
> 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 accessors are based
> on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
> specific accessors rather than MMIO.
> To solve this issue and keep the relevant existing peripherals' drivers untouched,
> this patchset:
>    - introduces a generic I/O space management framework, LIBIO, to support I/O
>      operations on host controllers operating either on MMIO buses or on buses
>      requiring specific driver I/O accessors;
>    - redefines the in/out accessors to provide a unified interface for both MMIO
>      and driver specific I/O operations. Using LIBIO, th call of in/out() from
>      the host children drivers, such as ipmi-si, will be redirected to the
>      corresponding device-specific I/O hooks to perform 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.

FWIW my thoughts on this are WTF!

Looks to me horribly over complicated and over generalised.

Surely is it could be done the same way that x86 does IO cycles?
So you encode the information into the 'address' the driver passes
to ioread16() (etc) to allow it to do either a normal bus cycle or
the indirect cycle onto the external bus.

So you have one kernel option that makes these real functions.

	David


_______________________________________________
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] 89+ messages in thread

* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-27 16:45   ` David Laight
  0 siblings, 0 replies; 89+ messages in thread
From: David Laight @ 2017-10-27 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Gabriele Paoloni
> Sent: 27 October 2017 17:11
> 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 accessors are based
> on MMIO ranges; on Hip06/Hip07 LPC the I/O accesses are performed through driver
> specific accessors rather than MMIO.
> To solve this issue and keep the relevant existing peripherals' drivers untouched,
> this patchset:
>    - introduces a generic I/O space management framework, LIBIO, to support I/O
>      operations on host controllers operating either on MMIO buses or on buses
>      requiring specific driver I/O accessors;
>    - redefines the in/out accessors to provide a unified interface for both MMIO
>      and driver specific I/O operations. Using LIBIO, th call of in/out() from
>      the host children drivers, such as ipmi-si, will be redirected to the
>      corresponding device-specific I/O hooks to perform 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.

FWIW my thoughts on this are WTF!

Looks to me horribly over complicated and over generalised.

Surely is it could be done the same way that x86 does IO cycles?
So you encode the information into the 'address' the driver passes
to ioread16() (etc) to allow it to do either a normal bus cycle or
the indirect cycle onto the external bus.

So you have one kernel option that makes these real functions.

	David

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

* Re: [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
  2017-10-27 16:11   ` Gabriele Paoloni
@ 2017-10-27 18:32     ` Corey Minyard
  -1 siblings, 0 replies; 89+ messages in thread
From: Corey Minyard @ 2017-10-27 18:32 UTC (permalink / raw)
  To: Gabriele Paoloni, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, linuxarm, linux-pci, john.garry, xuwei5,
	zhichang.yuan

On 10/27/2017 11:11 AM, Gabriele Paoloni wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
>
> In commit 41f8bba7f555 ("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  |  26 +++++
>   include/linux/logic_pio.h | 118 +++++++++++++++++++
>   lib/Kconfig               |  26 +++++
>   lib/Makefile              |   2 +
>   lib/logic_pio.c           | 286 ++++++++++++++++++++++++++++++++++++++++++++++
>   5 files changed, 458 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..334e5db 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>

This whole thing would be a lot simpler if you had:

#ifdef CONFIG_INDIRECT_PIO
#define inb logic_inb
#define outb logic outb
.
.
#endif /* CONFIG_INDIRECT_PIO */

and let the "ifndef XXX" below handle not enabling the standard code.
You could even put that in logic_pio.h to avoid polluting io.h.

You might have to add "#ifndef inb", etc. above, but I still think it would
be better.

I'm not sure if this wouldn't be better done in arm64/include/asm/io.h, 
though.
A specific machine may want to only do this in ranges, for instance.

-corey

> +
>   /*
>    * {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
> diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
> new file mode 100644
> index 0000000..f0a6f15
> --- /dev/null
> +++ b/include/linux/logic_pio.h
> @@ -0,0 +1,118 @@
> +/*
> + * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
> + * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> + * 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_LOGIC_PIO_H
> +#define __LINUX_LOGIC_PIO_H
> +
> +#ifdef __KERNEL__
> +
> +#include <linux/fwnode.h>
> +
> +#define PIO_INDIRECT		0x01UL /* indirect IO flag */
> +#define PIO_CPU_MMIO		0x00UL /* memory mapped io flag */
> +
> +struct logic_pio_hwaddr {
> +	struct list_head list;
> +	struct fwnode_handle *fwnode;
> +	resource_size_t hw_start;
> +	resource_size_t io_start;
> +	resource_size_t size; /* range size populated */
> +	unsigned long flags;
> +
> +	void *devpara;	/* private parameter of the host device */
> +	struct hostio_ops *ops;	/* ops operating on this node */
> +};
> +
> +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
> +u8 logic_inb(unsigned long addr);
> +void logic_outb(u8 value, unsigned long addr);
> +void logic_outw(u16 value, unsigned long addr);
> +void logic_outl(u32 value, unsigned long addr);
> +u16 logic_inw(unsigned long addr);
> +u32 logic_inl(unsigned long addr);
> +void logic_outb(u8 value, unsigned long addr);
> +void logic_outw(u16 value, unsigned long addr);
> +void logic_outl(u32 value, unsigned long addr);
> +void logic_insb(unsigned long addr, void *buffer, unsigned int count);
> +void logic_insl(unsigned long addr, void *buffer, unsigned int count);
> +void logic_insw(unsigned long addr, void *buffer, unsigned int count);
> +void logic_outsb(unsigned long addr, const void *buffer, unsigned int count);
> +void logic_outsw(unsigned long addr, const void *buffer, unsigned int count);
> +void logic_outsl(unsigned long addr, const void *buffer, unsigned int count);
> +
> +#define insb logic_insb
> +#define insw logic_insw
> +#define insl logic_insl
> +#define outsb logic_outsb
> +#define outsw logic_outsw
> +#define outsl logic_outsl
> +
> +/*
> + * Below we reserve 0x4000 bytes for Indirect IO as so far this library is only
> + * used by Hisilicon LPC Host. If needed in future we may reserve a wider IO
> + * area by redefining the macro below.
> + */
> +#define PIO_INDIRECT_SIZE 0x4000
> +#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
> +#else
> +#define MMIO_UPPER_LIMIT IO_SPACE_LIMIT
> +#endif
> +
> +#ifdef CONFIG_LOGIC_PIO
> +struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
> +
> +unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
> +			resource_size_t hw_addr, resource_size_t size);
> +
> +int logic_pio_register_range(struct logic_pio_hwaddr *newrange);
> +#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, resource_size_t size);
> +{
> +	return -1;
> +}
> +
> +static inline struct logic_pio_hwaddr
> +*logic_pio_register_range(struct logic_pio_hwaddr *newrange);
> +{
> +	return NULL;
> +}
> +#endif
> +
> +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_LOGIC_PIO_H */
> diff --git a/lib/Kconfig b/lib/Kconfig
> index 6762529..d7443a6 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.
> +

If this is always available on the hisilicon chips, I think you would 
want to just always
enable this on those chips.

-corey

>   config CRC_CCITT
>   	tristate "CRC-CCITT functions"
>   	help
> diff --git a/lib/Makefile b/lib/Makefile
> index 40c1837..e0246ad 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..f8427cb
> --- /dev/null
> +++ b/lib/logic_pio.c
> @@ -0,0 +1,286 @@
> +/*
> + * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
> + * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> + * 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/logic_pio.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);
> +
> +/*
> + * register a new io range node in the io range list.
> + *
> + * @newrange: pointer to the io range to be registered.
> + *
> + * returns 0 on success, the error code in case of failure
> + */
> +int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
> +{
> +	struct logic_pio_hwaddr *range;
> +	int ret = 0;
> +	resource_size_t start = new_range->hw_start;
> +	resource_size_t end = new_range->hw_start + new_range->size;
> +	resource_size_t allocated_mmio_size = 0;
> +	resource_size_t allocated_iio_size = MMIO_UPPER_LIMIT;
> +
> +	if (!new_range || !new_range->fwnode || !new_range->size)
> +		return -EINVAL;
> +
> +	mutex_lock(&io_range_mutex);
> +	list_for_each_entry_rcu(range, &io_range_list, list) {
> +
> +		if (range->fwnode == new_range->fwnode) {
> +			/* range already there */
> +			ret = -EFAULT;
> +			goto end_register;
> +		}
> +		if (range->flags == PIO_CPU_MMIO &&
> +				new_range->flags == PIO_CPU_MMIO) {
> +			/* for MMIO ranges we need to check for overlap */
> +			if (start >= range->hw_start + range->size ||
> +				end < range->hw_start)
> +				allocated_mmio_size += range->size;
> +			else {
> +				ret = -EFAULT;
> +				goto end_register;
> +			}
> +		} else if (range->flags == PIO_INDIRECT &&
> +				new_range->flags == PIO_INDIRECT) {
> +			allocated_iio_size += range->size;
> +		}
> +	}
> +
> +	/* range not registered yet, check for available space */
> +	if (new_range->flags == PIO_CPU_MMIO) {
> +
> +		if (allocated_mmio_size + new_range->size - 1 >
> +			MMIO_UPPER_LIMIT) {
> +			/* if it's too big check if 64K space can be reserved */
> +			if (allocated_mmio_size + SZ_64K - 1 >
> +			MMIO_UPPER_LIMIT) {
> +				ret = -E2BIG;
> +				goto end_register;
> +			}
> +			new_range->size = SZ_64K;
> +			pr_warn("Requested IO range too big, new size set to 64K\n");
> +		}
> +
> +		new_range->io_start = allocated_mmio_size;
> +
> +	} else if (new_range->flags == PIO_INDIRECT) {
> +
> +		if (allocated_iio_size + new_range->size - 1 >
> +		IO_SPACE_LIMIT) {
> +			ret = -E2BIG;
> +			goto end_register;
> +		}
> +		new_range->io_start = allocated_iio_size;
> +
> +	} else {
> +		/* invalid flag */
> +		ret = -EINVAL;
> +		goto end_register;
> +	}
> +
> +	list_add_tail_rcu(&new_range->list, &io_range_list);
> +
> +end_register:
> +	mutex_unlock(&io_range_mutex);
> +	return ret;
> +}
> +
> +/*
> + * 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;
> +}
> +
> +/* return a registered range given an input PIO token */
> +static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
> +{
> +	struct logic_pio_hwaddr *range;
> +
> +	list_for_each_entry_rcu(range, &io_range_list, list) {
> +		if (pio >= range->io_start &&
> +				pio < range->io_start + range->size)
> +			return range;
> +	}
> +	pr_err("PIO entry token invalid\n");
> +	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_hwaddr *range;
> +	resource_size_t hwaddr = -1;
> +
> +	range = find_io_range(pio);
> +	if (range)
> +		hwaddr = range->hw_start + pio - range->io_start;
> +
> +	return hwaddr;
> +}
> +
> +/*
> + * 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,
> +		       resource_size_t size)
> +{
> +	struct logic_pio_hwaddr *range;
> +
> +	range = find_io_range_by_fwnode(fwnode);
> +	if (!range || range->flags == PIO_CPU_MMIO) {
> +		pr_err("range not found or invalid\n");
> +		return -1;
> +	}
> +	if (range->size < size) {
> +		pr_err("resource size 0x%llx cannot fit in IO range size 0x%llx\n",
> +		       size, range->size);
> +		return -1;
> +	}
> +	return addr - range->hw_start + range->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->flags != PIO_CPU_MMIO)
> +			continue;
> +		if (addr >= range->hw_start &&
> +			addr < range->hw_start + range->size)
> +			return addr - range->hw_start +
> +				range->io_start;
> +	}
> +	pr_err("addr not registered in io_range_list\n");
> +	return -1;
> +}
> +
> +#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
> +#define BUILD_LOGIC_IO(bw, type)					\
> +type logic_in##bw(unsigned long addr)					\
> +{									\
> +	type ret = -1;							\
> +									\
> +	if (addr < MMIO_UPPER_LIMIT) {					\
> +		ret = read##bw(PCI_IOBASE + addr);			\
> +	} else {							\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			ret = entry->ops->pfin(entry->devpara,		\
> +					addr, sizeof(type));		\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +	return ret;							\
> +}									\
> +									\
> +void logic_out##bw(type value, unsigned long addr)			\
> +{									\
> +	if (addr < MMIO_UPPER_LIMIT) {					\
> +		write##bw(value, PCI_IOBASE + addr);			\
> +	} else {							\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			entry->ops->pfout(entry->devpara,		\
> +					addr, value, sizeof(type));	\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +}									\
> +									\
> +void logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
> +{									\
> +	if (addr < MMIO_UPPER_LIMIT) {					\
> +		reads##bw(PCI_IOBASE + addr, buffer, count);		\
> +	} else {							\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			entry->ops->pfins(entry->devpara,		\
> +				addr, buffer, sizeof(type), count);	\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +									\
> +}									\
> +									\
> +void logic_outs##bw(unsigned long addr, const void *buffer,		\
> +		    unsigned int count)					\
> +{									\
> +	if (addr < MMIO_UPPER_LIMIT)					\
> +		writes##bw(PCI_IOBASE + addr, buffer, count);		\
> +	else {								\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			entry->ops->pfouts(entry->devpara,		\
> +				addr, buffer, sizeof(type), count);	\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +}
> +
> +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 */

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

* [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
@ 2017-10-27 18:32     ` Corey Minyard
  0 siblings, 0 replies; 89+ messages in thread
From: Corey Minyard @ 2017-10-27 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/27/2017 11:11 AM, Gabriele Paoloni wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
>
> In commit 41f8bba7f555 ("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  |  26 +++++
>   include/linux/logic_pio.h | 118 +++++++++++++++++++
>   lib/Kconfig               |  26 +++++
>   lib/Makefile              |   2 +
>   lib/logic_pio.c           | 286 ++++++++++++++++++++++++++++++++++++++++++++++
>   5 files changed, 458 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..334e5db 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>

This whole thing would be a lot simpler if you had:

#ifdef CONFIG_INDIRECT_PIO
#define inb logic_inb
#define outb logic outb
.
.
#endif /* CONFIG_INDIRECT_PIO */

and let the "ifndef XXX" below handle not enabling the standard code.
You could even put that in logic_pio.h to avoid polluting io.h.

You might have to add "#ifndef inb", etc. above, but I still think it would
be better.

I'm not sure if this wouldn't be better done in arm64/include/asm/io.h, 
though.
A specific machine may want to only do this in ranges, for instance.

-corey

> +
>   /*
>    * {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
> diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
> new file mode 100644
> index 0000000..f0a6f15
> --- /dev/null
> +++ b/include/linux/logic_pio.h
> @@ -0,0 +1,118 @@
> +/*
> + * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
> + * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> + * 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_LOGIC_PIO_H
> +#define __LINUX_LOGIC_PIO_H
> +
> +#ifdef __KERNEL__
> +
> +#include <linux/fwnode.h>
> +
> +#define PIO_INDIRECT		0x01UL /* indirect IO flag */
> +#define PIO_CPU_MMIO		0x00UL /* memory mapped io flag */
> +
> +struct logic_pio_hwaddr {
> +	struct list_head list;
> +	struct fwnode_handle *fwnode;
> +	resource_size_t hw_start;
> +	resource_size_t io_start;
> +	resource_size_t size; /* range size populated */
> +	unsigned long flags;
> +
> +	void *devpara;	/* private parameter of the host device */
> +	struct hostio_ops *ops;	/* ops operating on this node */
> +};
> +
> +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
> +u8 logic_inb(unsigned long addr);
> +void logic_outb(u8 value, unsigned long addr);
> +void logic_outw(u16 value, unsigned long addr);
> +void logic_outl(u32 value, unsigned long addr);
> +u16 logic_inw(unsigned long addr);
> +u32 logic_inl(unsigned long addr);
> +void logic_outb(u8 value, unsigned long addr);
> +void logic_outw(u16 value, unsigned long addr);
> +void logic_outl(u32 value, unsigned long addr);
> +void logic_insb(unsigned long addr, void *buffer, unsigned int count);
> +void logic_insl(unsigned long addr, void *buffer, unsigned int count);
> +void logic_insw(unsigned long addr, void *buffer, unsigned int count);
> +void logic_outsb(unsigned long addr, const void *buffer, unsigned int count);
> +void logic_outsw(unsigned long addr, const void *buffer, unsigned int count);
> +void logic_outsl(unsigned long addr, const void *buffer, unsigned int count);
> +
> +#define insb logic_insb
> +#define insw logic_insw
> +#define insl logic_insl
> +#define outsb logic_outsb
> +#define outsw logic_outsw
> +#define outsl logic_outsl
> +
> +/*
> + * Below we reserve 0x4000 bytes for Indirect IO as so far this library is only
> + * used by Hisilicon LPC Host. If needed in future we may reserve a wider IO
> + * area by redefining the macro below.
> + */
> +#define PIO_INDIRECT_SIZE 0x4000
> +#define MMIO_UPPER_LIMIT (IO_SPACE_LIMIT - PIO_INDIRECT_SIZE)
> +#else
> +#define MMIO_UPPER_LIMIT IO_SPACE_LIMIT
> +#endif
> +
> +#ifdef CONFIG_LOGIC_PIO
> +struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
> +
> +unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
> +			resource_size_t hw_addr, resource_size_t size);
> +
> +int logic_pio_register_range(struct logic_pio_hwaddr *newrange);
> +#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, resource_size_t size);
> +{
> +	return -1;
> +}
> +
> +static inline struct logic_pio_hwaddr
> +*logic_pio_register_range(struct logic_pio_hwaddr *newrange);
> +{
> +	return NULL;
> +}
> +#endif
> +
> +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_LOGIC_PIO_H */
> diff --git a/lib/Kconfig b/lib/Kconfig
> index 6762529..d7443a6 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.
> +

If this is always available on the hisilicon chips, I think you would 
want to just always
enable this on those chips.

-corey

>   config CRC_CCITT
>   	tristate "CRC-CCITT functions"
>   	help
> diff --git a/lib/Makefile b/lib/Makefile
> index 40c1837..e0246ad 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..f8427cb
> --- /dev/null
> +++ b/lib/logic_pio.c
> @@ -0,0 +1,286 @@
> +/*
> + * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
> + * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> + * 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/logic_pio.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);
> +
> +/*
> + * register a new io range node in the io range list.
> + *
> + * @newrange: pointer to the io range to be registered.
> + *
> + * returns 0 on success, the error code in case of failure
> + */
> +int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
> +{
> +	struct logic_pio_hwaddr *range;
> +	int ret = 0;
> +	resource_size_t start = new_range->hw_start;
> +	resource_size_t end = new_range->hw_start + new_range->size;
> +	resource_size_t allocated_mmio_size = 0;
> +	resource_size_t allocated_iio_size = MMIO_UPPER_LIMIT;
> +
> +	if (!new_range || !new_range->fwnode || !new_range->size)
> +		return -EINVAL;
> +
> +	mutex_lock(&io_range_mutex);
> +	list_for_each_entry_rcu(range, &io_range_list, list) {
> +
> +		if (range->fwnode == new_range->fwnode) {
> +			/* range already there */
> +			ret = -EFAULT;
> +			goto end_register;
> +		}
> +		if (range->flags == PIO_CPU_MMIO &&
> +				new_range->flags == PIO_CPU_MMIO) {
> +			/* for MMIO ranges we need to check for overlap */
> +			if (start >= range->hw_start + range->size ||
> +				end < range->hw_start)
> +				allocated_mmio_size += range->size;
> +			else {
> +				ret = -EFAULT;
> +				goto end_register;
> +			}
> +		} else if (range->flags == PIO_INDIRECT &&
> +				new_range->flags == PIO_INDIRECT) {
> +			allocated_iio_size += range->size;
> +		}
> +	}
> +
> +	/* range not registered yet, check for available space */
> +	if (new_range->flags == PIO_CPU_MMIO) {
> +
> +		if (allocated_mmio_size + new_range->size - 1 >
> +			MMIO_UPPER_LIMIT) {
> +			/* if it's too big check if 64K space can be reserved */
> +			if (allocated_mmio_size + SZ_64K - 1 >
> +			MMIO_UPPER_LIMIT) {
> +				ret = -E2BIG;
> +				goto end_register;
> +			}
> +			new_range->size = SZ_64K;
> +			pr_warn("Requested IO range too big, new size set to 64K\n");
> +		}
> +
> +		new_range->io_start = allocated_mmio_size;
> +
> +	} else if (new_range->flags == PIO_INDIRECT) {
> +
> +		if (allocated_iio_size + new_range->size - 1 >
> +		IO_SPACE_LIMIT) {
> +			ret = -E2BIG;
> +			goto end_register;
> +		}
> +		new_range->io_start = allocated_iio_size;
> +
> +	} else {
> +		/* invalid flag */
> +		ret = -EINVAL;
> +		goto end_register;
> +	}
> +
> +	list_add_tail_rcu(&new_range->list, &io_range_list);
> +
> +end_register:
> +	mutex_unlock(&io_range_mutex);
> +	return ret;
> +}
> +
> +/*
> + * 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;
> +}
> +
> +/* return a registered range given an input PIO token */
> +static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
> +{
> +	struct logic_pio_hwaddr *range;
> +
> +	list_for_each_entry_rcu(range, &io_range_list, list) {
> +		if (pio >= range->io_start &&
> +				pio < range->io_start + range->size)
> +			return range;
> +	}
> +	pr_err("PIO entry token invalid\n");
> +	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_hwaddr *range;
> +	resource_size_t hwaddr = -1;
> +
> +	range = find_io_range(pio);
> +	if (range)
> +		hwaddr = range->hw_start + pio - range->io_start;
> +
> +	return hwaddr;
> +}
> +
> +/*
> + * 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,
> +		       resource_size_t size)
> +{
> +	struct logic_pio_hwaddr *range;
> +
> +	range = find_io_range_by_fwnode(fwnode);
> +	if (!range || range->flags == PIO_CPU_MMIO) {
> +		pr_err("range not found or invalid\n");
> +		return -1;
> +	}
> +	if (range->size < size) {
> +		pr_err("resource size 0x%llx cannot fit in IO range size 0x%llx\n",
> +		       size, range->size);
> +		return -1;
> +	}
> +	return addr - range->hw_start + range->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->flags != PIO_CPU_MMIO)
> +			continue;
> +		if (addr >= range->hw_start &&
> +			addr < range->hw_start + range->size)
> +			return addr - range->hw_start +
> +				range->io_start;
> +	}
> +	pr_err("addr not registered in io_range_list\n");
> +	return -1;
> +}
> +
> +#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
> +#define BUILD_LOGIC_IO(bw, type)					\
> +type logic_in##bw(unsigned long addr)					\
> +{									\
> +	type ret = -1;							\
> +									\
> +	if (addr < MMIO_UPPER_LIMIT) {					\
> +		ret = read##bw(PCI_IOBASE + addr);			\
> +	} else {							\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			ret = entry->ops->pfin(entry->devpara,		\
> +					addr, sizeof(type));		\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +	return ret;							\
> +}									\
> +									\
> +void logic_out##bw(type value, unsigned long addr)			\
> +{									\
> +	if (addr < MMIO_UPPER_LIMIT) {					\
> +		write##bw(value, PCI_IOBASE + addr);			\
> +	} else {							\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			entry->ops->pfout(entry->devpara,		\
> +					addr, value, sizeof(type));	\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +}									\
> +									\
> +void logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
> +{									\
> +	if (addr < MMIO_UPPER_LIMIT) {					\
> +		reads##bw(PCI_IOBASE + addr, buffer, count);		\
> +	} else {							\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			entry->ops->pfins(entry->devpara,		\
> +				addr, buffer, sizeof(type), count);	\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +									\
> +}									\
> +									\
> +void logic_outs##bw(unsigned long addr, const void *buffer,		\
> +		    unsigned int count)					\
> +{									\
> +	if (addr < MMIO_UPPER_LIMIT)					\
> +		writes##bw(PCI_IOBASE + addr, buffer, count);		\
> +	else {								\
> +		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
> +									\
> +		if (entry && entry->ops)				\
> +			entry->ops->pfouts(entry->devpara,		\
> +				addr, buffer, sizeof(type), count);	\
> +		else							\
> +			WARN_ON_ONCE(1);				\
> +	}								\
> +}
> +
> +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 */

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
  2017-10-27 16:45   ` David Laight
  (?)
  (?)
@ 2017-10-30 11:32     ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 11:32 UTC (permalink / raw)
  To: David Laight, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, minyard, benh, John Garry, linux-kernel, xuwei (O),
	Linuxarm, linux-acpi, linux-pci, olof, brian.starkey

Hi David

[...]

> FWIW my thoughts on this are WTF!
> 
> Looks to me horribly over complicated and over generalised.
> 
> Surely is it could be done the same way that x86 does IO cycles?

No

> So you encode the information into the 'address' the driver passes
> to ioread16() (etc) to allow it to do either a normal bus cycle or
> the indirect cycle onto the external bus.

In order to do that you need to have a special PCI bridge that is able
to detect the special IO addresses and initiate such special IO cycles
on the external bus. This is not supported by our HW (and this why
we need the LPC accessors)

Gab

> 
> So you have one kernel option that makes these real functions.
> 
> 	David

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-30 11:32     ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 11:32 UTC (permalink / raw)
  To: David Laight, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, Linuxarm, linux-pci, minyard, John Garry, xuwei (O)

Hi David

[...]

> FWIW my thoughts on this are WTF!
> 
> Looks to me horribly over complicated and over generalised.
> 
> Surely is it could be done the same way that x86 does IO cycles?

No

> So you encode the information into the 'address' the driver passes
> to ioread16() (etc) to allow it to do either a normal bus cycle or
> the indirect cycle onto the external bus.

In order to do that you need to have a special PCI bridge that is able
to detect the special IO addresses and initiate such special IO cycles
on the external bus. This is not supported by our HW (and this why
we need the LPC accessors)

Gab

> 
> So you have one kernel option that makes these real functions.
> 
> 	David

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-30 11:32     ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 11:32 UTC (permalink / raw)
  To: David Laight, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, minyard, benh, John Garry, linux-kernel, xuwei (O),
	Linuxarm, linux-acpi, linux-pci, olof, brian.starkey

Hi David

[...]

> FWIW my thoughts on this are WTF!
> 
> Looks to me horribly over complicated and over generalised.
> 
> Surely is it could be done the same way that x86 does IO cycles?

No

> So you encode the information into the 'address' the driver passes
> to ioread16() (etc) to allow it to do either a normal bus cycle or
> the indirect cycle onto the external bus.

In order to do that you need to have a special PCI bridge that is able
to detect the special IO addresses and initiate such special IO cycles
on the external bus. This is not supported by our HW (and this why
we need the LPC accessors)

Gab

> 
> So you have one kernel option that makes these real functions.
> 
> 	David


_______________________________________________
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] 89+ messages in thread

* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-10-30 11:32     ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi David

[...]

> FWIW my thoughts on this are WTF!
> 
> Looks to me horribly over complicated and over generalised.
> 
> Surely is it could be done the same way that x86 does IO cycles?

No

> So you encode the information into the 'address' the driver passes
> to ioread16() (etc) to allow it to do either a normal bus cycle or
> the indirect cycle onto the external bus.

In order to do that you need to have a special PCI bridge that is able
to detect the special IO addresses and initiate such special IO cycles
on the external bus. This is not supported by our HW (and this why
we need the LPC accessors)

Gab

> 
> So you have one kernel option that makes these real functions.
> 
> 	David

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

* RE: [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
  2017-10-27 18:32     ` Corey Minyard
  (?)
  (?)
@ 2017-10-30 15:31       ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:31 UTC (permalink / raw)
  To: minyard, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, Linuxarm, linux-pci, John Garry, xuwei (O),
	zhichang.yuan

Hi Corey

Many Thanks for your comments

[...]

> >   #define IO_SPACE_LIMIT 0xffff
> >   #endif
> >
> > +#include <linux/logic_pio.h>
> 
> This whole thing would be a lot simpler if you had:
> 
> #ifdef CONFIG_INDIRECT_PIO
> #define inb logic_inb
> #define outb logic outb
> .
> .
> #endif /* CONFIG_INDIRECT_PIO */
> 
> and let the "ifndef XXX" below handle not enabling the standard code.
> You could even put that in logic_pio.h to avoid polluting io.h.

Agreed. I'll move it into "logic_pio.h"

> 
> You might have to add "#ifndef inb", etc. above, but I still think it
> would
> be better.

Yes agreed also on adding the "#ifndef ***" around each function re-definition
in logic_pio.h

This will be fixed in v11

> 
> I'm not sure if this wouldn't be better done in arm64/include/asm/io.h,
> though.
> A specific machine may want to only do this in ranges, for instance.

No I don’t think so...this io functions re-0definition has nothing to do
with ARM architecture and I think it is better to keep everything in
logic_pio.h including the file from "include/asm-generic/io.h"

Cheers
Gab

> 
> -corey

[...]

> > --- 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.
> > +
> 
> If this is always available on the hisilicon chips, I think you would
> want to just always
> enable this on those chips.

In patch 6/9 we have 

+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

So the LPC host controller driver is selecting INDIRECT_PIO...

> 
> -corey
> 

Cheers
Gab


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

* RE: [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
@ 2017-10-30 15:31       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:31 UTC (permalink / raw)
  To: minyard, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, Linuxarm, linux-pci, John Garry, xuwei (O),
	zhichang.yuan

Hi Corey

Many Thanks for your comments

[...]

> >   #define IO_SPACE_LIMIT 0xffff
> >   #endif
> >
> > +#include <linux/logic_pio.h>
> 
> This whole thing would be a lot simpler if you had:
> 
> #ifdef CONFIG_INDIRECT_PIO
> #define inb logic_inb
> #define outb logic outb
> .
> .
> #endif /* CONFIG_INDIRECT_PIO */
> 
> and let the "ifndef XXX" below handle not enabling the standard code.
> You could even put that in logic_pio.h to avoid polluting io.h.

Agreed. I'll move it into "logic_pio.h"

> 
> You might have to add "#ifndef inb", etc. above, but I still think it
> would
> be better.

Yes agreed also on adding the "#ifndef ***" around each function re-definition
in logic_pio.h

This will be fixed in v11

> 
> I'm not sure if this wouldn't be better done in arm64/include/asm/io.h,
> though.
> A specific machine may want to only do this in ranges, for instance.

No I don’t think so...this io functions re-0definition has nothing to do
with ARM architecture and I think it is better to keep everything in
logic_pio.h including the file from "include/asm-generic/io.h"

Cheers
Gab

> 
> -corey

[...]

> > --- 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.
> > +
> 
> If this is always available on the hisilicon chips, I think you would
> want to just always
> enable this on those chips.

In patch 6/9 we have 

+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

So the LPC host controller driver is selecting INDIRECT_PIO...

> 
> -corey
> 

Cheers
Gab

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

* RE: [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
@ 2017-10-30 15:31       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:31 UTC (permalink / raw)
  To: minyard, catalin.marinas, will.deacon, robh+dt, frowand.list,
	bhelgaas, rafael, arnd, linux-arm-kernel, lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, Linuxarm, linux-pci, John Garry, xuwei (O),
	zhichang.yuan

SGkgQ29yZXkNCg0KTWFueSBUaGFua3MgZm9yIHlvdXIgY29tbWVudHMNCg0KWy4uLl0NCg0KPiA+
ICAgI2RlZmluZSBJT19TUEFDRV9MSU1JVCAweGZmZmYNCj4gPiAgICNlbmRpZg0KPiA+DQo+ID4g
KyNpbmNsdWRlIDxsaW51eC9sb2dpY19waW8uaD4NCj4gDQo+IFRoaXMgd2hvbGUgdGhpbmcgd291
bGQgYmUgYSBsb3Qgc2ltcGxlciBpZiB5b3UgaGFkOg0KPiANCj4gI2lmZGVmIENPTkZJR19JTkRJ
UkVDVF9QSU8NCj4gI2RlZmluZSBpbmIgbG9naWNfaW5iDQo+ICNkZWZpbmUgb3V0YiBsb2dpYyBv
dXRiDQo+IC4NCj4gLg0KPiAjZW5kaWYgLyogQ09ORklHX0lORElSRUNUX1BJTyAqLw0KPiANCj4g
YW5kIGxldCB0aGUgImlmbmRlZiBYWFgiIGJlbG93IGhhbmRsZSBub3QgZW5hYmxpbmcgdGhlIHN0
YW5kYXJkIGNvZGUuDQo+IFlvdSBjb3VsZCBldmVuIHB1dCB0aGF0IGluIGxvZ2ljX3Bpby5oIHRv
IGF2b2lkIHBvbGx1dGluZyBpby5oLg0KDQpBZ3JlZWQuIEknbGwgbW92ZSBpdCBpbnRvICJsb2dp
Y19waW8uaCINCg0KPiANCj4gWW91IG1pZ2h0IGhhdmUgdG8gYWRkICIjaWZuZGVmIGluYiIsIGV0
Yy4gYWJvdmUsIGJ1dCBJIHN0aWxsIHRoaW5rIGl0DQo+IHdvdWxkDQo+IGJlIGJldHRlci4NCg0K
WWVzIGFncmVlZCBhbHNvIG9uIGFkZGluZyB0aGUgIiNpZm5kZWYgKioqIiBhcm91bmQgZWFjaCBm
dW5jdGlvbiByZS1kZWZpbml0aW9uDQppbiBsb2dpY19waW8uaA0KDQpUaGlzIHdpbGwgYmUgZml4
ZWQgaW4gdjExDQoNCj4gDQo+IEknbSBub3Qgc3VyZSBpZiB0aGlzIHdvdWxkbid0IGJlIGJldHRl
ciBkb25lIGluIGFybTY0L2luY2x1ZGUvYXNtL2lvLmgsDQo+IHRob3VnaC4NCj4gQSBzcGVjaWZp
YyBtYWNoaW5lIG1heSB3YW50IHRvIG9ubHkgZG8gdGhpcyBpbiByYW5nZXMsIGZvciBpbnN0YW5j
ZS4NCg0KTm8gSSBkb27igJl0IHRoaW5rIHNvLi4udGhpcyBpbyBmdW5jdGlvbnMgcmUtMGRlZmlu
aXRpb24gaGFzIG5vdGhpbmcgdG8gZG8NCndpdGggQVJNIGFyY2hpdGVjdHVyZSBhbmQgSSB0aGlu
ayBpdCBpcyBiZXR0ZXIgdG8ga2VlcCBldmVyeXRoaW5nIGluDQpsb2dpY19waW8uaCBpbmNsdWRp
bmcgdGhlIGZpbGUgZnJvbSAiaW5jbHVkZS9hc20tZ2VuZXJpYy9pby5oIg0KDQpDaGVlcnMNCkdh
Yg0KDQo+IA0KPiAtY29yZXkNCg0KWy4uLl0NCg0KPiA+IC0tLSBhL2xpYi9LY29uZmlnDQo+ID4g
KysrIGIvbGliL0tjb25maWcNCj4gPiBAQCAtNTksNiArNTksMzIgQEAgY29uZmlnIEFSQ0hfVVNF
X0NNUFhDSEdfTE9DS1JFRg0KPiA+ICAgY29uZmlnIEFSQ0hfSEFTX0ZBU1RfTVVMVElQTElFUg0K
PiA+ICAgCWJvb2wNCj4gPg0KPiA+ICtjb25maWcgTE9HSUNfUElPDQo+ID4gKwlib29sICJHZW5l
cmljIGxvZ2ljYWwgSS9PIG1hbmFnZW1lbnQiDQo+ID4gKwlkZWZfYm9vbCB5IGlmIFBDSSAmJiAh
WDg2ICYmICFJQTY0ICYmICFQT1dFUlBDDQo+ID4gKwloZWxwDQo+ID4gKwkgIEZvciBzb21lIGFy
Y2hpdGVjdHVyZXMsIHRoZXJlIGFyZSBubyBJTyBzcGFjZS4gVG8gc3VwcG9ydCB0aGUNCj4gPiAr
CSAgYWNjZXNzZXMgdG8gbGVnYWN5IEkvTyBkZXZpY2VzIG9uIHRob3NlIGFyY2hpdGVjdHVyZXMs
IGtlcm5lbA0KPiA+ICsJICBpbXBsZW1lbnRlZCB0aGUgbWVtb3J5IG1hcHBlZCBJL08gbWVjaGFu
aXNtIGJhc2VkIG9uIGJyaWRnZSBidXMNCj4gPiArCSAgc3VwcG9ydHMuIEJ1dCBmb3Igc29tZSBi
dXNlcyB3aGljaCBkbyBub3Qgc3VwcG9ydCBNTUlPLCB0aGUNCj4gPiArCSAgcGVyaXBoZXJhbHMg
dGhlcmUgc2hvdWxkIGJlIGFjY2Vzc2VkIHdpdGggZGV2aWNlLXNwZWNpZmljIHdheS4NCj4gPiAr
CSAgVG8gYWJzdHJhY3QgdGhvc2UgZGlmZmVyZW50IEkvTyBhY2Nlc3NlcyBpbnRvIHVuaWZpZWQg
SS9PDQo+IGFjY2Vzc29ycywNCj4gPiArCSAgdGhpcyBvcHRpb24gcHJvdmlkZSBhIGdlbmVyaWMg
SS9PIHNwYWNlIG1hbmFnZW1lbnQgd2F5IGFmdGVyDQo+IG1hcHBpbmcNCj4gPiArCSAgdGhlIGRl
dmljZSBJL08gdG8gc3lzdGVtIGxvZ2ljYWwvZmFrZSBJL08gYW5kIGhlbHAgdG8gaGlkZSBhbGwN
Cj4gdGhlDQo+ID4gKwkgIGhhcmR3YXJlIGRldGFpbC4NCj4gPiArDQo+ID4gK2NvbmZpZyBJTkRJ
UkVDVF9QSU8NCj4gPiArCWJvb2wgIkFjY2VzcyBJL08gaW4gbm9uLU1NSU8gbW9kZSIgaWYgTE9H
SUNfUElPDQo+ID4gKwloZWxwDQo+ID4gKwkgIE9uIHNvbWUgcGxhdGZvcm1zIHdoZXJlIG5vIHNl
cGFyYXRlIEkvTyBzcGFjZSBleGlzdCwgdGhlcmUgYXJlDQo+IEkvTw0KPiA+ICsJICBob3N0cyB3
aGljaCBjYW4gbm90IGJlIGFjY2Vzc2VkIGluIE1NSU8gbW9kZS4gQmFzZWQgb24NCj4gTE9HSUNf
UElPDQo+ID4gKwkgIG1lY2hhbmlzbSwgdGhlIGhvc3QtbG9jYWwgSS9PIHJlc291cmNlIGNhbiBi
ZSBtYXBwZWQgaW50bw0KPiBzeXN0ZW0NCj4gPiArCSAgbG9naWMgUElPIHNwYWNlIHNoYXJlZCB3
aXRoIE1NSU8gaG9zdHMsIHN1Y2ggYXMgUENJL1BDSUUsIHRoZW4NCj4gc3lzdGVtDQo+ID4gKwkg
IGNhbiBhY2Nlc3MgdGhlIEkvTyBkZXZpY2VzIHdpdGggdGhlIG1hcHBlZCBsb2dpYyBQSU8gdGhy
b3VnaA0KPiBJL08NCj4gPiArCSAgYWNjZXNzb3JzLg0KPiA+ICsJICBUaGlzIHdheSBoYXMgYSBs
aXR0bGUgSS9PIHBlcmZvcm1hbmNlIGNvc3QuIFBsZWFzZSBtYWtlIHN1cmUNCj4geW91cg0KPiA+
ICsJICBkZXZpY2VzIHJlYWxseSBuZWVkIHRoaXMgY29uZmlndXJlIGl0ZW0gZW5hYmxlZC4NCj4g
PiArDQo+IA0KPiBJZiB0aGlzIGlzIGFsd2F5cyBhdmFpbGFibGUgb24gdGhlIGhpc2lsaWNvbiBj
aGlwcywgSSB0aGluayB5b3Ugd291bGQNCj4gd2FudCB0byBqdXN0IGFsd2F5cw0KPiBlbmFibGUg
dGhpcyBvbiB0aG9zZSBjaGlwcy4NCg0KSW4gcGF0Y2ggNi85IHdlIGhhdmUgDQoNCitjb25maWcg
SElTSUxJQ09OX0xQQw0KKwlib29sICJTdXBwb3J0IGZvciBJU0EgSS9PIHNwYWNlIG9uIEhpc2ls
aWNvbiBIaXAwWCINCisJZGVwZW5kcyBvbiAoQVJNNjQgJiYgKEFSQ0hfSElTSSB8fCBDT01QSUxF
X1RFU1QpKQ0KKwlzZWxlY3QgTE9HSUNfUElPDQorCXNlbGVjdCBJTkRJUkVDVF9QSU8NCg0KU28g
dGhlIExQQyBob3N0IGNvbnRyb2xsZXIgZHJpdmVyIGlzIHNlbGVjdGluZyBJTkRJUkVDVF9QSU8u
Li4NCg0KPiANCj4gLWNvcmV5DQo+IA0KDQpDaGVlcnMNCkdhYg0KDQo=

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

* [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method
@ 2017-10-30 15:31       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Corey

Many Thanks for your comments

[...]

> >   #define IO_SPACE_LIMIT 0xffff
> >   #endif
> >
> > +#include <linux/logic_pio.h>
> 
> This whole thing would be a lot simpler if you had:
> 
> #ifdef CONFIG_INDIRECT_PIO
> #define inb logic_inb
> #define outb logic outb
> .
> .
> #endif /* CONFIG_INDIRECT_PIO */
> 
> and let the "ifndef XXX" below handle not enabling the standard code.
> You could even put that in logic_pio.h to avoid polluting io.h.

Agreed. I'll move it into "logic_pio.h"

> 
> You might have to add "#ifndef inb", etc. above, but I still think it
> would
> be better.

Yes agreed also on adding the "#ifndef ***" around each function re-definition
in logic_pio.h

This will be fixed in v11

> 
> I'm not sure if this wouldn't be better done in arm64/include/asm/io.h,
> though.
> A specific machine may want to only do this in ranges, for instance.

No I don?t think so...this io functions re-0definition has nothing to do
with ARM architecture and I think it is better to keep everything in
logic_pio.h including the file from "include/asm-generic/io.h"

Cheers
Gab

> 
> -corey

[...]

> > --- 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.
> > +
> 
> If this is always available on the hisilicon chips, I think you would
> want to just always
> enable this on those chips.

In patch 6/9 we have 

+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

So the LPC host controller driver is selecting INDIRECT_PIO...

> 
> -corey
> 

Cheers
Gab

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

* RE: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  2017-10-27 16:44     ` Randy Dunlap
  (?)
  (?)
@ 2017-10-30 15:55       ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:55 UTC (permalink / raw)
  To: Randy Dunlap, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, Linuxarm, linux-pci, minyard, John Garry, xuwei (O),
	zhichang.yuan

Hi Randy

> -----Original Message-----
> From: Randy Dunlap [mailto:rdunlap@infradead.org]
> Sent: 27 October 2017 17:44
> To: Gabriele Paoloni; catalin.marinas@arm.com; will.deacon@arm.com;
> robh+dt@kernel.org; frowand.list@gmail.com; bhelgaas@google.com;
> rafael@kernel.org; arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com
> Cc: mark.rutland@arm.com; brian.starkey@arm.com; olof@lixom.net;
> benh@kernel.crashing.org; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O); zhichang.yuan
> Subject: Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07
> with DT bindings
> 
> On 10/27/17 09:11, Gabriele Paoloni wrote:
> > diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> > index 2408ea3..358eed3 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
> 
> Hi,
> 
> Why bool? why not tristate?

Well for the nature of our HW it would not make much sense to have the
LPC modular. Also you can see in patch 8 the LPC host is "translating"
the resources of its children before these are actually probed and this
is done by acpi_indirectio_scan_init() as part of the ACPI init process.

Thanks
Gab

> 
> --
> ~Randy

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

* RE: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-30 15:55       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:55 UTC (permalink / raw)
  To: Randy Dunlap, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, brian.starkey, olof, benh, linux-kernel,
	linux-acpi, Linuxarm, linux-pci, minyard, John Garry, xuwei (O),
	zhichang.yuan

Hi Randy

> -----Original Message-----
> From: Randy Dunlap [mailto:rdunlap@infradead.org]
> Sent: 27 October 2017 17:44
> To: Gabriele Paoloni; catalin.marinas@arm.com; will.deacon@arm.com;
> robh+dt@kernel.org; frowand.list@gmail.com; bhelgaas@google.com;
> rafael@kernel.org; arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com
> Cc: mark.rutland@arm.com; brian.starkey@arm.com; olof@lixom.net;
> benh@kernel.crashing.org; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O); zhichang.yuan
> Subject: Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07
> with DT bindings
> 
> On 10/27/17 09:11, Gabriele Paoloni wrote:
> > diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> > index 2408ea3..358eed3 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
> 
> Hi,
> 
> Why bool? why not tristate?

Well for the nature of our HW it would not make much sense to have the
LPC modular. Also you can see in patch 8 the LPC host is "translating"
the resources of its children before these are actually probed and this
is done by acpi_indirectio_scan_init() as part of the ACPI init process.

Thanks
Gab

> 
> --
> ~Randy

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

* RE: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-30 15:55       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:55 UTC (permalink / raw)
  To: Randy Dunlap, catalin.marinas, will.deacon, robh+dt,
	frowand.list, bhelgaas, rafael, arnd, linux-arm-kernel,
	lorenzo.pieralisi
  Cc: mark.rutland, minyard, benh, John Garry, linux-kernel, xuwei (O),
	Linuxarm, linux-acpi, zhichang.yuan, linux-pci, olof,
	brian.starkey

Hi Randy

> -----Original Message-----
> From: Randy Dunlap [mailto:rdunlap@infradead.org]
> Sent: 27 October 2017 17:44
> To: Gabriele Paoloni; catalin.marinas@arm.com; will.deacon@arm.com;
> robh+dt@kernel.org; frowand.list@gmail.com; bhelgaas@google.com;
> rafael@kernel.org; arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com
> Cc: mark.rutland@arm.com; brian.starkey@arm.com; olof@lixom.net;
> benh@kernel.crashing.org; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O); zhichang.yuan
> Subject: Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07
> with DT bindings
> 
> On 10/27/17 09:11, Gabriele Paoloni wrote:
> > diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> > index 2408ea3..358eed3 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
> 
> Hi,
> 
> Why bool? why not tristate?

Well for the nature of our HW it would not make much sense to have the
LPC modular. Also you can see in patch 8 the LPC host is "translating"
the resources of its children before these are actually probed and this
is done by acpi_indirectio_scan_init() as part of the ACPI init process.

Thanks
Gab

> 
> --
> ~Randy
_______________________________________________
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] 89+ messages in thread

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-10-30 15:55       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-10-30 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Randy

> -----Original Message-----
> From: Randy Dunlap [mailto:rdunlap at infradead.org]
> Sent: 27 October 2017 17:44
> To: Gabriele Paoloni; catalin.marinas at arm.com; will.deacon at arm.com;
> robh+dt at kernel.org; frowand.list at gmail.com; bhelgaas at google.com;
> rafael at kernel.org; arnd at arndb.de; linux-arm-kernel at lists.infradead.org;
> lorenzo.pieralisi at arm.com
> Cc: mark.rutland at arm.com; brian.starkey at arm.com; olof at lixom.net;
> benh at kernel.crashing.org; linux-kernel at vger.kernel.org; linux-
> acpi at vger.kernel.org; Linuxarm; linux-pci at vger.kernel.org;
> minyard at acm.org; John Garry; xuwei (O); zhichang.yuan
> Subject: Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07
> with DT bindings
> 
> On 10/27/17 09:11, Gabriele Paoloni wrote:
> > diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> > index 2408ea3..358eed3 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
> 
> Hi,
> 
> Why bool? why not tristate?

Well for the nature of our HW it would not make much sense to have the
LPC modular. Also you can see in patch 8 the LPC host is "translating"
the resources of its children before these are actually probed and this
is done by acpi_indirectio_scan_init() as part of the ACPI init process.

Thanks
Gab

> 
> --
> ~Randy

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

* Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
  2017-10-27 16:11   ` Gabriele Paoloni
  (?)
  (?)
@ 2017-11-07  0:21     ` Bjorn Helgaas
  -1 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:21 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: mark.rutland, minyard, lorenzo.pieralisi, linux-acpi, arnd,
	rafael, linux-pci, catalin.marinas, john.garry, will.deacon,
	linux-kernel, xuwei5, linuxarm, olof, robh+dt, benh, bhelgaas,
	frowand.list, brian.starkey, linux-arm-kernel

s/MANTAINERS/MAINTAINERS/

On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> Added maintainer for drivers/bus/hisi_lpc.c
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f66488d..b49d4c0 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
>  F:	net/802/hippi.c
>  F:	drivers/net/hippi/
>  
> +HISILICON LPC BUS DRIVER
> +L:	linuxarm@huawei.com
> +W:	http://www.hisilicon.com
> +S:	Maintained
> +F:	drivers/bus/hisi_lpc.c
> +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt

Does this really count as a "maintainer" since it's only a mailing
list, not a real person?  I personally prefer a specific person
because there's no accountability with a mailing list.

> +
>  HISILICON NETWORK SUBSYSTEM DRIVER
>  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
>  M:	Salil Mehta <salil.mehta@huawei.com>
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-11-07  0:21     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:21 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, linuxarm,
	linux-pci, minyard, john.garry, xuwei5

s/MANTAINERS/MAINTAINERS/

On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> Added maintainer for drivers/bus/hisi_lpc.c
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f66488d..b49d4c0 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
>  F:	net/802/hippi.c
>  F:	drivers/net/hippi/
>  
> +HISILICON LPC BUS DRIVER
> +L:	linuxarm@huawei.com
> +W:	http://www.hisilicon.com
> +S:	Maintained
> +F:	drivers/bus/hisi_lpc.c
> +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt

Does this really count as a "maintainer" since it's only a mailing
list, not a real person?  I personally prefer a specific person
because there's no accountability with a mailing list.

> +
>  HISILICON NETWORK SUBSYSTEM DRIVER
>  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
>  M:	Salil Mehta <salil.mehta@huawei.com>
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-11-07  0:21     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:21 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: mark.rutland, minyard, lorenzo.pieralisi, linux-acpi, arnd,
	rafael, linux-pci, catalin.marinas, john.garry, will.deacon,
	linux-kernel, xuwei5, linuxarm, olof, robh+dt, benh, bhelgaas,
	frowand.list, brian.starkey, linux-arm-kernel

s/MANTAINERS/MAINTAINERS/

On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> Added maintainer for drivers/bus/hisi_lpc.c
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f66488d..b49d4c0 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
>  F:	net/802/hippi.c
>  F:	drivers/net/hippi/
>  
> +HISILICON LPC BUS DRIVER
> +L:	linuxarm@huawei.com
> +W:	http://www.hisilicon.com
> +S:	Maintained
> +F:	drivers/bus/hisi_lpc.c
> +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt

Does this really count as a "maintainer" since it's only a mailing
list, not a real person?  I personally prefer a specific person
because there's no accountability with a mailing list.

> +
>  HISILICON NETWORK SUBSYSTEM DRIVER
>  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
>  M:	Salil Mehta <salil.mehta@huawei.com>
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

_______________________________________________
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] 89+ messages in thread

* [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-11-07  0:21     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:21 UTC (permalink / raw)
  To: linux-arm-kernel

s/MANTAINERS/MAINTAINERS/

On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> Added maintainer for drivers/bus/hisi_lpc.c
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f66488d..b49d4c0 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
>  F:	net/802/hippi.c
>  F:	drivers/net/hippi/
>  
> +HISILICON LPC BUS DRIVER
> +L:	linuxarm at huawei.com
> +W:	http://www.hisilicon.com
> +S:	Maintained
> +F:	drivers/bus/hisi_lpc.c
> +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt

Does this really count as a "maintainer" since it's only a mailing
list, not a real person?  I personally prefer a specific person
because there's no accountability with a mailing list.

> +
>  HISILICON NETWORK SUBSYSTEM DRIVER
>  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
>  M:	Salil Mehta <salil.mehta@huawei.com>
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
  2017-10-27 16:11   ` Gabriele Paoloni
  (?)
@ 2017-11-07  0:23     ` Bjorn Helgaas
  -1 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:23 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, linuxarm,
	linux-pci, minyard, john.garry, xuwei5

> PCI: remove unused __weak attribute in pci_register_io_range()

Please capitalize to follow drivers/pci convention, e.g.,

  PCI: Remove __weak attribute from pci_register_io_range()

(Also do the same for the other PCI patches.)

On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> Currently pci_register_io_range() has only one definition;
> therefore there is no use of the __weak attribute.
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> ---
>  drivers/pci/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index af0cc34..eee967c 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
>   * 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(phys_addr_t addr, resource_size_t size)
>  {
>  	int err = 0;
>  
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07  0:23     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:23 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: mark.rutland, minyard, lorenzo.pieralisi, linux-acpi, arnd,
	rafael, linux-pci, catalin.marinas, john.garry, will.deacon,
	linux-kernel, xuwei5, linuxarm, olof, robh+dt, benh, bhelgaas,
	frowand.list, brian.starkey, linux-arm-kernel

> PCI: remove unused __weak attribute in pci_register_io_range()

Please capitalize to follow drivers/pci convention, e.g.,

  PCI: Remove __weak attribute from pci_register_io_range()

(Also do the same for the other PCI patches.)

On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> Currently pci_register_io_range() has only one definition;
> therefore there is no use of the __weak attribute.
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> ---
>  drivers/pci/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index af0cc34..eee967c 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
>   * 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(phys_addr_t addr, resource_size_t size)
>  {
>  	int err = 0;
>  
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

_______________________________________________
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] 89+ messages in thread

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07  0:23     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:23 UTC (permalink / raw)
  To: linux-arm-kernel

> PCI: remove unused __weak attribute in pci_register_io_range()

Please capitalize to follow drivers/pci convention, e.g.,

  PCI: Remove __weak attribute from pci_register_io_range()

(Also do the same for the other PCI patches.)

On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> Currently pci_register_io_range() has only one definition;
> therefore there is no use of the __weak attribute.
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> ---
>  drivers/pci/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index af0cc34..eee967c 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
>   * 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(phys_addr_t addr, resource_size_t size)
>  {
>  	int err = 0;
>  
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
  2017-10-27 16:11   ` Gabriele Paoloni
  (?)
@ 2017-11-07  0:25     ` Bjorn Helgaas
  -1 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:25 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, linuxarm,
	linux-pci, minyard, john.garry, xuwei5

On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> Currently pci_register_io_range() has only one definition;
> therefore there is no use of the __weak attribute.
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Acked-by: Bjorn Helgaas <helgaas@kernel.org>

Also, I normally use this (Google address instead of kernel.org):

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

(Also affects your other PCI patches.)

> ---
>  drivers/pci/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index af0cc34..eee967c 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
>   * 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(phys_addr_t addr, resource_size_t size)
>  {
>  	int err = 0;
>  
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07  0:25     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:25 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: mark.rutland, minyard, lorenzo.pieralisi, linux-acpi, arnd,
	rafael, linux-pci, catalin.marinas, john.garry, will.deacon,
	linux-kernel, xuwei5, linuxarm, olof, robh+dt, benh, bhelgaas,
	frowand.list, brian.starkey, linux-arm-kernel

On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> Currently pci_register_io_range() has only one definition;
> therefore there is no use of the __weak attribute.
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Acked-by: Bjorn Helgaas <helgaas@kernel.org>

Also, I normally use this (Google address instead of kernel.org):

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

(Also affects your other PCI patches.)

> ---
>  drivers/pci/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index af0cc34..eee967c 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
>   * 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(phys_addr_t addr, resource_size_t size)
>  {
>  	int err = 0;
>  
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

_______________________________________________
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] 89+ messages in thread

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07  0:25     ` Bjorn Helgaas
  0 siblings, 0 replies; 89+ messages in thread
From: Bjorn Helgaas @ 2017-11-07  0:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> Currently pci_register_io_range() has only one definition;
> therefore there is no use of the __weak attribute.
> 
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Acked-by: Bjorn Helgaas <helgaas@kernel.org>

Also, I normally use this (Google address instead of kernel.org):

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

(Also affects your other PCI patches.)

> ---
>  drivers/pci/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index af0cc34..eee967c 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
>   * 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(phys_addr_t addr, resource_size_t size)
>  {
>  	int err = 0;
>  
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
  2017-11-07  0:21     ` Bjorn Helgaas
  (?)
  (?)
@ 2017-11-07 10:49       ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:49 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi

Hi Bjorn

Many Thanks for reviewing

> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:21
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon
> LPC driver
> 
> s/MANTAINERS/MAINTAINERS/

Oops thanks

> 
> On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> > Added maintainer for drivers/bus/hisi_lpc.c
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > ---
> >  MAINTAINERS | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index f66488d..b49d4c0 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
> >  F:	net/802/hippi.c
> >  F:	drivers/net/hippi/
> >
> > +HISILICON LPC BUS DRIVER
> > +L:	linuxarm@huawei.com
> > +W:	http://www.hisilicon.com
> > +S:	Maintained
> > +F:	drivers/bus/hisi_lpc.c
> > +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-
> pin-count.txt
> 
> Does this really count as a "maintainer" since it's only a mailing
> list, not a real person?  I personally prefer a specific person
> because there's no accountability with a mailing list.

Right; before the maintainer was meant to be me but as I am moving
to a different role we decided to put down a mailing list.
However after discussing internally we agreed to have a person as
maintainer and we'll specify him in the next patchset.

Cheers
Gab

> 
> > +
> >  HISILICON NETWORK SUBSYSTEM DRIVER
> >  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
> >  M:	Salil Mehta <salil.mehta@huawei.com>
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-11-07 10:49       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:49 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O)

Hi Bjorn

Many Thanks for reviewing

> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:21
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon
> LPC driver
> 
> s/MANTAINERS/MAINTAINERS/

Oops thanks

> 
> On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> > Added maintainer for drivers/bus/hisi_lpc.c
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > ---
> >  MAINTAINERS | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index f66488d..b49d4c0 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
> >  F:	net/802/hippi.c
> >  F:	drivers/net/hippi/
> >
> > +HISILICON LPC BUS DRIVER
> > +L:	linuxarm@huawei.com
> > +W:	http://www.hisilicon.com
> > +S:	Maintained
> > +F:	drivers/bus/hisi_lpc.c
> > +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-
> pin-count.txt
> 
> Does this really count as a "maintainer" since it's only a mailing
> list, not a real person?  I personally prefer a specific person
> because there's no accountability with a mailing list.

Right; before the maintainer was meant to be me but as I am moving
to a different role we decided to put down a mailing list.
However after discussing internally we agreed to have a person as
maintainer and we'll specify him in the next patchset.

Cheers
Gab

> 
> > +
> >  HISILICON NETWORK SUBSYSTEM DRIVER
> >  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
> >  M:	Salil Mehta <salil.mehta@huawei.com>
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-11-07 10:49       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:49 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O)

Hi Bjorn

Many Thanks for reviewing

> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:21
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon
> LPC driver
>=20
> s/MANTAINERS/MAINTAINERS/

Oops thanks

>=20
> On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> > Added maintainer for drivers/bus/hisi_lpc.c
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > ---
> >  MAINTAINERS | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index f66488d..b49d4c0 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
> >  F:	net/802/hippi.c
> >  F:	drivers/net/hippi/
> >
> > +HISILICON LPC BUS DRIVER
> > +L:	linuxarm@huawei.com
> > +W:	http://www.hisilicon.com
> > +S:	Maintained
> > +F:	drivers/bus/hisi_lpc.c
> > +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-
> pin-count.txt
>=20
> Does this really count as a "maintainer" since it's only a mailing
> list, not a real person?  I personally prefer a specific person
> because there's no accountability with a mailing list.

Right; before the maintainer was meant to be me but as I am moving
to a different role we decided to put down a mailing list.
However after discussing internally we agreed to have a person as
maintainer and we'll specify him in the next patchset.

Cheers
Gab

>=20
> > +
> >  HISILICON NETWORK SUBSYSTEM DRIVER
> >  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
> >  M:	Salil Mehta <salil.mehta@huawei.com>
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver
@ 2017-11-07 10:49       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Bjorn

Many Thanks for reviewing

> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas at kernel.org]
> Sent: 07 November 2017 00:21
> To: Gabriele Paoloni
> Cc: catalin.marinas at arm.com; will.deacon at arm.com; robh+dt at kernel.org;
> frowand.list at gmail.com; bhelgaas at google.com; rafael at kernel.org;
> arnd at arndb.de; linux-arm-kernel at lists.infradead.org;
> lorenzo.pieralisi at arm.com; mark.rutland at arm.com; brian.starkey at arm.com;
> olof at lixom.net; benh at kernel.crashing.org; linux-kernel at vger.kernel.org;
> linux-acpi at vger.kernel.org; Linuxarm; linux-pci at vger.kernel.org;
> minyard at acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon
> LPC driver
> 
> s/MANTAINERS/MAINTAINERS/

Oops thanks

> 
> On Fri, Oct 27, 2017 at 05:11:27PM +0100, Gabriele Paoloni wrote:
> > Added maintainer for drivers/bus/hisi_lpc.c
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > ---
> >  MAINTAINERS | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index f66488d..b49d4c0 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6130,6 +6130,13 @@ F:	include/uapi/linux/if_hippi.h
> >  F:	net/802/hippi.c
> >  F:	drivers/net/hippi/
> >
> > +HISILICON LPC BUS DRIVER
> > +L:	linuxarm at huawei.com
> > +W:	http://www.hisilicon.com
> > +S:	Maintained
> > +F:	drivers/bus/hisi_lpc.c
> > +F:	Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-
> pin-count.txt
> 
> Does this really count as a "maintainer" since it's only a mailing
> list, not a real person?  I personally prefer a specific person
> because there's no accountability with a mailing list.

Right; before the maintainer was meant to be me but as I am moving
to a different role we decided to put down a mailing list.
However after discussing internally we agreed to have a person as
maintainer and we'll specify him in the next patchset.

Cheers
Gab

> 
> > +
> >  HISILICON NETWORK SUBSYSTEM DRIVER
> >  M:	Yisen Zhuang <yisen.zhuang@huawei.com>
> >  M:	Salil Mehta <salil.mehta@huawei.com>
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
  2017-11-07  0:25     ` Bjorn Helgaas
  (?)
  (?)
@ 2017-11-07 10:50       ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:25
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
> 
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> 
> Also, I normally use this (Google address instead of kernel.org):
> 
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> 
> (Also affects your other PCI patches.)

Ok no probs, we'll change all the Acked-by in the next patchset

Many Thanks
Gab 

> 
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err = 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07 10:50       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O)



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:25
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
> 
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> 
> Also, I normally use this (Google address instead of kernel.org):
> 
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> 
> (Also affects your other PCI patches.)

Ok no probs, we'll change all the Acked-by in the next patchset

Many Thanks
Gab 

> 
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err = 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07 10:50       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O)



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:25
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
>=20
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
>=20
> Also, I normally use this (Google address instead of kernel.org):
>=20
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
>=20
> (Also affects your other PCI patches.)

Ok no probs, we'll change all the Acked-by in the next patchset

Many Thanks
Gab=20

>=20
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err =3D 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07 10:50       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: linux-arm-kernel



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas at kernel.org]
> Sent: 07 November 2017 00:25
> To: Gabriele Paoloni
> Cc: catalin.marinas at arm.com; will.deacon at arm.com; robh+dt at kernel.org;
> frowand.list at gmail.com; bhelgaas at google.com; rafael at kernel.org;
> arnd at arndb.de; linux-arm-kernel at lists.infradead.org;
> lorenzo.pieralisi at arm.com; mark.rutland at arm.com; brian.starkey at arm.com;
> olof at lixom.net; benh at kernel.crashing.org; linux-kernel at vger.kernel.org;
> linux-acpi at vger.kernel.org; Linuxarm; linux-pci at vger.kernel.org;
> minyard at acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
> 
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> 
> Also, I normally use this (Google address instead of kernel.org):
> 
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> 
> (Also affects your other PCI patches.)

Ok no probs, we'll change all the Acked-by in the next patchset

Many Thanks
Gab 

> 
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err = 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
  2017-11-07  0:23     ` Bjorn Helgaas
  (?)
  (?)
@ 2017-11-07 10:50       ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:23
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
> 
> > PCI: remove unused __weak attribute in pci_register_io_range()
> 
> Please capitalize to follow drivers/pci convention, e.g.,
> 
>   PCI: Remove __weak attribute from pci_register_io_range()
> 
> (Also do the same for the other PCI patches.)

Agreed, many thanks

Gab

> 
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err = 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07 10:50       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O)



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:23
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
> 
> > PCI: remove unused __weak attribute in pci_register_io_range()
> 
> Please capitalize to follow drivers/pci convention, e.g.,
> 
>   PCI: Remove __weak attribute from pci_register_io_range()
> 
> (Also do the same for the other PCI patches.)

Agreed, many thanks

Gab

> 
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err = 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07 10:50       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O)



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 07 November 2017 00:23
> To: Gabriele Paoloni
> Cc: catalin.marinas@arm.com; will.deacon@arm.com; robh+dt@kernel.org;
> frowand.list@gmail.com; bhelgaas@google.com; rafael@kernel.org;
> arnd@arndb.de; linux-arm-kernel@lists.infradead.org;
> lorenzo.pieralisi@arm.com; mark.rutland@arm.com; brian.starkey@arm.com;
> olof@lixom.net; benh@kernel.crashing.org; linux-kernel@vger.kernel.org;
> linux-acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org;
> minyard@acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
>=20
> > PCI: remove unused __weak attribute in pci_register_io_range()
>=20
> Please capitalize to follow drivers/pci convention, e.g.,
>=20
>   PCI: Remove __weak attribute from pci_register_io_range()
>=20
> (Also do the same for the other PCI patches.)

Agreed, many thanks

Gab

>=20
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err =3D 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range()
@ 2017-11-07 10:50       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-07 10:50 UTC (permalink / raw)
  To: linux-arm-kernel



> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas at kernel.org]
> Sent: 07 November 2017 00:23
> To: Gabriele Paoloni
> Cc: catalin.marinas at arm.com; will.deacon at arm.com; robh+dt at kernel.org;
> frowand.list at gmail.com; bhelgaas at google.com; rafael at kernel.org;
> arnd at arndb.de; linux-arm-kernel at lists.infradead.org;
> lorenzo.pieralisi at arm.com; mark.rutland at arm.com; brian.starkey at arm.com;
> olof at lixom.net; benh at kernel.crashing.org; linux-kernel at vger.kernel.org;
> linux-acpi at vger.kernel.org; Linuxarm; linux-pci at vger.kernel.org;
> minyard at acm.org; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 2/9] PCI: remove unused __weak attribute in
> pci_register_io_range()
> 
> > PCI: remove unused __weak attribute in pci_register_io_range()
> 
> Please capitalize to follow drivers/pci convention, e.g.,
> 
>   PCI: Remove __weak attribute from pci_register_io_range()
> 
> (Also do the same for the other PCI patches.)

Agreed, many thanks

Gab

> 
> On Fri, Oct 27, 2017 at 05:11:20PM +0100, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > Currently pci_register_io_range() has only one definition;
> > therefore there is no use of the __weak attribute.
> >
> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> > Acked-by: Bjorn Helgaas <helgaas@kernel.org>
> > ---
> >  drivers/pci/pci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index af0cc34..eee967c 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -3270,7 +3270,7 @@ static DEFINE_SPINLOCK(io_range_lock);
> >   * 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(phys_addr_t addr, resource_size_t size)
> >  {
> >  	int err = 0;
> >
> > --
> > 2.7.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi"
> in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  2017-10-27 16:11   ` Gabriele Paoloni
  (?)
@ 2017-11-09  0:46     ` dann frazier
  -1 siblings, 0 replies; 89+ messages in thread
From: dann frazier @ 2017-11-09  0:46 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, linuxarm,
	linux-pci, minyard, john.garry, xuwei5, zhichang.yuan

On Fri, Oct 27, 2017 at 05:11:24PM +0100, Gabriele Paoloni wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
> 
> 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: Zou Rongrong <zourongrong@huawei.com>
> 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 ++
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 526 +++++++++++++++++++++
>  4 files changed, 569 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/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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..c885483
> --- /dev/null
> +++ b/drivers/bus/hisi_lpc.c
> @@ -0,0 +1,526 @@
> +/*
> + * 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/slab.h>
> +
> +#define LPC_MIN_BUS_RANGE	0x0
> +
> +/*
> + * The default maximal IO size for Hip06/Hip07 LPC bus.
> + * Defining the I/O range size as 0x4000 here should be sufficient for
> + * all peripherals under the bus.
> + */
> +#define LPC_BUS_IO_SIZE		0x4000
> +
> +/*
> + * 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

Any reason not to put this in the LPC_ namespace as well?

> +/* 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

It's now lpcdev

> + * @para: some parameters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the read back data is stored
> + * @opcnt: how many I/O operations required in this calling
> + *
> + * Only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + */
> +static int
> +hisilpc_target_in(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
> +		  unsigned long ptaddr, unsigned char *buf,
> +		  unsigned long opcnt)
> +{
> +	unsigned long cnt_per_trans;
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int ret;
> +
> +	if (!buf || !opcnt || !para || !para->csize || !lpcdev)
> +		return -EINVAL;
> +
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
> +	waitcnt = LPC_PEROP_WAITCNT;
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	ret = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !ret; cnt_per_trans = para->csize) {
> +		unsigned long flags;
> +
> +		/* whole operation must be atomic */
> +		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
> +
> +		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
> +
> +		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
> +
> +		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
> +
> +		writel(START_WORK, lpcdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
> +		if (!ret) {
> +			opcnt -= cnt_per_trans;
> +			for (cnt_per_trans--; cnt_per_trans--; buf++)
> +				*buf = readb_relaxed(lpcdev->membase +
> +					LPC_REG_RDATA);
> +			*buf = readb(lpcdev->membase + LPC_REG_RDATA);
> +		}
> +
> +		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * hisilpc_target_out - trigger a series of lpc cycles to write required
> + *			data to target peripheral.
> + * @pdev: pointer to hisi lpc device
> + * @para: some parameters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the data to be written is stored
> + * @opcnt: how many I/O operations required
> + *
> + * Only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + *
> + */
> +static int
> +hisilpc_target_out(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
> +		   unsigned long ptaddr, const unsigned char *buf,
> +		   unsigned long opcnt)
> +{
> +	unsigned long cnt_per_trans;
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int ret;
> +
> +	if (!buf || !opcnt || !para || !lpcdev)
> +		return -EINVAL;
> +
> +	/* default is increasing address */
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
> +	waitcnt = LPC_PEROP_WAITCNT;
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	ret = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !ret; cnt_per_trans = para->csize) {
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
> +
> +		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
> +		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
> +		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
> +
> +		opcnt -= cnt_per_trans;
> +		for (; cnt_per_trans--; buf++)
> +			writeb_relaxed(*buf, lpcdev->membase + LPC_REG_WDATA);
> +
> +		writel(START_WORK, lpcdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
> +
> +		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
> +	}
> +
> +	return ret;
> +}
> +
> +static inline unsigned long
> +hisi_lpc_pio_to_addr(struct hisilpc_dev *lpcdev, unsigned long pio)
> +{
> +	return pio - lpcdev->io_host->io_start +
> +		lpcdev->io_host->hw_start;
> +}
> +
> +
> +/**
> + * hisilpc_comm_in - read/input the data from the I/O peripheral
> + *		     through LPC.
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @pio: the target I/O port address.
> + * @dlen: the data length required to read from the target I/O port.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * For inb, return the data read from I/O or -1 when error occur.
> + */
> +static u32 hisilpc_comm_in(void *devobj, unsigned long pio, size_t dlen)
> +{
> +	int ret = 0;
> +	unsigned char rd_data = 0;
> +	unsigned long ptaddr;
> +	struct lpc_cycle_para iopara;
> +	struct hisilpc_dev *lpcdev = devobj;
> +
> +	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
> +		return -1;
> +
> +	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
> +
> +	iopara.opflags = FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, &rd_data, dlen);
> +	if (ret)
> +		return -1;
> +
> +	return le32_to_cpu((u32)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.

@outval & @pio are in the opposite order of the actual function

> + * @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.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * Returns 0 on success, -errno otherwise
> + *
> + */
> +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 = inbuf;
> +	/*
> +	 * ensure data stream whose length is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	cntleft = count * dlen;
> +	do {
> +		int ret;
> +
> +		loopcnt = min_t(unsigned int, 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 = outbuf;
> +	/*
> +	 * ensure data stream whose length is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	cntleft = count * dlen;
> +	do {
> +		loopcnt = min_t(unsigned int, 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;
> +	struct logic_pio_hwaddr *range;
> +	int ret = 0;
> +
> +	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 */
> +	range = devm_kzalloc(dev, 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;
> +
> +	ret = logic_pio_register_range(range);
> +	if (ret) {
> +		kfree(range);
> +		dev_err(dev, "OF: register IO range FAIL!\n");
> +		return -ret;
> +	}
> +	lpcdev->io_host = range;
> +	lpcdev->io_host->devpara = lpcdev;
> +	lpcdev->io_host->ops = &hisi_lpc_ops;
> +
> +	/*
> +	 * 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.
> +	 */
> +	dev_info(dev, " calling of_platform_populate");
> +	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
> +	if (ret) {
> +		/*
> +		 * When LPC probing is not completely successful, set 'devpara'
> +		 * as NULL. This will make all the LPC I/O return failure
> +		 * directly without any hardware operations. It will prevent
> +		 * some peripherals which had not finished the initialization to
> +		 * manipulate I/O for safety.
> +		 */
> +		lpcdev->io_host->devpara = NULL;
> +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> +			ret);

nit: Maybe "OF: scanning hisilpc children failed(%d)" ?

> +		return ret;
> +	}
> +
> +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> +		&lpcdev->io_host->io_start,
> +		&lpcdev->io_host->size);
> +
> +	return ret;
> +}


 -dann

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

* Re: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-11-09  0:46     ` dann frazier
  0 siblings, 0 replies; 89+ messages in thread
From: dann frazier @ 2017-11-09  0:46 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: mark.rutland, minyard, lorenzo.pieralisi, linux-acpi, arnd,
	rafael, linux-pci, catalin.marinas, john.garry, will.deacon,
	linux-kernel, xuwei5, linuxarm, olof, robh+dt, zhichang.yuan,
	benh, bhelgaas, frowand.list, brian.starkey, linux-arm-kernel

On Fri, Oct 27, 2017 at 05:11:24PM +0100, Gabriele Paoloni wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
> 
> 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: Zou Rongrong <zourongrong@huawei.com>
> 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 ++
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 526 +++++++++++++++++++++
>  4 files changed, 569 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/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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..c885483
> --- /dev/null
> +++ b/drivers/bus/hisi_lpc.c
> @@ -0,0 +1,526 @@
> +/*
> + * 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/slab.h>
> +
> +#define LPC_MIN_BUS_RANGE	0x0
> +
> +/*
> + * The default maximal IO size for Hip06/Hip07 LPC bus.
> + * Defining the I/O range size as 0x4000 here should be sufficient for
> + * all peripherals under the bus.
> + */
> +#define LPC_BUS_IO_SIZE		0x4000
> +
> +/*
> + * 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

Any reason not to put this in the LPC_ namespace as well?

> +/* 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

It's now lpcdev

> + * @para: some parameters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the read back data is stored
> + * @opcnt: how many I/O operations required in this calling
> + *
> + * Only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + */
> +static int
> +hisilpc_target_in(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
> +		  unsigned long ptaddr, unsigned char *buf,
> +		  unsigned long opcnt)
> +{
> +	unsigned long cnt_per_trans;
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int ret;
> +
> +	if (!buf || !opcnt || !para || !para->csize || !lpcdev)
> +		return -EINVAL;
> +
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
> +	waitcnt = LPC_PEROP_WAITCNT;
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	ret = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !ret; cnt_per_trans = para->csize) {
> +		unsigned long flags;
> +
> +		/* whole operation must be atomic */
> +		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
> +
> +		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
> +
> +		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
> +
> +		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
> +
> +		writel(START_WORK, lpcdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
> +		if (!ret) {
> +			opcnt -= cnt_per_trans;
> +			for (cnt_per_trans--; cnt_per_trans--; buf++)
> +				*buf = readb_relaxed(lpcdev->membase +
> +					LPC_REG_RDATA);
> +			*buf = readb(lpcdev->membase + LPC_REG_RDATA);
> +		}
> +
> +		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * hisilpc_target_out - trigger a series of lpc cycles to write required
> + *			data to target peripheral.
> + * @pdev: pointer to hisi lpc device
> + * @para: some parameters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the data to be written is stored
> + * @opcnt: how many I/O operations required
> + *
> + * Only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + *
> + */
> +static int
> +hisilpc_target_out(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
> +		   unsigned long ptaddr, const unsigned char *buf,
> +		   unsigned long opcnt)
> +{
> +	unsigned long cnt_per_trans;
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int ret;
> +
> +	if (!buf || !opcnt || !para || !lpcdev)
> +		return -EINVAL;
> +
> +	/* default is increasing address */
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
> +	waitcnt = LPC_PEROP_WAITCNT;
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	ret = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !ret; cnt_per_trans = para->csize) {
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
> +
> +		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
> +		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
> +		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
> +
> +		opcnt -= cnt_per_trans;
> +		for (; cnt_per_trans--; buf++)
> +			writeb_relaxed(*buf, lpcdev->membase + LPC_REG_WDATA);
> +
> +		writel(START_WORK, lpcdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
> +
> +		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
> +	}
> +
> +	return ret;
> +}
> +
> +static inline unsigned long
> +hisi_lpc_pio_to_addr(struct hisilpc_dev *lpcdev, unsigned long pio)
> +{
> +	return pio - lpcdev->io_host->io_start +
> +		lpcdev->io_host->hw_start;
> +}
> +
> +
> +/**
> + * hisilpc_comm_in - read/input the data from the I/O peripheral
> + *		     through LPC.
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @pio: the target I/O port address.
> + * @dlen: the data length required to read from the target I/O port.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * For inb, return the data read from I/O or -1 when error occur.
> + */
> +static u32 hisilpc_comm_in(void *devobj, unsigned long pio, size_t dlen)
> +{
> +	int ret = 0;
> +	unsigned char rd_data = 0;
> +	unsigned long ptaddr;
> +	struct lpc_cycle_para iopara;
> +	struct hisilpc_dev *lpcdev = devobj;
> +
> +	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
> +		return -1;
> +
> +	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
> +
> +	iopara.opflags = FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, &rd_data, dlen);
> +	if (ret)
> +		return -1;
> +
> +	return le32_to_cpu((u32)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.

@outval & @pio are in the opposite order of the actual function

> + * @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.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * Returns 0 on success, -errno otherwise
> + *
> + */
> +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 = inbuf;
> +	/*
> +	 * ensure data stream whose length is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	cntleft = count * dlen;
> +	do {
> +		int ret;
> +
> +		loopcnt = min_t(unsigned int, 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 = outbuf;
> +	/*
> +	 * ensure data stream whose length is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	cntleft = count * dlen;
> +	do {
> +		loopcnt = min_t(unsigned int, 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;
> +	struct logic_pio_hwaddr *range;
> +	int ret = 0;
> +
> +	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 */
> +	range = devm_kzalloc(dev, 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;
> +
> +	ret = logic_pio_register_range(range);
> +	if (ret) {
> +		kfree(range);
> +		dev_err(dev, "OF: register IO range FAIL!\n");
> +		return -ret;
> +	}
> +	lpcdev->io_host = range;
> +	lpcdev->io_host->devpara = lpcdev;
> +	lpcdev->io_host->ops = &hisi_lpc_ops;
> +
> +	/*
> +	 * 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.
> +	 */
> +	dev_info(dev, " calling of_platform_populate");
> +	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
> +	if (ret) {
> +		/*
> +		 * When LPC probing is not completely successful, set 'devpara'
> +		 * as NULL. This will make all the LPC I/O return failure
> +		 * directly without any hardware operations. It will prevent
> +		 * some peripherals which had not finished the initialization to
> +		 * manipulate I/O for safety.
> +		 */
> +		lpcdev->io_host->devpara = NULL;
> +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> +			ret);

nit: Maybe "OF: scanning hisilpc children failed(%d)" ?

> +		return ret;
> +	}
> +
> +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> +		&lpcdev->io_host->io_start,
> +		&lpcdev->io_host->size);
> +
> +	return ret;
> +}


 -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] 89+ messages in thread

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-11-09  0:46     ` dann frazier
  0 siblings, 0 replies; 89+ messages in thread
From: dann frazier @ 2017-11-09  0:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 27, 2017 at 05:11:24PM +0100, Gabriele Paoloni wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
> 
> 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: Zou Rongrong <zourongrong@huawei.com>
> 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 ++
>  drivers/bus/Kconfig                                |   9 +
>  drivers/bus/Makefile                               |   1 +
>  drivers/bus/hisi_lpc.c                             | 526 +++++++++++++++++++++
>  4 files changed, 569 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/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 2408ea3..358eed3 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..c885483
> --- /dev/null
> +++ b/drivers/bus/hisi_lpc.c
> @@ -0,0 +1,526 @@
> +/*
> + * 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/slab.h>
> +
> +#define LPC_MIN_BUS_RANGE	0x0
> +
> +/*
> + * The default maximal IO size for Hip06/Hip07 LPC bus.
> + * Defining the I/O range size as 0x4000 here should be sufficient for
> + * all peripherals under the bus.
> + */
> +#define LPC_BUS_IO_SIZE		0x4000
> +
> +/*
> + * 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

Any reason not to put this in the LPC_ namespace as well?

> +/* 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

It's now lpcdev

> + * @para: some parameters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the read back data is stored
> + * @opcnt: how many I/O operations required in this calling
> + *
> + * Only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + */
> +static int
> +hisilpc_target_in(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
> +		  unsigned long ptaddr, unsigned char *buf,
> +		  unsigned long opcnt)
> +{
> +	unsigned long cnt_per_trans;
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int ret;
> +
> +	if (!buf || !opcnt || !para || !para->csize || !lpcdev)
> +		return -EINVAL;
> +
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
> +	waitcnt = LPC_PEROP_WAITCNT;
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	ret = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !ret; cnt_per_trans = para->csize) {
> +		unsigned long flags;
> +
> +		/* whole operation must be atomic */
> +		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
> +
> +		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
> +
> +		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
> +
> +		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
> +
> +		writel(START_WORK, lpcdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
> +		if (!ret) {
> +			opcnt -= cnt_per_trans;
> +			for (cnt_per_trans--; cnt_per_trans--; buf++)
> +				*buf = readb_relaxed(lpcdev->membase +
> +					LPC_REG_RDATA);
> +			*buf = readb(lpcdev->membase + LPC_REG_RDATA);
> +		}
> +
> +		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * hisilpc_target_out - trigger a series of lpc cycles to write required
> + *			data to target peripheral.
> + * @pdev: pointer to hisi lpc device
> + * @para: some parameters used to control the lpc I/O operations
> + * @ptaddr: the lpc I/O target port address
> + * @buf: where the data to be written is stored
> + * @opcnt: how many I/O operations required
> + *
> + * Only one byte data is read each I/O operation.
> + *
> + * Returns 0 on success, non-zero on fail.
> + *
> + */
> +static int
> +hisilpc_target_out(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para,
> +		   unsigned long ptaddr, const unsigned char *buf,
> +		   unsigned long opcnt)
> +{
> +	unsigned long cnt_per_trans;
> +	unsigned int cmd_word;
> +	unsigned int waitcnt;
> +	int ret;
> +
> +	if (!buf || !opcnt || !para || !lpcdev)
> +		return -EINVAL;
> +
> +	/* default is increasing address */
> +	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
> +	waitcnt = LPC_PEROP_WAITCNT;
> +	if (!(para->opflags & FG_INCRADDR_LPC)) {
> +		cmd_word |= LPC_CMD_SAMEADDR;
> +		waitcnt = LPC_MAX_WAITCNT;
> +	}
> +
> +	ret = 0;
> +	cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
> +	for (; opcnt && !ret; cnt_per_trans = para->csize) {
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&lpcdev->cycle_lock, flags);
> +
> +		writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN);
> +		writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD);
> +		writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR);
> +
> +		opcnt -= cnt_per_trans;
> +		for (; cnt_per_trans--; buf++)
> +			writeb_relaxed(*buf, lpcdev->membase + LPC_REG_WDATA);
> +
> +		writel(START_WORK, lpcdev->membase + LPC_REG_START);
> +
> +		/* whether the operation is finished */
> +		ret = wait_lpc_idle(lpcdev->membase, waitcnt);
> +
> +		spin_unlock_irqrestore(&lpcdev->cycle_lock, flags);
> +	}
> +
> +	return ret;
> +}
> +
> +static inline unsigned long
> +hisi_lpc_pio_to_addr(struct hisilpc_dev *lpcdev, unsigned long pio)
> +{
> +	return pio - lpcdev->io_host->io_start +
> +		lpcdev->io_host->hw_start;
> +}
> +
> +
> +/**
> + * hisilpc_comm_in - read/input the data from the I/O peripheral
> + *		     through LPC.
> + * @devobj: pointer to the device information relevant to LPC controller.
> + * @pio: the target I/O port address.
> + * @dlen: the data length required to read from the target I/O port.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * For inb, return the data read from I/O or -1 when error occur.
> + */
> +static u32 hisilpc_comm_in(void *devobj, unsigned long pio, size_t dlen)
> +{
> +	int ret = 0;
> +	unsigned char rd_data = 0;
> +	unsigned long ptaddr;
> +	struct lpc_cycle_para iopara;
> +	struct hisilpc_dev *lpcdev = devobj;
> +
> +	if (!lpcdev || !dlen || dlen > LPC_MAX_DULEN)
> +		return -1;
> +
> +	ptaddr = hisi_lpc_pio_to_addr(lpcdev, pio);
> +
> +	iopara.opflags = FG_INCRADDR_LPC;
> +	iopara.csize = dlen;
> +
> +	ret = hisilpc_target_in(lpcdev, &iopara, ptaddr, &rd_data, dlen);
> +	if (ret)
> +		return -1;
> +
> +	return le32_to_cpu((u32)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.

@outval & @pio are in the opposite order of the actual function

> + * @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.
> + *
> + * when succeed, the data read back is stored in buffer pointed by inbuf.
> + * Returns 0 on success, -errno otherwise
> + *
> + */
> +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 = inbuf;
> +	/*
> +	 * ensure data stream whose length is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	cntleft = count * dlen;
> +	do {
> +		int ret;
> +
> +		loopcnt = min_t(unsigned int, 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 = outbuf;
> +	/*
> +	 * ensure data stream whose length is multiple of dlen to be processed
> +	 * each IO input
> +	 */
> +	cntleft = count * dlen;
> +	do {
> +		loopcnt = min_t(unsigned int, 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;
> +	struct logic_pio_hwaddr *range;
> +	int ret = 0;
> +
> +	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 */
> +	range = devm_kzalloc(dev, 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;
> +
> +	ret = logic_pio_register_range(range);
> +	if (ret) {
> +		kfree(range);
> +		dev_err(dev, "OF: register IO range FAIL!\n");
> +		return -ret;
> +	}
> +	lpcdev->io_host = range;
> +	lpcdev->io_host->devpara = lpcdev;
> +	lpcdev->io_host->ops = &hisi_lpc_ops;
> +
> +	/*
> +	 * 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.
> +	 */
> +	dev_info(dev, " calling of_platform_populate");
> +	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
> +	if (ret) {
> +		/*
> +		 * When LPC probing is not completely successful, set 'devpara'
> +		 * as NULL. This will make all the LPC I/O return failure
> +		 * directly without any hardware operations. It will prevent
> +		 * some peripherals which had not finished the initialization to
> +		 * manipulate I/O for safety.
> +		 */
> +		lpcdev->io_host->devpara = NULL;
> +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> +			ret);

nit: Maybe "OF: scanning hisilpc children failed(%d)" ?

> +		return ret;
> +	}
> +
> +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> +		&lpcdev->io_host->io_start,
> +		&lpcdev->io_host->size);
> +
> +	return ret;
> +}


 -dann

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

* RE: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
  2017-11-09  0:46     ` dann frazier
  (?)
  (?)
@ 2017-11-09 10:05       ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 10:05 UTC (permalink / raw)
  To: dann frazier
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi


Hi Dann

[...]

> > +
> > +#define START_WORK		0x01
> 
> Any reason not to put this in the LPC_ namespace as well?

No, not really. We'll make it consistent in the next patchset 

> 
> > +/* The minimal nanosecond interval for each query on LPC cycle
> status. */

[...]

> > + * hisilpc_target_in - trigger a series of lpc cycles to read
> required data
> > + *		       from target peripheral.
> > + * @pdev: pointer to hisi lpc device
> 
> It's now lpcdev
> 

Thanks, we'll change it.

> > + * @para: some parameters used to control the lpc I/O operations

[...]

> > + * @pio: the target I/O port address.
> 
> @outval & @pio are in the opposite order of the actual function

Thanks, we'll change it.

> 

[...]

> > +		lpcdev->io_host->devpara = NULL;
> > +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> > +			ret);
> 
> nit: Maybe "OF: scanning hisilpc children failed(%d)" ?
> 

Yes, thanks we'll change it.

> > +		return ret;
> > +	}
> > +
> > +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> > +		&lpcdev->io_host->io_start,
> > +		&lpcdev->io_host->size);
> > +
> > +	return ret;
> > +}
> 
> 
>  -dann

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

* RE: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-11-09 10:05       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 10:05 UTC (permalink / raw)
  To: dann frazier
  Cc: catalin.marinas, will.deacon, robh+dt, frowand.list, bhelgaas,
	rafael, arnd, linux-arm-kernel, lorenzo.pieralisi, mark.rutland,
	brian.starkey, olof, benh, linux-kernel, linux-acpi, Linuxarm,
	linux-pci, minyard, John Garry, xuwei (O),
	zhichang.yuan


Hi Dann

[...]

> > +
> > +#define START_WORK		0x01
> 
> Any reason not to put this in the LPC_ namespace as well?

No, not really. We'll make it consistent in the next patchset 

> 
> > +/* The minimal nanosecond interval for each query on LPC cycle
> status. */

[...]

> > + * hisilpc_target_in - trigger a series of lpc cycles to read
> required data
> > + *		       from target peripheral.
> > + * @pdev: pointer to hisi lpc device
> 
> It's now lpcdev
> 

Thanks, we'll change it.

> > + * @para: some parameters used to control the lpc I/O operations

[...]

> > + * @pio: the target I/O port address.
> 
> @outval & @pio are in the opposite order of the actual function

Thanks, we'll change it.

> 

[...]

> > +		lpcdev->io_host->devpara = NULL;
> > +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> > +			ret);
> 
> nit: Maybe "OF: scanning hisilpc children failed(%d)" ?
> 

Yes, thanks we'll change it.

> > +		return ret;
> > +	}
> > +
> > +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> > +		&lpcdev->io_host->io_start,
> > +		&lpcdev->io_host->size);
> > +
> > +	return ret;
> > +}
> 
> 
>  -dann

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

* RE: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-11-09 10:05       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 10:05 UTC (permalink / raw)
  To: dann frazier
  Cc: mark.rutland, minyard, lorenzo.pieralisi, linux-acpi, arnd,
	rafael, linux-pci, catalin.marinas, John Garry, will.deacon,
	linux-kernel, xuwei (O),
	Linuxarm, olof, robh+dt, zhichang.yuan, benh, bhelgaas,
	frowand.list, brian.starkey, linux-arm-kernel


Hi Dann

[...]

> > +
> > +#define START_WORK		0x01
> 
> Any reason not to put this in the LPC_ namespace as well?

No, not really. We'll make it consistent in the next patchset 

> 
> > +/* The minimal nanosecond interval for each query on LPC cycle
> status. */

[...]

> > + * hisilpc_target_in - trigger a series of lpc cycles to read
> required data
> > + *		       from target peripheral.
> > + * @pdev: pointer to hisi lpc device
> 
> It's now lpcdev
> 

Thanks, we'll change it.

> > + * @para: some parameters used to control the lpc I/O operations

[...]

> > + * @pio: the target I/O port address.
> 
> @outval & @pio are in the opposite order of the actual function

Thanks, we'll change it.

> 

[...]

> > +		lpcdev->io_host->devpara = NULL;
> > +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> > +			ret);
> 
> nit: Maybe "OF: scanning hisilpc children failed(%d)" ?
> 

Yes, thanks we'll change it.

> > +		return ret;
> > +	}
> > +
> > +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> > +		&lpcdev->io_host->io_start,
> > +		&lpcdev->io_host->size);
> > +
> > +	return ret;
> > +}
> 
> 
>  -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] 89+ messages in thread

* [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
@ 2017-11-09 10:05       ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 10:05 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Dann

[...]

> > +
> > +#define START_WORK		0x01
> 
> Any reason not to put this in the LPC_ namespace as well?

No, not really. We'll make it consistent in the next patchset 

> 
> > +/* The minimal nanosecond interval for each query on LPC cycle
> status. */

[...]

> > + * hisilpc_target_in - trigger a series of lpc cycles to read
> required data
> > + *		       from target peripheral.
> > + * @pdev: pointer to hisi lpc device
> 
> It's now lpcdev
> 

Thanks, we'll change it.

> > + * @para: some parameters used to control the lpc I/O operations

[...]

> > + * @pio: the target I/O port address.
> 
> @outval & @pio are in the opposite order of the actual function

Thanks, we'll change it.

> 

[...]

> > +		lpcdev->io_host->devpara = NULL;
> > +		dev_err(dev, "OF: scan hisilpc children got failed(%d)\n",
> > +			ret);
> 
> nit: Maybe "OF: scanning hisilpc children failed(%d)" ?
> 

Yes, thanks we'll change it.

> > +		return ret;
> > +	}
> > +
> > +	dev_info(dev, "hslpc end probing. range[%pa - sz:%pa]\n",
> > +		&lpcdev->io_host->io_start,
> > +		&lpcdev->io_host->size);
> > +
> > +	return ret;
> > +}
> 
> 
>  -dann

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

* Re: [PATCH v10 0/9] LPC: legacy ISA I/O support
  2017-10-27 16:11 ` Gabriele Paoloni
  (?)
@ 2017-11-09 16:16   ` dann frazier
  -1 siblings, 0 replies; 89+ messages in thread
From: dann frazier @ 2017-11-09 16:16 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	lorenzo.pieralisi, Mark Rutland, Brian Starkey, olof, benh,
	linux-kernel, linux-acpi, linuxarm, linux-pci, Corey Minyard,
	John Garry, xuwei5

On Fri, Oct 27, 2017 at 10:11 AM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
>
> This patchset supports the IPMI-bt device attached to the Low-Pin-Count
> interface implemented on Hisilicon Hip06/Hip07 SoC.

fwiw, I tested this on one of our D05 boards and verified that the
IPMI SI worked fine.

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

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

* Re: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-11-09 16:16   ` dann frazier
  0 siblings, 0 replies; 89+ messages in thread
From: dann frazier @ 2017-11-09 16:16 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: Mark Rutland, Corey Minyard, lorenzo.pieralisi, linux-acpi,
	Arnd Bergmann, rafael, linux-pci, Catalin Marinas, John Garry,
	Will Deacon, linux-kernel, xuwei5, linuxarm, olof, Rob Herring,
	benh, Bjorn Helgaas, Frank Rowand, Brian Starkey,
	linux-arm-kernel

On Fri, Oct 27, 2017 at 10:11 AM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
>
> This patchset supports the IPMI-bt device attached to the Low-Pin-Count
> interface implemented on Hisilicon Hip06/Hip07 SoC.

fwiw, I tested this on one of our D05 boards and verified that the
IPMI SI worked fine.

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] 89+ messages in thread

* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-11-09 16:16   ` dann frazier
  0 siblings, 0 replies; 89+ messages in thread
From: dann frazier @ 2017-11-09 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 27, 2017 at 10:11 AM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
>
> This patchset supports the IPMI-bt device attached to the Low-Pin-Count
> interface implemented on Hisilicon Hip06/Hip07 SoC.

fwiw, I tested this on one of our D05 boards and verified that the
IPMI SI worked fine.

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

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
  2017-11-09 16:16   ` dann frazier
  (?)
  (?)
@ 2017-11-09 16:18     ` Gabriele Paoloni
  -1 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 16:18 UTC (permalink / raw)
  To: dann frazier
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	lorenzo.pieralisi, Mark Rutland, Brian Starkey, olof, benh,
	linux-kernel, linux-acpi, Linuxarm, linux-pci, Corey

Hi Dann

> -----Original Message-----
> From: dann frazier [mailto:dann.frazier@canonical.com]
> Sent: 09 November 2017 16:16
> To: Gabriele Paoloni
> Cc: Catalin Marinas; Will Deacon; Rob Herring; Frank Rowand; Bjorn
> Helgaas; rafael@kernel.org; Arnd Bergmann; linux-arm-kernel;
> lorenzo.pieralisi@arm.com; Mark Rutland; Brian Starkey; olof@lixom.net;
> benh@kernel.crashing.org; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org; Corey
> Minyard; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 0/9] LPC: legacy ISA I/O support
> 
> On Fri, Oct 27, 2017 at 10:11 AM, Gabriele Paoloni
> <gabriele.paoloni@huawei.com> wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > This patchset supports the IPMI-bt device attached to the Low-Pin-
> Count
> > interface implemented on Hisilicon Hip06/Hip07 SoC.
> 
> fwiw, I tested this on one of our D05 boards and verified that the
> IPMI SI worked fine.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>

Many thanks for this
Gab

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-11-09 16:18     ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 16:18 UTC (permalink / raw)
  To: dann frazier
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	lorenzo.pieralisi, Mark Rutland, Brian Starkey, olof, benh,
	linux-kernel, linux-acpi, Linuxarm, linux-pci, Corey Minyard,
	John Garry, xuwei (O)

Hi Dann

> -----Original Message-----
> From: dann frazier [mailto:dann.frazier@canonical.com]
> Sent: 09 November 2017 16:16
> To: Gabriele Paoloni
> Cc: Catalin Marinas; Will Deacon; Rob Herring; Frank Rowand; Bjorn
> Helgaas; rafael@kernel.org; Arnd Bergmann; linux-arm-kernel;
> lorenzo.pieralisi@arm.com; Mark Rutland; Brian Starkey; olof@lixom.net;
> benh@kernel.crashing.org; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Linuxarm; linux-pci@vger.kernel.org; Corey
> Minyard; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 0/9] LPC: legacy ISA I/O support
> 
> On Fri, Oct 27, 2017 at 10:11 AM, Gabriele Paoloni
> <gabriele.paoloni@huawei.com> wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > This patchset supports the IPMI-bt device attached to the Low-Pin-
> Count
> > interface implemented on Hisilicon Hip06/Hip07 SoC.
> 
> fwiw, I tested this on one of our D05 boards and verified that the
> IPMI SI worked fine.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>

Many thanks for this
Gab

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

* RE: [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-11-09 16:18     ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 16:18 UTC (permalink / raw)
  To: dann frazier
  Cc: Catalin Marinas, Will Deacon, Rob Herring, Frank Rowand,
	Bjorn Helgaas, rafael, Arnd Bergmann, linux-arm-kernel,
	lorenzo.pieralisi, Mark Rutland, Brian Starkey, olof, benh,
	linux-kernel, linux-acpi, Linuxarm, linux-pci, Corey Minyard,
	John Garry, xuwei (O)

SGkgRGFubg0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IGRhbm4gZnJh
emllciBbbWFpbHRvOmRhbm4uZnJhemllckBjYW5vbmljYWwuY29tXQ0KPiBTZW50OiAwOSBOb3Zl
bWJlciAyMDE3IDE2OjE2DQo+IFRvOiBHYWJyaWVsZSBQYW9sb25pDQo+IENjOiBDYXRhbGluIE1h
cmluYXM7IFdpbGwgRGVhY29uOyBSb2IgSGVycmluZzsgRnJhbmsgUm93YW5kOyBCam9ybg0KPiBI
ZWxnYWFzOyByYWZhZWxAa2VybmVsLm9yZzsgQXJuZCBCZXJnbWFubjsgbGludXgtYXJtLWtlcm5l
bDsNCj4gbG9yZW56by5waWVyYWxpc2lAYXJtLmNvbTsgTWFyayBSdXRsYW5kOyBCcmlhbiBTdGFy
a2V5OyBvbG9mQGxpeG9tLm5ldDsNCj4gYmVuaEBrZXJuZWwuY3Jhc2hpbmcub3JnOyBsaW51eC1r
ZXJuZWxAdmdlci5rZXJuZWwub3JnOyBsaW51eC0NCj4gYWNwaUB2Z2VyLmtlcm5lbC5vcmc7IExp
bnV4YXJtOyBsaW51eC1wY2lAdmdlci5rZXJuZWwub3JnOyBDb3JleQ0KPiBNaW55YXJkOyBKb2hu
IEdhcnJ5OyB4dXdlaSAoTykNCj4gU3ViamVjdDogUmU6IFtQQVRDSCB2MTAgMC85XSBMUEM6IGxl
Z2FjeSBJU0EgSS9PIHN1cHBvcnQNCj4gDQo+IE9uIEZyaSwgT2N0IDI3LCAyMDE3IGF0IDEwOjEx
IEFNLCBHYWJyaWVsZSBQYW9sb25pDQo+IDxnYWJyaWVsZS5wYW9sb25pQGh1YXdlaS5jb20+IHdy
b3RlOg0KPiA+IEZyb206IGdhYnJpZWxlIHBhb2xvbmkgPGdhYnJpZWxlLnBhb2xvbmlAaHVhd2Vp
LmNvbT4NCj4gPg0KPiA+IFRoaXMgcGF0Y2hzZXQgc3VwcG9ydHMgdGhlIElQTUktYnQgZGV2aWNl
IGF0dGFjaGVkIHRvIHRoZSBMb3ctUGluLQ0KPiBDb3VudA0KPiA+IGludGVyZmFjZSBpbXBsZW1l
bnRlZCBvbiBIaXNpbGljb24gSGlwMDYvSGlwMDcgU29DLg0KPiANCj4gZndpdywgSSB0ZXN0ZWQg
dGhpcyBvbiBvbmUgb2Ygb3VyIEQwNSBib2FyZHMgYW5kIHZlcmlmaWVkIHRoYXQgdGhlDQo+IElQ
TUkgU0kgd29ya2VkIGZpbmUuDQo+IA0KPiBUZXN0ZWQtYnk6IGRhbm4gZnJhemllciA8ZGFubi5m
cmF6aWVyQGNhbm9uaWNhbC5jb20+DQoNCk1hbnkgdGhhbmtzIGZvciB0aGlzDQpHYWINCg==

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

* [PATCH v10 0/9] LPC: legacy ISA I/O support
@ 2017-11-09 16:18     ` Gabriele Paoloni
  0 siblings, 0 replies; 89+ messages in thread
From: Gabriele Paoloni @ 2017-11-09 16:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Dann

> -----Original Message-----
> From: dann frazier [mailto:dann.frazier at canonical.com]
> Sent: 09 November 2017 16:16
> To: Gabriele Paoloni
> Cc: Catalin Marinas; Will Deacon; Rob Herring; Frank Rowand; Bjorn
> Helgaas; rafael at kernel.org; Arnd Bergmann; linux-arm-kernel;
> lorenzo.pieralisi at arm.com; Mark Rutland; Brian Starkey; olof at lixom.net;
> benh at kernel.crashing.org; linux-kernel at vger.kernel.org; linux-
> acpi at vger.kernel.org; Linuxarm; linux-pci at vger.kernel.org; Corey
> Minyard; John Garry; xuwei (O)
> Subject: Re: [PATCH v10 0/9] LPC: legacy ISA I/O support
> 
> On Fri, Oct 27, 2017 at 10:11 AM, Gabriele Paoloni
> <gabriele.paoloni@huawei.com> wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > This patchset supports the IPMI-bt device attached to the Low-Pin-
> Count
> > interface implemented on Hisilicon Hip06/Hip07 SoC.
> 
> fwiw, I tested this on one of our D05 boards and verified that the
> IPMI SI worked fine.
> 
> Tested-by: dann frazier <dann.frazier@canonical.com>

Many thanks for this
Gab

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

end of thread, other threads:[~2017-11-09 16:21 UTC | newest]

Thread overview: 89+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-27 16:11 [PATCH v10 0/9] LPC: legacy ISA I/O support Gabriele Paoloni
2017-10-27 16:11 ` Gabriele Paoloni
2017-10-27 16:11 ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 18:32   ` Corey Minyard
2017-10-27 18:32     ` Corey Minyard
2017-10-30 15:31     ` Gabriele Paoloni
2017-10-30 15:31       ` Gabriele Paoloni
2017-10-30 15:31       ` Gabriele Paoloni
2017-10-30 15:31       ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range() Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-11-07  0:23   ` Bjorn Helgaas
2017-11-07  0:23     ` Bjorn Helgaas
2017-11-07  0:23     ` Bjorn Helgaas
2017-11-07 10:50     ` Gabriele Paoloni
2017-11-07 10:50       ` Gabriele Paoloni
2017-11-07 10:50       ` Gabriele Paoloni
2017-11-07 10:50       ` Gabriele Paoloni
2017-11-07  0:25   ` Bjorn Helgaas
2017-11-07  0:25     ` Bjorn Helgaas
2017-11-07  0:25     ` Bjorn Helgaas
2017-11-07 10:50     ` Gabriele Paoloni
2017-11-07 10:50       ` Gabriele Paoloni
2017-11-07 10:50       ` Gabriele Paoloni
2017-11-07 10:50       ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 3/9] PCI: add fwnode handler as input param of pci_register_io_range() Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 4/9] PCI: Apply the new generic I/O management on PCI IO hosts Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 5/9] OF: Add missing I/O range exception for indirect-IO devices Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:44   ` Randy Dunlap
2017-10-27 16:44     ` Randy Dunlap
2017-10-27 16:44     ` Randy Dunlap
2017-10-27 16:44     ` Randy Dunlap
2017-10-30 15:55     ` Gabriele Paoloni
2017-10-30 15:55       ` Gabriele Paoloni
2017-10-30 15:55       ` Gabriele Paoloni
2017-10-30 15:55       ` Gabriele Paoloni
2017-11-09  0:46   ` dann frazier
2017-11-09  0:46     ` dann frazier
2017-11-09  0:46     ` dann frazier
2017-11-09 10:05     ` Gabriele Paoloni
2017-11-09 10:05       ` Gabriele Paoloni
2017-11-09 10:05       ` Gabriele Paoloni
2017-11-09 10:05       ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 8/9] LPC: Add the ACPI LPC support Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11 ` [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-10-27 16:11   ` Gabriele Paoloni
2017-11-07  0:21   ` Bjorn Helgaas
2017-11-07  0:21     ` Bjorn Helgaas
2017-11-07  0:21     ` Bjorn Helgaas
2017-11-07  0:21     ` Bjorn Helgaas
2017-11-07 10:49     ` Gabriele Paoloni
2017-11-07 10:49       ` Gabriele Paoloni
2017-11-07 10:49       ` Gabriele Paoloni
2017-11-07 10:49       ` Gabriele Paoloni
2017-10-27 16:45 ` [PATCH v10 0/9] LPC: legacy ISA I/O support David Laight
2017-10-27 16:45   ` David Laight
2017-10-27 16:45   ` David Laight
2017-10-27 16:45   ` David Laight
2017-10-30 11:32   ` Gabriele Paoloni
2017-10-30 11:32     ` Gabriele Paoloni
2017-10-30 11:32     ` Gabriele Paoloni
2017-10-30 11:32     ` Gabriele Paoloni
2017-11-09 16:16 ` dann frazier
2017-11-09 16:16   ` dann frazier
2017-11-09 16:16   ` dann frazier
2017-11-09 16:18   ` Gabriele Paoloni
2017-11-09 16:18     ` Gabriele Paoloni
2017-11-09 16:18     ` Gabriele Paoloni
2017-11-09 16:18     ` Gabriele Paoloni

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.