From: Arnd Bergmann <arnd@arndb.de>
To: linuxppc-dev@ozlabs.org
Subject: Re: [PATCH/RFC] Hookable IO operations
Date: Fri, 3 Nov 2006 23:20:34 +0100 [thread overview]
Message-ID: <200611032320.34762.arnd@arndb.de> (raw)
In-Reply-To: <1162588367.10630.100.camel@localhost.localdomain>
On Friday 03 November 2006 22:12, Benjamin Herrenschmidt wrote:
> +/*
> + *
> + * Low level MMIO accessors
> + *
> + * This provides the non-bus specific accessors to MMIO. Those are PowerPC
> + * specific and thus shouldn't be used in generic code. The accessors
> + * provided here are:
> + *
> + * in_8, in_le16, in_be16, in_le32, in_be32, in_le64, in_be64
> + * out_8, out_le16, out_be16, out_le32, out_be32, out_le64, out_be64
> + * _insb, _insw_ns, _insl_ns, _outsb, _outsw_ns, _outsl_ns
> + *
> + * Those operate direction on a kernel virtual address. Note that the prototype
> + * for the out_* accessors has the arguments in opposite order from the usual
> + * linux PCI accessors. Unlike those, they take the address first and the value
> + * next.
> + *
> + * Note: I might drop the _ns suffix on the stream operations soon as it is
> + * simply normal for stream operations to not swap in the first place.
> + *
> + */
> +
> +#define DEF_MMIO_IN(name, type, insn) \
> +static inline type in_##name(const volatile type __iomem *addr) \
> +{ \
> + type ret; \
> + __asm__ __volatile__("sync;" insn ";twi 0,%0,0;isync" \
> + : "=r" (ret) : "r" (addr), "m" (*addr)); \
> + return ret; \
> +}
> +
> +#define DEF_MMIO_OUT(name, type, insn) \
> +static inline void out_##name(volatile type __iomem *addr, type val) \
> +{ \
> + __asm__ __volatile__("sync;" insn \
> + : "=m" (*addr) : "r" (val), "r" (addr)); \
> + get_paca()->io_sync = 1; \
> +}
> +
> +
> +#define DEF_MMIO_IN_BE(pfx, size, insn) \
> + DEF_MMIO_IN(pfx##size, u##size, __stringify(insn)"%U2%X2 %0,%2")
> +#define DEF_MMIO_IN_LE(pfx, size, insn) \
> + DEF_MMIO_IN(pfx##size, u##size, __stringify(insn)" %0,0,%1")
> +
> +#define DEF_MMIO_OUT_BE(pfx, size, insn) \
> + DEF_MMIO_OUT(pfx##size, u##size, __stringify(insn)"%U0%X0 %1,%0")
> +#define DEF_MMIO_OUT_LE(pfx, size, insn) \
> + DEF_MMIO_OUT(pfx##size, u##size, __stringify(insn)" %1,0,%2")
> +
> +DEF_MMIO_IN_BE( , 8, lbz);
> +DEF_MMIO_IN_BE(be, 16, lhz);
> +DEF_MMIO_IN_BE(be, 32, lwz);
> +DEF_MMIO_IN_BE(be, 64, ld);
> +DEF_MMIO_IN_LE(le, 16, lhbrx);
> +DEF_MMIO_IN_LE(le, 32, lwbrx);
> +
> +DEF_MMIO_OUT_BE( , 8, stb);
> +DEF_MMIO_OUT_BE(be, 16, sth);
> +DEF_MMIO_OUT_BE(be, 32, stw);
> +DEF_MMIO_OUT_BE(be, 64, std);
> +DEF_MMIO_OUT_LE(le, 16, sthbrx);
> +DEF_MMIO_OUT_LE(le, 32, stwbrx);
I think it would be helpful to not generate the function name itself,
but pass it down to the macro, so you grep for the definition, either
DEF_MMIO_IN_BE(in_be16, u16, lwz)
or going further, making it look more like a declaration
static inline u16 DEF_MMIO_IN_BE(in_be16, u16, lwz)
which may even do the right thing with ctags (need to check that)
> +/*
> + * IO stream instructions are defined out of line
> + */
> +extern void _insb(volatile u8 __iomem *port, void *buf, long count);
> +extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
> +extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
> +extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
> +extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
> +extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
If you leave out the 'extern', it fits into a normal line ;-)
> +
> +/*
> + * PCI IO accessors.
> + *
> + * Right now, we still use the eeh versions inline but that might change
> + * as EEH can use the new hook mecanism, provided it doesn't impact
> + * performances too much
> + */
> +
> +#include <asm/eeh.h>
> +
> +#define DEF_PCI_DT_b u8
> +#define DEF_PCI_DT_w u16
> +#define DEF_PCI_DT_l u32
> +#define DEF_PCI_DT_q u64
> +
> +#define __do_writeb(val, addr) out_8(addr, val)
> +#define __do_writew(val, addr) out_le16(addr, val)
> +#define __do_writel(val, addr) out_le32(addr, val)
> +#define __do_writeq(val, addr) out_le64(addr, val)
> +
> +#ifdef CONFIG_PPC_INDIRECT_IO
> +#define DEF_PCI_HOOK(x) x
> +#else
> +#define DEF_PCI_HOOK(x) NULL
> +#endif
> +
> +#define DEF_PCI_AC_IN_MMIO(ts) \
> +extern DEF_PCI_DT_##ts (*__ind_read##ts)(const volatile void __iomem * addr); \
> +static inline DEF_PCI_DT_##ts read##ts(const volatile void __iomem * addr) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_read##ts) != NULL) \
> + return __ind_read##ts(addr); \
> + return eeh_read##ts(addr); \
> +}
> +
> +#define DEF_PCI_AC_IN_PIO(ts) \
> +extern DEF_PCI_DT_##ts (*__ind_in##ts)(unsigned long port); \
> +static inline DEF_PCI_DT_##ts in##ts(unsigned long port) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_in##ts) != NULL) \
> + return __ind_in##ts(port); \
> + return read##ts((void __iomem *)pci_io_base + port); \
> +}
> +
> +#define DEF_PCI_AC_OUT_MMIO(ts) \
> +extern void (*__ind_write##ts)(DEF_PCI_DT_##ts val, \
> + volatile void __iomem *addr); \
> +static inline void write##ts(DEF_PCI_DT_##ts val, volatile void __iomem *addr) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_write##ts) != NULL) \
> + __ind_write##ts(val, addr); \
> + else \
> + __do_write##ts(val, addr); \
> +}
> +
> +#define DEF_PCI_AC_OUT_PIO(ts) \
> +extern void (*__ind_out##ts)(DEF_PCI_DT_##ts val, unsigned long port); \
> +static inline void out##ts(DEF_PCI_DT_##ts val, unsigned long port) \
> +{ \
> + if (DEF_PCI_HOOK(__ind_out##ts) != NULL) \
> + __ind_out##ts(val, port); \
> + else \
> + write##ts(val, (void __iomem *)pci_io_base + port); \
> +}
> +
> +#define DEF_PCI_AC_MMIO(ts, dir) DEF_PCI_AC_##dir##_MMIO(ts)
> +#define DEF_PCI_AC_PIO(ts, dir) DEF_PCI_AC_##dir##_PIO(ts)
> +
> +#define DEF_PCI_AC(ts, dir) DEF_PCI_AC_MMIO(ts, dir) \
> + DEF_PCI_AC_PIO(ts, dir)
> +DEF_PCI_AC(b, IN)
> +DEF_PCI_AC(w, IN)
> +DEF_PCI_AC(l, IN)
> +DEF_PCI_AC_MMIO(q, IN)
> +DEF_PCI_AC(b, OUT)
> +DEF_PCI_AC(w, OUT)
> +DEF_PCI_AC(l, OUT)
> +DEF_PCI_AC_MMIO(q, OUT)
similarly here, you could write these using slightly different macros
as
DEF_PCI_AC_OUT_MMIO(writeb, u8)
DEF_PCI_AC_OUT_PIO(outb, u8)
DEF_PCI_AC_OUT_MMIO(writew, u16)
DEF_PCI_AC_OUT_PIO(outw, u16)
> +
> +/* We still use EEH versions for now. Ultimately, we might just get rid of
> + * EEH in here and use it as a set of __memset_io etc... hooks
> + */
Yes, I fully agree. The definition of eeh_memset_io and the others
looks like they really want to be out-of-line.
> +
> +extern void (*__memset_io)(volatile void __iomem *addr, int c,
> + unsigned long n);
> +extern void (*__memcpy_fromio)(void *dest, const volatile void __iomem *src,
> + unsigned long n);
> +extern void (*__memcpy_toio)(volatile void __iomem *dest, const void *src,
> + unsigned long n);
Why are these all separate symbols? Wouldn't it be clearer to group them
in ppc_md, or a similar structure of function pointers?
> --- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-11-03 15:52:54.000000000 +1100
> +++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-11-03 18:51:14.000000000 +1100
> @@ -599,3 +599,48 @@ void __init setup_per_cpu_areas(void)
> }
> }
> #endif
> +
> +
> +#ifdef CONFIG_PPC_INDIRECT_IO
> +
> +#define EXP_PCI_AC_IN_MMIO(ts) \
> +DEF_PCI_DT_##ts (*__ind_read##ts)(const volatile void __iomem * addr); \
> +EXPORT_SYMBOL(__ind_read##ts);
> +
> +#define EXP_PCI_AC_IN_PIO(ts) \
> +DEF_PCI_DT_##ts (*__ind_in##ts)(unsigned long port); \
> +EXPORT_SYMBOL(__ind_in##ts);
> +
> +#define EXP_PCI_AC_OUT_MMIO(ts) \
> +void (*__ind_write##ts)(DEF_PCI_DT_##ts val, \
> + volatile void __iomem *addr); \
> +EXPORT_SYMBOL(__ind_write##ts);
> +
> +#define EXP_PCI_AC_OUT_PIO(ts) \
> +void (*__ind_out##ts)(DEF_PCI_DT_##ts val, unsigned long port); \
> +EXPORT_SYMBOL(__ind_out##ts);
> +
> +#define EXP_PCI_AC_MMIO(ts, dir) EXP_PCI_AC_##dir##_MMIO(ts)
> +#define EXP_PCI_AC_PIO(ts, dir) EXP_PCI_AC_##dir##_PIO(ts)
> +
> +#define EXP_PCI_AC(ts, dir) EXP_PCI_AC_MMIO(ts, dir) \
> + EXP_PCI_AC_PIO(ts, dir)
> +EXP_PCI_AC(b, IN)
> +EXP_PCI_AC(w, IN)
> +EXP_PCI_AC(l, IN)
> +EXP_PCI_AC_MMIO(q, IN)
> +EXP_PCI_AC(b, OUT)
> +EXP_PCI_AC(w, OUT)
> +EXP_PCI_AC(l, OUT)
> +EXP_PCI_AC_MMIO(q, OUT)
This is the point where it gets completely unreadable. I ended up
running the macros through 'gcc -E' to see what they do ;-)
If you resolve all the macros, you actually get fewer lines, and
it suddenly becomes readable, as well as parsable with grep and ctags:
u8 (*__ind_readb) (const volatile void __iomem * addr);
EXPORT_SYMBOL(__ind_readb);
u8 (*__ind_inb) (unsigned long port);
EXPORT_SYMBOL(__ind_inb);
u16 (*__ind_readw) (const volatile void __iomem * addr);
EXPORT_SYMBOL(__ind_readw);
u16 (*__ind_inw) (unsigned long port);
...
I do the same when I start using macros, it's always hard to know exactly
when to stop ;-)
> -static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
> +static u8 iseries_readb(const volatile void __iomem *IoAddress)
Since you're converting iSeries_Read_Byte from SilLycAps, shouldn't
you change IoAddress to something more sensible at the same time?
> {
> u64 BarOffset;
> u64 dsa;
> @@ -462,7 +411,8 @@ static u8 iSeries_Read_Byte(const volati
> num_printed = 0;
> }
> if (num_printed++ < 10)
> - printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress);
> + printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
> + IoAddress);
> return 0xff;
And the name in the comment should also be changed.
Arnd <><
next prev parent reply other threads:[~2006-11-03 22:20 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-11-03 21:12 [PATCH/RFC] Hookable IO operations Benjamin Herrenschmidt
2006-11-03 22:20 ` Arnd Bergmann [this message]
2006-11-03 22:32 ` Benjamin Herrenschmidt
2006-11-03 22:48 ` Arnd Bergmann
2006-11-03 22:56 ` Benjamin Herrenschmidt
2006-11-04 0:15 ` Arnd Bergmann
2006-11-04 1:06 ` Benjamin Herrenschmidt
2006-11-04 16:28 ` Segher Boessenkool
2006-11-04 22:05 ` Benjamin Herrenschmidt
2006-11-04 22:33 ` Segher Boessenkool
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200611032320.34762.arnd@arndb.de \
--to=arnd@arndb.de \
--cc=linuxppc-dev@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.