Hi, Alex,

Thanks for your review!
Sorry for the late response!
As this patch-set was two weeks ago, it must be painful to check this thread 
again.

I thought John had discussed with you about most of the comments when I was 
back from ten days' leave, and I have no more to supplement,
so...
But when I started the work on V7, met somethings need to clarify with you.
Please kindly check the below.


On 2017/1/31 1:12, Alexander Graf wrote:
> On 01/24/2017 08:05 AM, zhichang.yuan wrote:
>> Low-pin-count interface is integrated into some SoCs. The accesses to those
>> peripherals under LPC make use of I/O ports rather than the memory mapped 
>> I/O.
>>
>> To drive these devices, this patch introduces a method named indirect-IO.
>> In this method the in/out() accessor in include/asm-generic/io.h will be
>> redefined. When upper layer drivers call in/out() with those known legacy 
>> port
>> addresses to access the peripherals, the I/O operations will be routed to the
>> right hooks which are registered specific to the host device, such as LPC.
>> Then the hardware relevant manupulations are finished by the corresponding
>> host.
>>
>> According to the comments on V5, this patch adds a common indirect-IO driver
>> which support this I/O indirection to the generic directory.
>>
>> In the later pathches, some host-relevant drivers are implemented to support
>> the specific I/O hooks and register them.
>> Based on these, the upper layer drivers which depend on in/out() can work 
>> well
>> without any extra work or any changes.
>>
>> Signed-off-by: zhichang.yuan <[email protected]>
>> Signed-off-by: Gabriele Paoloni <[email protected]>
>> Signed-off-by: John Garry <[email protected]>
> 
> I like the extio idea. That allows us to handle all PIO requests on platforms 
> that don't have native PIO support via different routes depending on the 
> region they're in. Unfortunately we now we have 2 frameworks for handling 
> sparse PIO regions: One in extio, one in PCI.
> 
> Why don't we just merge the two? Most of the code that has #ifdef PCI_IOBASE 
> throughout the code base sounds like an ideal candidate to get migrated to 
> extio instead. Then we only have a single framework to worry about ...
> 
>> ---
>>   include/asm-generic/io.h |  50 ++++++++++++++++
>>   include/linux/extio.h    |  85 +++++++++++++++++++++++++++
>>   include/linux/io.h       |   1 +
>>   lib/Kconfig              |   8 +++
>>   lib/Makefile             |   2 +
>>   lib/extio.c              | 147 
>> +++++++++++++++++++++++++++++++++++++++++++++++
>>   6 files changed, 293 insertions(+)
>>   create mode 100644 include/linux/extio.h
>>   create mode 100644 lib/extio.c
>>
>> diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
>> index 7ef015e..c0d6db1 100644
>> --- a/include/asm-generic/io.h
>> +++ b/include/asm-generic/io.h
>> @@ -21,6 +21,8 @@
>>     #include <asm-generic/pci_iomap.h>
>>   +#include <linux/extio.h>
>> +
>>   #ifndef mmiowb
>>   #define mmiowb() do {} while (0)
>>   #endif
>> @@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem 
>> *addr, const void *buffer,
>>    */
>>     #ifndef inb
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define inb extio_inb
>> +#else
>>   #define inb inb
>>   static inline u8 inb(unsigned long addr)
>>   {
>>       return readb(PCI_IOBASE + addr);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
> 
> ... we would also get rid of all of these constructs. Instead, every 
> architecture that doesn't implement native PIO defines would end up in extio 
> and we would enable it unconditionally for them.

Do you want to implement like these?

#ifndef inb
#define inb extio_inb
#endif

In this way, we don't need the CONFIG_INDIRECT_PIO and make extio as kernel 
built-in.
I thought these are your ideas, right?


Best,
Zhichang

> 
>>   #endif
>>     #ifndef inw
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define inw extio_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 extio_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 extio_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 extio_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 extio_outl
>> +#else
>>   #define outl outl
>>   static inline void outl(u32 value, unsigned long addr)
>>   {
>>       writel(value, PCI_IOBASE + addr);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef inb_p
>> @@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long 
>> addr)
>>    */
>>     #ifndef insb
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define insb extio_insb
>> +#else
>>   #define insb insb
>>   static inline void insb(unsigned long addr, void *buffer, unsigned int 
>> count)
>>   {
>>       readsb(PCI_IOBASE + addr, buffer, count);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef insw
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define insw extio_insw
>> +#else
>>   #define insw insw
>>   static inline void insw(unsigned long addr, void *buffer, unsigned int 
>> count)
>>   {
>>       readsw(PCI_IOBASE + addr, buffer, count);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef insl
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define insl extio_insl
>> +#else
>>   #define insl insl
>>   static inline void insl(unsigned long addr, void *buffer, unsigned int 
>> count)
>>   {
>>       readsl(PCI_IOBASE + addr, buffer, count);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef outsb
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define outsb extio_outsb
>> +#else
>>   #define outsb outsb
>>   static inline void outsb(unsigned long addr, const void *buffer,
>>                unsigned int count)
>>   {
>>       writesb(PCI_IOBASE + addr, buffer, count);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef outsw
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define outsw extio_outsw
>> +#else
>>   #define outsw outsw
>>   static inline void outsw(unsigned long addr, const void *buffer,
>>                unsigned int count)
>>   {
>>       writesw(PCI_IOBASE + addr, buffer, count);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef outsl
>> +#ifdef CONFIG_INDIRECT_PIO
>> +#define outsl extio_outsl
>> +#else
>>   #define outsl outsl
>>   static inline void outsl(unsigned long addr, const void *buffer,
>>                unsigned int count)
>>   {
>>       writesl(PCI_IOBASE + addr, buffer, count);
>>   }
>> +#endif /* CONFIG_INDIRECT_PIO */
>>   #endif
>>     #ifndef insb_p
>> diff --git a/include/linux/extio.h b/include/linux/extio.h
>> new file mode 100644
>> index 0000000..2ca7eab
>> --- /dev/null
>> +++ b/include/linux/extio.h
>> @@ -0,0 +1,85 @@
>> +/*
>> + * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
>> + * Author: Zhichang Yuan <[email protected]>
>> + *
>> + * 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_EXTIO_H
>> +#define __LINUX_EXTIO_H
>> +
>> +#ifdef __KERNEL__
>> +
>> +#include <linux/fwnode.h>
>> +
>> +struct extio_ops {
>> +    u64 (*pfin)(void *devobj, unsigned long ptaddr,    size_t dlen);
>> +    void (*pfout)(void *devobj, unsigned long ptaddr, u32 outval,
>> +                    size_t dlen);
>> +    u64 (*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);
>> +};
>> +
>> +struct extio_node {
>> +    unsigned long bus_start;    /* bus start address */
>> +    unsigned long io_start;    /* io port token corresponding to bus_start 
>> */
>> +    size_t range_size;    /* size of the extio node operating range */
>> +    struct fwnode_handle *fwnode;
>> +    struct list_head list;
>> +    struct extio_ops *ops;    /* ops operating on this node */
>> +    void *devpara;    /* private parameter of the host device */
>> +};
>> +
>> +extern u8 extio_inb(unsigned long addr);
>> +extern void extio_outb(u8 value, unsigned long addr);
>> +extern void extio_outw(u16 value, unsigned long addr);
>> +extern void extio_outl(u32 value, unsigned long addr);
>> +extern u16 extio_inw(unsigned long addr);
>> +extern u32 extio_inl(unsigned long addr);
>> +extern void extio_outb(u8 value, unsigned long addr);
>> +extern void extio_outw(u16 value, unsigned long addr);
>> +extern void extio_outl(u32 value, unsigned long addr);
>> +extern void extio_insb(unsigned long addr, void *buffer, unsigned int 
>> count);
>> +extern void extio_insl(unsigned long addr, void *buffer, unsigned int 
>> count);
>> +extern void extio_insw(unsigned long addr, void *buffer, unsigned int 
>> count);
>> +extern void extio_outsb(unsigned long addr, const void *buffer,
>> +            unsigned int count);
>> +extern void extio_outsw(unsigned long addr, const void *buffer,
>> +            unsigned int count);
>> +extern void extio_outsl(unsigned long addr, const void *buffer,
>> +            unsigned int count);
>> +
>> +#ifdef CONFIG_INDIRECT_PIO
>> +extern struct extio_node *extio_find_node(struct fwnode_handle *node);
>> +
>> +extern unsigned long
>> +extio_translate(struct fwnode_handle *node, unsigned long bus_addr);
>> +#else
>> +static inline struct extio_node *extio_find_node(struct fwnode_handle *node)
>> +{
>> +    return NULL;
>> +}
>> +
>> +static inline unsigned long
>> +extio_translate(struct fwnode_handle *node, unsigned long bus_addr)
>> +{
>> +    return -1;
>> +}
>> +#endif
>> +extern void register_extio(struct extio_node *node);
>> +
>> +#endif /* __KERNEL__ */
>> +#endif /* __LINUX_EXTIO_H */
>> diff --git a/include/linux/io.h b/include/linux/io.h
>> index 82ef36e..6c68478 100644
>> --- a/include/linux/io.h
>> +++ b/include/linux/io.h
>> @@ -24,6 +24,7 @@
>>   #include <linux/err.h>
>>   #include <asm/io.h>
>>   #include <asm/page.h>
>> +#include <linux/extio.h>
>>     struct device;
>>   struct resource;
>> diff --git a/lib/Kconfig b/lib/Kconfig
>> index 260a80e..1d27c44 100644
>> --- a/lib/Kconfig
>> +++ b/lib/Kconfig
>> @@ -59,6 +59,14 @@ config ARCH_USE_CMPXCHG_LOCKREF
>>   config ARCH_HAS_FAST_MULTIPLIER
>>       bool
>>   +config INDIRECT_PIO
>> +    bool "access peripherals with legacy I/O port"
>> +    depends on PCI
>> +    help
>> +      Support special accessors for ISA I/O devices. This is needed for
>> +      SoCs that have not I/O space and do not support standard MMIO
>> +      read/write for the ISA range.
>> +
>>   config CRC_CCITT
>>       tristate "CRC-CCITT functions"
>>       help
>> diff --git a/lib/Makefile b/lib/Makefile
>> index bc4073a..bf03e05 100644
>> --- a/lib/Makefile
>> +++ b/lib/Makefile
>> @@ -70,6 +70,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_INDIRECT_PIO)    += extio.o
>> +
>>   obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
>>     obj-$(CONFIG_BTREE) += btree.o
>> diff --git a/lib/extio.c b/lib/extio.c
>> new file mode 100644
>> index 0000000..46228de
>> --- /dev/null
>> +++ b/lib/extio.c
>> @@ -0,0 +1,147 @@
>> +/*
>> + * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
>> + * Author: Zhichang Yuan <[email protected]>
>> + *
>> + * 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/io.h>
>> +#include <linux/spinlock.h>
>> +
>> +static LIST_HEAD(extio_dev_list);
>> +static DEFINE_RWLOCK(extio_list_lock);
> 
> Why not just make the list an RCU list? Then you don't need read locks. We 
> also wouldn't create potential lock contention between devices that could 
> easily have parallel PIO operations (say a PCI device and an LPC device).
> 
>> +
>> +void register_extio(struct extio_node *node)
>> +{
>> +    write_lock(&extio_list_lock);
>> +    list_add_tail(&node->list, &extio_dev_list);
>> +    write_unlock(&extio_list_lock);
>> +}
>> +
>> +static struct extio_node *find_extio_token(unsigned long addr)
>> +{
>> +    struct extio_node *extio_entry;
>> +
>> +    read_lock(&extio_list_lock);
>> +    list_for_each_entry(extio_entry, &extio_dev_list, list) {
>> +        if ((addr < extio_entry->io_start + extio_entry->range_size) &&
>> +            (addr >= extio_entry->io_start))
>> +            break;
>> +    }
>> +    read_unlock(&extio_list_lock);
>> +    return (&extio_entry->list == &extio_dev_list) ? NULL : extio_entry;
>> +}
>> +
>> +struct extio_node *extio_find_node(struct fwnode_handle *node)
>> +{
>> +    struct extio_node *entry;
>> +
>> +    read_lock(&extio_list_lock);
>> +    list_for_each_entry(entry, &extio_dev_list, list) {
>> +        if (entry->fwnode == node)
>> +            break;
>> +    }
>> +    read_unlock(&extio_list_lock);
>> +
>> +    return (&entry->list == &extio_dev_list) ? NULL : entry;
>> +}
>> +
>> +unsigned long extio_translate(struct fwnode_handle *node,
>> +        unsigned long bus_addr)
>> +{
>> +    struct extio_node *entry;
>> +    unsigned long port_id = -1;
>> +
>> +    read_lock(&extio_list_lock);
>> +    list_for_each_entry(entry, &extio_dev_list, list) {
>> +        if (entry->fwnode == node &&
>> +            bus_addr >= entry->bus_start &&
>> +            bus_addr - entry->bus_start < entry->range_size)
>> +            port_id = entry->io_start + bus_addr -
>> +                    entry->bus_start;
>> +    }
>> +    read_unlock(&extio_list_lock);
>> +
>> +    return port_id;
>> +}
>> +
>> +#ifdef PCI_IOBASE
>> +
>> +#define BUILD_EXTIO(bw, type)                        \
>> +type extio_in##bw(unsigned long addr)                    \
>> +{                                    \
>> +    struct extio_node *extio_entry = find_extio_token(addr);    \
>> +                                    \
>> +    if (!extio_entry)                        \
>> +        return read##bw(PCI_IOBASE + addr);            \
>> +    return extio_entry->ops->pfin ?                    \
>> +            extio_entry->ops->pfin(extio_entry->devpara,    \
>> +            addr, sizeof(type)) : -1;            \
>> +}                                    \
>> +                                    \
>> +void extio_out##bw(type value, unsigned long addr)            \
>> +{                                    \
>> +    struct extio_node *extio_entry = find_extio_token(addr);    \
>> +                                    \
>> +    if (!extio_entry)                        \
>> +        write##bw(value, PCI_IOBASE + addr);            \
> 
> All of the fallback code would also disappear as a nice side effect of making 
> pci pio handling a user of extio :).
> 
> 
> Alex
> 
> 
> .
> 

Reply via email to