From patchwork Fri Oct 27 16:11:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831384 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpn71GgSz9t3r for ; Sat, 28 Oct 2017 03:12:43 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751314AbdJ0QMk (ORCPT ); Fri, 27 Oct 2017 12:12:40 -0400 Received: from szxga05-in.huawei.com ([45.249.212.191]:9527 "EHLO szxga05-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751179AbdJ0QMj (ORCPT ); Fri, 27 Oct 2017 12:12:39 -0400 Received: from 172.30.72.60 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.60]) by dggrg05-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DKA16066; Sat, 28 Oct 2017 00:12:33 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:27 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH v10 1/9] LIB: Introduce a generic PIO mapping method Date: Fri, 27 Oct 2017 17:11:19 +0100 Message-ID: <1509120687-7352-2-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020203.59F35AF2.0063, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 935bd1feaf1dce30368c1369b4f0df6a Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: "zhichang.yuan" 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 Signed-off-by: Gabriele Paoloni --- 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 + /* * {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 + * Author: Zhichang Yuan + * + * 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 . + */ + +#ifndef __LINUX_LOGIC_PIO_H +#define __LINUX_LOGIC_PIO_H + +#ifdef __KERNEL__ + +#include + +#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 + * Author: Zhichang Yuan + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 */ From patchwork Fri Oct 27 16:11:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831393 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNps91thHz9t3r for ; Sat, 28 Oct 2017 03:16:13 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752740AbdJ0QPn (ORCPT ); Fri, 27 Oct 2017 12:15:43 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9455 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752629AbdJ0QOy (ORCPT ); Fri, 27 Oct 2017 12:14:54 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16578; Sat, 28 Oct 2017 00:14:41 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:32 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , Subject: [PATCH v10 2/9] PCI: remove unused __weak attribute in pci_register_io_range() Date: Fri, 27 Oct 2017 17:11:20 +0100 Message-ID: <1509120687-7352-3-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020202.59F35B72.0031, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: c83d41304ba06320d1c5a75713abacc4 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: gabriele paoloni Currently pci_register_io_range() has only one definition; therefore there is no use of the __weak attribute. Signed-off-by: Gabriele Paoloni Acked-by: Bjorn Helgaas Acked-by: Bjorn Helgaas --- 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; From patchwork Fri Oct 27 16:11:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831394 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpsD0RZnz9t3r for ; Sat, 28 Oct 2017 03:16:16 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752218AbdJ0QPm (ORCPT ); Fri, 27 Oct 2017 12:15:42 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9454 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752033AbdJ0QOz (ORCPT ); Fri, 27 Oct 2017 12:14:55 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16563; Sat, 28 Oct 2017 00:14:38 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:37 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , Subject: [PATCH v10 3/9] PCI: add fwnode handler as input param of pci_register_io_range() Date: Fri, 27 Oct 2017 17:11:21 +0100 Message-ID: <1509120687-7352-4-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020204.59F35B6F.0023, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: f637e8d5eefb5ceb520003383bc07b0d Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: gabriele paoloni 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 Acked-by: Bjorn Helgaas --- 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 +#include #include #include #include @@ -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); From patchwork Fri Oct 27 16:11:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831392 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNprW14ZPz9t4b for ; Sat, 28 Oct 2017 03:15:39 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751595AbdJ0QPX (ORCPT ); Fri, 27 Oct 2017 12:15:23 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9452 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752664AbdJ0QO7 (ORCPT ); Fri, 27 Oct 2017 12:14:59 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16564; Sat, 28 Oct 2017 00:14:39 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:42 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , Subject: [PATCH v10 4/9] PCI: Apply the new generic I/O management on PCI IO hosts Date: Fri, 27 Oct 2017 17:11:22 +0100 Message-ID: <1509120687-7352-5-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020204.59F35B6F.009E, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: bad2eceb1bc65310c4673d45007ddb07 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: gabriele paoloni 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 Signed-off-by: Gabriele Paoloni Signed-off-by: Arnd Bergmann #earlier draft Acked-by: Bjorn Helgaas --- 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 #include #include +#include #include #include #include @@ -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 From patchwork Fri Oct 27 16:11:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831387 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpqX6kWJz9t4b for ; Sat, 28 Oct 2017 03:14:48 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751447AbdJ0QOr (ORCPT ); Fri, 27 Oct 2017 12:14:47 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9448 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752530AbdJ0QOp (ORCPT ); Fri, 27 Oct 2017 12:14:45 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16565; Sat, 28 Oct 2017 00:14:39 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:48 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH v10 5/9] OF: Add missing I/O range exception for indirect-IO devices Date: Fri, 27 Oct 2017 17:11:23 +0100 Message-ID: <1509120687-7352-6-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020203.59F35B6F.0144, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: d3057f1d5ea9f59b20f45be4aa1c4bdb Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: "zhichang.yuan" There are some special ISA/LPC devices that work on a specific I/O range where it is not correct to specify a 'ranges' property in DTS parent node as cpu addresses translated from DTS node are only for memory space on some architectures, such as Arm64. Without the parent 'ranges' property, current of_translate_address() return an error. Here we add special handlings for this case. During the OF address translation, some checkings will be perfromed to identify whether the device node is registered as indirect-IO. If yes, the I/O translation will be done in a different way from that one of PCI MMIO. In this way, the I/O 'reg' property of the special ISA/LPC devices will be parsed correctly. Signed-off-by: zhichang.yuan Signed-off-by: Gabriele Paoloni Signed-off-by: Arnd Bergmann #earlier draft Acked-by: Rob Herring --- 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; From patchwork Fri Oct 27 16:11:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831388 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpqf729lz9t3r for ; Sat, 28 Oct 2017 03:14:54 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752530AbdJ0QOw (ORCPT ); Fri, 27 Oct 2017 12:14:52 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9449 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752522AbdJ0QOr (ORCPT ); Fri, 27 Oct 2017 12:14:47 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16567; Sat, 28 Oct 2017 00:14:39 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:53 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH v10 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings Date: Fri, 27 Oct 2017 17:11:24 +0100 Message-ID: <1509120687-7352-7-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020203.59F35B6F.01E0, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: cc112455d751c6f463595c3a5dacec3a Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: "zhichang.yuan" The low-pin-count(LPC) interface of Hip06/Hip07 accesses the peripherals in I/O port addresses. This patch implements the LPC host controller driver which perform the I/O operations on the underlying hardware. We don't want to touch those existing peripherals' driver, such as ipmi-bt. So this driver applies the indirect-IO introduced in the previous patch after registering an indirect-IO node to the indirect-IO devices list which will be searched in the I/O accessors to retrieve the host-local I/O port. Signed-off-by: Zou Rongrong Signed-off-by: zhichang.yuan Signed-off-by: Gabriele Paoloni Acked-by: Rob Herring #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 + * Author: Zou Rongrong + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); From patchwork Fri Oct 27 16:11:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831395 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpsD6K7fz9t4c for ; Sat, 28 Oct 2017 03:16:16 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752650AbdJ0QOy (ORCPT ); Fri, 27 Oct 2017 12:14:54 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9453 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752574AbdJ0QOu (ORCPT ); Fri, 27 Oct 2017 12:14:50 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16568; Sat, 28 Oct 2017 00:14:39 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:58 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , Subject: [PATCH v10 7/9] ACPI: Translate the I/O range of non-MMIO devices before scanning Date: Fri, 27 Oct 2017 17:11:25 +0100 Message-ID: <1509120687-7352-8-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020204.59F35B70.0050, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 49727a8b2ee5a09c5d69a8b24490fdd6 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: gabriele paoloni 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 Signed-off-by: Gabriele Paoloni --- 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 + * Author: Zhichang Yuan + * + * 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 +#include +#include + +#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 + * Author: Zhichang Yuan + * + * 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); From patchwork Fri Oct 27 16:11:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831389 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpql3V3Fz9t3r for ; Sat, 28 Oct 2017 03:14:59 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752670AbdJ0QO4 (ORCPT ); Fri, 27 Oct 2017 12:14:56 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9450 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752539AbdJ0QOt (ORCPT ); Fri, 27 Oct 2017 12:14:49 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16571; Sat, 28 Oct 2017 00:14:40 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:13:04 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH v10 8/9] LPC: Add the ACPI LPC support Date: Fri, 27 Oct 2017 17:11:26 +0100 Message-ID: <1509120687-7352-9-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020204.59F35B70.016F, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 64e5a2f428088c0b3bdf29ea63aee021 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: "zhichang.yuan" Based on the provious patches, this patch supports the ACPI LPC host on Hip06/Hip07. Signed-off-by: zhichang.yuan Signed-off-by: John Garry Signed-off-by: Gabriele Paoloni Tested-by: dann frazier --- 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 + +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, }; From patchwork Fri Oct 27 16:11:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 831396 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yNpsg186Zz9ryr for ; Sat, 28 Oct 2017 03:16:39 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751688AbdJ0QQW (ORCPT ); Fri, 27 Oct 2017 12:16:22 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9451 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752569AbdJ0QOw (ORCPT ); Fri, 27 Oct 2017 12:14:52 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16573; Sat, 28 Oct 2017 00:14:40 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:13:09 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , Subject: [PATCH v10 9/9] MANTAINERS: Add maintainer for HiSilicon LPC driver Date: Fri, 27 Oct 2017 17:11:27 +0100 Message-ID: <1509120687-7352-10-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020206.59F35B71.011F, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: fb599be21189fc663ec2511fb904cde7 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Added maintainer for drivers/bus/hisi_lpc.c Signed-off-by: Gabriele Paoloni --- 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 M: Salil Mehta