finally fix 53c700 to use the generic iomem infrastructure
Subsystems (6)
PATCH 1/1 finally fix 53c700 to use the generic iomem infrastructure
This driver has had it's own different infrastructure for doing this for ages, but it's time it used the common one.
James
===== drivers/scsi/53c700.c 1.64 vs edited =====
drivers/scsi/53c700.c +1 -2
@@ -389,8 +389,7 @@ host->max_lun =NCR_700_MAX_LUNS ;BUG_ON (NCR_700_transport_template ==NULL ); host->transportt = NCR_700_transport_template; - host->unique_id = hostdata->base; - host->base = hostdata->base; + host->unique_id = (unsigned long )hostdata->base; hostdata->eh_complete =NULL ; host->hostdata[0 ] = (unsigned long )hostdata;/* kick the chip */
===== drivers/scsi/53c700.h 1.23 vs edited =====
drivers/scsi/53c700.h +20 -172
264 lines not on this page · raw message
===== drivers/scsi/NCR_D700.c 1.24 vs edited =====
drivers/scsi/NCR_D700.c +2 -3
@@ -197,12 +197,10 @@ }/* Fill in the three required pieces of hostdata */ - hostdata->base = region; + hostdata->base =ioport_map (region,64 ); hostdata->differential = (((1 <<siop) & differential) !=0 ); hostdata->clock =NCR_D700_CLOCK_MHZ ; -NCR_700_set_io_mapped (hostdata); -/* and register the siop */ host =NCR_700_detect (&NCR_D700_driver_template, hostdata, p->dev);if (!host) {
@@ -214,6 +212,7 @@/* FIXME: read this from SUS */ host->this_id = id_array[slot *2 + siop]; host->irq = irq; + host->base = region;scsi_scan_host (host);return 0 ;
===== drivers/scsi/lasi700.c 1.25 vs edited =====
drivers/scsi/lasi700.c +1 -0
@@ -131,6 +131,7 @@if (!host) goto out_kfree; host->this_id =7 ; + host->base = base; host->irq = dev->irq;if (request_irq (dev->irq, NCR_700_intr,SA_SHIRQ ,"lasi700" , host)) {printk (KERN_ERR "lasi700: request_irq failed!\n" );
===== drivers/scsi/sim710.c 1.27 vs edited =====
drivers/scsi/sim710.c +3 -2
@@ -120,11 +120,10 @@ }/* Fill in the three required pieces of hostdata */ - hostdata->base = base_addr; + hostdata->base =ioport_map (base_addr,64 ); hostdata->differential = differential; hostdata->clock = clock; hostdata->chip710 =1 ; -NCR_700_set_io_mapped (hostdata);/* and register the chip */ if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
@@ -133,6 +132,7 @@ goto out_release; } host->this_id = scsi_id; + host->base = base_addr; host->irq = irq;if (request_irq (irq, NCR_700_intr,SA_SHIRQ ,"sim710" , host)) {printk (KERN_ERR "sim710: request_irq failed\n" );
@@ -164,6 +164,7 @@NCR_700_release (host);kfree (hostdata);free_irq (host->irq, host); +release_region (host->base,64 );return 0 ; }
iomapping a big endian area
Quoted 2 lines · James Bottomley
This driver has had it's own different infrastructure for doing this for ages, but it's time it used the common one.
Thanks. I'd been looking at this for a while but hadn't got round tuit yet.
drivers/scsi/53c700.h line 238
Quoted 7 lines
#ifdef
CONFIG_53C700_LE_ON_BE
#define bE (hostdata->force_le_on_be? 0 : 3)
#define bSWAP (hostdata->force_le_on_be)drivers/scsi/53c700.h +4
-0+/* This is terrible, but there's no raw version of ioread32. That means +* that on a be board we swap twice (once in ioread32 and once again to +* get the value correct) */ +#define bS_to_io (x) ((hostdata->force_le_on_be) ? (x) : cpu_to_le32(x))
I raised this with Linus back when he did the original iomap() stuff. Unfortunately, I think he ignored the question ;-)
My thought on this is that we should encode the endianness of the registers in the ioremap cookie. Some architectures (sparc, I think?) can do this in their PTEs. The rest of us can do it in our ioread/writeN methods. I've planned for this in the parisc iomap implementation but not actually implemented it.
It doesn't look too hard so I'll commit something to the parisc tree later that'll let you iomap a BE area. Do we have any cards that need to be accessed in a BE way on a LE machine? (ie x86)
Signature · 6 lines
"Next the statesmen will invent cheap lies, putting the blame upon the nation that is attacked, and every man will be glad of those conscience-soothing falsities, and will diligently study them, and refuse to examine any refutations of them; and thus he will by and by convince himself that the war is just, and will thank God for the better sleep he enjoys after this process of grotesque self-deception." -- Mark Twain
Re: iomapping a big endian area
Quoted 5 lines · On Sun, 3 Apr 2005 02:37:57 +0100 Matthew Wilcox <[email protected]> wrote:
My thought on this is that we should encode the endianness of the registers in the ioremap cookie. Some architectures (sparc, I think?) can do this in their PTEs. The rest of us can do it in our ioread/writeN methods. I've planned for this in the parisc iomap implementation but not actually implemented it.
SPARC64 can do it in the PTEs, but we just use raw physical addresses in our I/O accessors, and in those load/store instructions we can specify the endianness.
Be careful though. Endianness can be dealt with on a hardware level. Consider a byte access to a 32-bit word sized config space datum, the PCI controller on a big-endian system will likely byte-twist the data lanes in order for this to work properly.
It's a subtle issue, and it's explained pretty well in some of the UltraSPARC PCI controller docs at:
http://www.sun.com/processors/documentation.html
In particular, "U2P UPA to PCI User's Manual", chapter 10 "Little-Endian Support", has some informative diagrams.
Re: iomapping a big endian area
Quoted 9 lines · David S. Miller
Quoted 5 lines
My thought on this is that we should encode the endianness of the registers in the ioremap cookie. Some architectures (sparc, I think?) can do this in their PTEs. The rest of us can do it in our ioread/writeN methods. I've planned for this in the parisc iomap implementation but not actually implemented it.
SPARC64 can do it in the PTEs, but we just use raw physical addresses in our I/O accessors, and in those load/store instructions we can specify the endianness.
Ah right. So you'd prefer an ioread8be() interface?
Quoted 4 lines
Be careful though. Endianness can be dealt with on a hardware level. Consider a byte access to a 32-bit word sized config space datum, the PCI controller on a big-endian system will likely byte-twist the data lanes in order for this to work properly.
Yup, PA-RISC PCI adapters (both Dino and Elroy) do the same thing. The 53c700 driver handles this lack of skewing by xoring the address with 3.
Signature · 6 lines
"Next the statesmen will invent cheap lies, putting the blame upon the nation that is attacked, and every man will be glad of those conscience-soothing falsities, and will diligently study them, and refuse to examine any refutations of them; and thus he will by and by convince himself that the war is just, and will thank God for the better sleep he enjoys after this process of grotesque self-deception." -- Mark Twain
Re: iomapping a big endian area
Quoted 5 lines · Matthew Wilcox
Quoted 3 lines
SPARC64 can do it in the PTEs, but we just use raw physical addresses in our I/O accessors, and in those load/store instructions we can specify the endianness.
Ah right. So you'd prefer an
ioread8be()interface?
Actually, ioread8be is unnecessary, but I was planning to add ioread16/ioread32 and iowritexx be on be variants (equivalent to _raw_readw et al.)
After all, the driver must know the card is BE, so the routines that make use of the feature are easily coded into the card, so there's no real need to add it to the iomem cookie.
Did anyone have a preference for the API? I was thinking ioread32_native, but ioread32be is fine too.
James
Re: iomapping a big endian area
Quoted 3 lines · On Sat, 02 Apr 2005 21:40:39 -0600 James Bottomley…
After all, the driver must know the card is BE, so the routines that make use of the feature are easily coded into the card, so there's no real need to add it to the iomem cookie.
Yes, I don't believe it needs to be in the cookie either.
Quoted 2 lines
Did anyone have a preference for the API? I was thinking
ioread32_native, but ioread32be is fine too.
I think doing foo{be,le}{8,16,32}() would be consistent with our byteorder.h interface names.
Re: iomapping a big endian area
Quoted 5 lines · David S. Miller
Quoted 2 lines
Did anyone have a preference for the API? I was thinking
ioread32_native, but ioread32be is fine too.I think doing foo{be,le}{8,16,32}() would be consistent with our
byteorder.hinterface names.
Thinking about this some more, I know of no case of a BE bus connected to a LE system, nor do I think anyone would ever create such a beast, so our only missing interface is for a BE bus on a BE system.
Thus, I think io{read,write}{16,32}_native are better interfaces ... they basically mean pass memory operations without byte swaps, so they're well defined on both BE and LE systems and correspond exactly to our existing _raw_{read,write}{w,l} calls (principle of least surprise).
James
Re: iomapping a big endian area
Quoted 10 lines · James Bottomley
Quoted 5 lines · David S. Miller
Quoted 2 lines
Did anyone have a preference for the API? I was thinking
ioread32_native, but ioread32be is fine too.I think doing foo{be,le}{8,16,32}() would be consistent with our
byteorder.hinterface names.Thinking about this some more, I know of no case of a BE bus connected to a LE system, nor do I think anyone would ever create such a beast, so our only missing interface is for a BE bus on a BE system.
It's more a matter of the device than the bus imho...
Quoted 1 line
Thus, I think io{read,write}{16,32}_native are better interfaces ...
I disagree. The driver will never "know" ...
Quoted 3 lines
they basically mean pass memory operations without byte swaps, so they're well defined on both BE and LE systems and correspond exactly to our existing _raw_{read,write}{w,l} calls (principle of least surprise).
I don't think it's sane. You know that your device is BE or LE and use the appropriate interface. "native" doesn't make sense to me in this context.
Ben.
Re: iomapping a big endian area
Quoted 1 line · Benjamin Herrenschmidt
I disagree. The driver will never "know" ...
? the driver has to know. Look at the 53c700 to see exactly how awful it is. This beast has byte and word registers. When used BE, all the byte registers alter their position (to both inb and readb).
Quoted 3 lines
I don't think it's sane. You know that your device is BE or LE and use the appropriate interface. "native" doesn't make sense to me in this context.
Well ... it's like this. Native means "pass through without swapping" and has an easy implementation on both BE and LE platforms. Logically io{read,write}{16,32}be would have to do byte swaps on LE platforms. Being lazy, I'm opposed to doing the work if there's no actual use for it, so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
James
Re: iomapping a big endian area
Quoted 6 lines · James Bottomley
Well ... it's like this. Native means "pass through without swapping" and has an easy implementation on both BE and LE platforms. Logically io{read,write}{16,32}be would have to do byte swaps on LE platforms. Being lazy, I'm opposed to doing the work if there's no actual use for it, so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
The IOC4 device that provides IDE, serial ports and external interrupts on Altix systems has a big endian register layour, and the PCI-X bridge in those Altix systems can do the swapping if a special bit is set.
In older kernels that bit was set from the driver through a special API, but it seems the firmware does that automatically now.
Re: iomapping a big endian area
Quoted 6 lines · Christoph Hellwig
The IOC4 device that provides IDE, serial ports and external interrupts on Altix systems has a big endian register layour, and the PCI-X bridge in those Altix systems can do the swapping if a special bit is set.
In older kernels that bit was set from the driver through a special API, but it seems the firmware does that automatically now.
We already have some unusual code in drivers to support other altix design ... features ... do you regard this as something that's likely to be replicated on other platforms, or is it more in the category of a one off mistake that can be corrected in firmware?
James
Re: iomapping a big endian area
Quoted 5 lines · James Bottomley
Quoted 4 lines · Christoph Hellwig
The IOC4 device that provides IDE, serial ports and external interrupts on Altix systems has a big endian register layour, and the PCI-X bridge in those Altix systems can do the swapping if a special bit is set.
Quoted 7 lines
Quoted 2 lines
In older kernels that bit was set from the driver through a special API, but it seems the firmware does that automatically now.
We already have some unusual code in drivers to support other altix design ... features ... do you regard this as something that's likely to be replicated on other platforms, or is it more in the category of a one off mistake that can be corrected in firmware?
The whole line of altix pci bridges can do byteswapping, so it's more than just one product that could benefit (however slightly). Not sure about other bridges though.
Jesse
Re: iomapping a big endian area
In reply to James BottomleyQuoted 15 lines · James Bottomley
Quoted 1 line · Benjamin Herrenschmidt
I disagree. The driver will never "know" ...
? the driver has to know. Look at the 53c700 to see exactly how awful it is. This beast has byte and word registers. When used BE, all the byte registers alter their position (to both inb and readb).
Quoted 3 lines
I don't think it's sane. You know that your device is BE or LE and use the appropriate interface. "native" doesn't make sense to me in this context.
Quoted 6 lines
Well ... it's like this. Native means "pass through without swapping" and has an easy implementation on both BE and LE platforms. Logically io{read,write}{16,32}be would have to do byte swaps on LE platforms. Being lazy, I'm opposed to doing the work if there's no actual use for it, so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
I would probably spell "native" as "noswap". "native" just doesn't convey enough specific meaning...
Signature · 1 line
~Randy
Re: iomapping a big endian area
Quoted 10 lines
Quoted 7 lines
Well ... it's like this. Native means "pass through without swapping" and has an easy implementation on both BE and LE platforms. Logically io{read,write}{16,32}be would have to do byte swaps on LE platforms. Being lazy, I'm opposed to doing the work if there's no actual use for it, so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
I would probably spell "native" as "noswap". "native" just doesn't convey enough specific meaning...
But that implies that the driver has to know that the bus and the device and the CPU are on the same byte endian etc.... that is rather specific, and if they all know, then they can also just use the correct "be" or "le" ... I really see no point in "native" abstraction.
Ben.
Re: iomapping a big endian area
In reply to James BottomleyQuoted 2 lines · James Bottomley
so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
The Network Processing Engines in the Intel IXP425 are big-endian and its XScale core may be run in little-endian mode. There's a bunch of gotchas related to running in little-endian mode so you typically run the IXP425 in big-endian mode, though.
David Vrabel
Signature · 4 lines
David Vrabel, Design Engineer Arcom, Clifton Road Tel: +44 (0)1223 411200 ext. 3233 Cambridge CB1 7EA, UK Web: http://www.arcom.com/
Re: iomapping a big endian area
Quoted 9 lines · David Vrabel
Quoted 2 lines · James Bottomley
so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
The Network Processing Engines in the Intel IXP425 are big-endian and its XScale core may be run in little-endian mode. There's a bunch of gotchas related to running in little-endian mode so you typically run the IXP425 in big-endian mode, though.
But the Linux interface (on the CPU side of the PCI bus interface) doesn't care about the implimentation details in the XScale Core. That's why it's a complete subsystem, isolated from the ix86 by the PCI/Bus interface.
Quoted 6 lines
David Vrabel
Signature · 4 lines
David Vrabel, Design Engineer Arcom, Clifton Road Tel: +44 (0)1223 411200 ext. 3233 Cambridge CB1 7EA, UK Web: http://www.arcom.com/
Cheers,
Dick Johnson
Penguin : Linux version 2.6.11 on an i686 machine (5537.79 BogoMips).
Notice : All mail here is now cached for review by Dictator Bush.
98.36% of all statistics are fiction.
Re: iomapping a big endian area
Quoted 5 lines · Richard B. Johnson
But the Linux interface (on the CPU side of the PCI bus interface) doesn't care about the implimentation details in the XScale Core. That's why it's a complete subsystem, isolated from the ix86 by the PCI/Bus interface.
Hmmm.
*takes a long hard look at the IXP425 based board in front of him*
You're right. It's really is a PCI add-on card for an x86 platform. All this time I've been thinking it was a standalone processor board. Thanks for clearing that up!
David Vrabel
ps. The IXP425 is an ARM (Intel's XScale architecture) based processor.
Re: iomapping a big endian area
In reply to David VrabelQuoted 4 lines · David Vrabel
The Network Processing Engines in the Intel IXP425 are big-endian and its XScale core may be run in little-endian mode. There's a bunch of gotchas related to running in little-endian mode so you typically run the IXP425 in big-endian mode, though.
Yes, based on feedback from Mips people and others pointing out the existence of the motorola rapidio bus, which is BE, I give in and agree that the io{read,write}{16,32}be are the way to go.
How does the attached look?
James
===== arch/parisc/lib/iomap.c 1.1 vs edited =====
arch/parisc/lib/iomap.c +64 -0
@@ -43,10 +43,14 @@struct iomap_ops {unsigned int (*read8)(void __iomem *);unsigned int (*read16)(void __iomem *); +unsigned int (*read16be)(void __iomem *);unsigned int (*read32)(void __iomem *); +unsigned int (*read32be)(void __iomem *);void (*write8)(u8 ,void __iomem *);void (*write16)(u16 ,void __iomem *); +void (*write16be)(u16 ,void __iomem *);void (*write32)(u32 ,void __iomem *); +void (*write32be)(u32 ,void __iomem *);void (*read8r)(void __iomem *,void *,unsigned long );void (*read16r)(void __iomem *,void *,unsigned long );void (*read32r)(void __iomem *,void *,unsigned long );
@@ -122,9 +126,13 @@static const struct iomap_ops ioport_ops = { ioport_read8, ioport_read16, + ioport_read16, + ioport_read32, ioport_read32, ioport_write8, ioport_write16, + ioport_write16, + ioport_write32, ioport_write32, ioport_read8r, ioport_read16r,
@@ -146,11 +154,21 @@return readw (addr); } +static unsigned int iomem_read16be (void __iomem *addr) +{ +return __raw_readw (addr); +} +static unsigned int iomem_read32 (void __iomem *addr) {return readl (addr); } +static unsigned int iomem_read32be (void __iomem *addr) +{ +return __raw_readl (addr); +} +static void iomem_write8 (u8 datum,void __iomem *addr) {writeb (datum, addr);
@@ -161,11 +179,21 @@writew (datum, addr); } +static void iomem_write16be (u16 datum,void __iomem *addr) +{ +__raw_writew (datum, addr); +} +static void iomem_write32 (u32 datum,void __iomem *addr) {writel (datum, addr); } +static void iomem_write32be (u32 datum,void __iomem *addr) +{ +__raw_writel (datum, addr); +} +static void iomem_read8r (void __iomem *addr,void *dst,unsigned long count) {while (count--) {
@@ -217,10 +245,14 @@static const struct iomap_ops iomem_ops = { iomem_read8, iomem_read16, + iomem_read16be, iomem_read32, + iomem_read32be, iomem_write8, iomem_write16, + iomem_write16be, iomem_write32, + iomem_write32be, iomem_read8r, iomem_read16r, iomem_read32r,
@@ -253,6 +285,13 @@return le16_to_cpup ((u16 *)addr); } +unsigned int ioread16be (void __iomem *addr) +{ +if (unlikely (INDIRECT_ADDR (addr))) +return iomap_ops[ADDR_TO_REGION (addr)]->read16be (addr); +return *((u16 *)addr); +} +unsigned int ioread32 (void __iomem *addr) {if (unlikely (INDIRECT_ADDR (addr)))
@@ -260,6 +299,13 @@return le32_to_cpup ((u32 *)addr); } +unsigned int ioread32be (void __iomem *addr) +{ +if (unlikely (INDIRECT_ADDR (addr))) +return iomap_ops[ADDR_TO_REGION (addr)]->read32be (addr); +return *((u32 *)addr); +} +void iowrite8 (u8 datum,void __iomem *addr) {if (unlikely (INDIRECT_ADDR (addr))) {
@@ -278,12 +324,30 @@ } } +void iowrite16be (u16 datum,void __iomem *addr) +{ +if (unlikely (INDIRECT_ADDR (addr))) { + iomap_ops[ADDR_TO_REGION (addr)]->write16be (datum, addr); + }else { + *((u16 *)addr) = datum; + } +} +void iowrite32 (u32 datum,void __iomem *addr) {if (unlikely (INDIRECT_ADDR (addr))) { iomap_ops[ADDR_TO_REGION (addr)]->write32 (datum, addr); }else { *((u32 *)addr) =cpu_to_le32 (datum); + } +} + +void iowrite32be (u32 datum,void __iomem *addr) +{ +if (unlikely (INDIRECT_ADDR (addr))) { + iomap_ops[ADDR_TO_REGION (addr)]->write32be (datum, addr); + }else { + *((u32 *)addr) = datum; } }
===== include/asm-generic/iomap.h 1.3 vs edited =====
include/asm-generic/iomap.h +5 -0
@@ -2,6 +2,7 @@#define __GENERIC_IO_H#include <linux/linkage.h> +#include <asm/byteorder.h> /* * These are the "generic" interfaces for doing new-style
@@ -26,11 +27,15 @@*/ extern unsigned int fastcall ioread8(void __iomem *); extern unsigned int fastcall ioread16(void __iomem *); +extern unsigned int fastcall ioread16be(void __iomem *); extern unsigned int fastcall ioread32(void __iomem *); +extern unsigned int fastcall ioread32be(void __iomem *); extern void fastcall iowrite8(u8, void __iomem *); extern void fastcall iowrite16(u16, void __iomem *); +extern void fastcall iowrite16be(u16, void __iomem *); extern void fastcall iowrite32(u32, void __iomem *); +extern void fastcall iowrite32be(u32, void __iomem *);/* * "string" versions of the above. Note that they
===== lib/iomap.c 1.6 vs edited =====
lib/iomap.c +20 -0
@@ -58,13 +58,23 @@ { IO_COND(addr, return inw(port), return readw(addr)); } +unsigned int fastcall ioread16be(void __iomem *addr) +{ + IO_COND(addr, return inw(port), return cpu_to_be16(__raw_readw(addr))); +} unsigned int fastcall ioread32(void __iomem *addr) { IO_COND(addr, return inl(port), return readl(addr)); } +unsigned int fastcall ioread32be(void __iomem *addr) +{ + IO_COND(addr, return inl(port), return cpu_to_be32(__raw_readl(addr))); +}EXPORT_SYMBOL (ioread8);EXPORT_SYMBOL (ioread16); +EXPORT_SYMBOL (ioread16be);EXPORT_SYMBOL (ioread32); +EXPORT_SYMBOL (ioread32be); void fastcall iowrite8(u8 val, void __iomem *addr) {
@@ -74,13 +84,23 @@ {IO_COND (addr,outw (val,port),writew (val, addr)); } +void fastcall iowrite16be(u16 val, void __iomem *addr) +{ +IO_COND (addr,outw (val,port),__raw_writew (be16_to_cpu (val), addr)); +} void fastcall iowrite32(u32 val, void __iomem *addr) {IO_COND (addr,outl (val,port),writel (val, addr)); } +void fastcall iowrite32be(u32 val, void __iomem *addr) +{ +IO_COND (addr,outl (val,port),__raw_writel (val, addr)); +}EXPORT_SYMBOL (iowrite8);EXPORT_SYMBOL (iowrite16); +EXPORT_SYMBOL (iowrite16be);EXPORT_SYMBOL (iowrite32); +EXPORT_SYMBOL (iowrite32be);/* * These are the "repeat MMIO read/write" functions.
Re: iomapping a big endian area
Quoted 11 lines · On Mon, 04 Apr 2005 13:57:59 -0500 James Bottomley…
Quoted 4 lines · David Vrabel
The Network Processing Engines in the Intel IXP425 are big-endian and its XScale core may be run in little-endian mode. There's a bunch of gotchas related to running in little-endian mode so you typically run the IXP425 in big-endian mode, though.
Yes, based on feedback from Mips people and others pointing out the existence of the motorola rapidio bus, which is BE, I give in and agree that the io{read,write}{16,32}be are the way to go.
How does the attached look?
This looks fine to me.
Re: iomapping a big endian area
In reply to James BottomleyQuoted 6 lines · James Bottomley
Quoted 1 line · Benjamin Herrenschmidt
I disagree. The driver will never "know" ...
? the driver has to know. Look at the 53c700 to see exactly how awful it is. This beast has byte and word registers. When used BE, all the byte registers alter their position (to both inb and readb).
What I mean is that the driver doesn't have "know" whatever CPU/bus combo endianness will require it to use "native" or "swapped" access. What the driver knows is wether the device it tries to access need BE or LE accessors.
Quoted 10 lines
Quoted 3 lines
I don't think it's sane. You know that your device is BE or LE and use the appropriate interface. "native" doesn't make sense to me in this context.
Well ... it's like this. Native means "pass through without swapping" and has an easy implementation on both BE and LE platforms. Logically io{read,write}{16,32}be would have to do byte swaps on LE platforms. Being lazy, I'm opposed to doing the work if there's no actual use for it, so can you provide an example of a BE bus (or device) used on a LE platform that would actually benefit from this abstraction?
I don't think drivers will benefit from "native" vs. "swapping". Taht means that pretty much all drivers that care will end up with #ifdef crap to pick up the right one based on the CPU endian, and some wil get it wrong of course. No, I _do_ thing that this should be hidden in the implementation, and we should provide "le" and "be" accessors (le beeing the current ones, be new ones). Which one swap or not is in the implementation of those accessors for the architecture, but the driver shouldn't have to care.
Ben.
Re: iomapping a big endian area
In reply to James BottomleyQuoted 10 lines · James Bottomley
Actually, ioread8be is unnecessary, but I was planning to add ioread16/ioread32 and iowritexx be on be variants (equivalent to
_raw_readwet al.)After all, the driver must know the card is BE, so the routines that make use of the feature are easily coded into the card, so there's no real need to add it to the iomem cookie.
Did anyone have a preference for the API? I was thinking
ioread32_native, but ioread32be is fine too.
I think we want "be" since obviously, the "ioread32" one is "le", that makes sense to provide both and let the implementation bother with what has to swap or not. With "native", x86 would do what ? swap or not swap ? unclear ... with "be", at least it's clear.
The problem ? Hehe, well ... there is at least one little problem: The way iomap "fixes" the issue of mem vs. io space in a driver could have been used to also fix le vs. be issues. For example, an USB OHCI controller is normally little endian. But some too-stupid-for-words HW folks tried to be too smart on a number of embedded chips, and put a big endian version of it. Thus the driver ends up having to support both. Most embedded vendors just butcher the driver with #ifdef's which is fine by me ... until you end up having _also_ a PCI bus with an EHCI/OHCI pair on it on the same board... then you are toast.
But, I wouldn't bother too much about this case. The driver has other issues than just IO to deal with (the DMA data structures in memory are also endian- swapped) so I suppose the entire driver need to be somewhat #included from a wrapper an compiled twice for different endians to get that right...
Ben.
Re: iomapping a big endian area
In reply to James BottomleyQuoted 10 lines · James Bottomley
Quoted 5 lines · Matthew Wilcox
Quoted 3 lines
SPARC64 can do it in the PTEs, but we just use raw physical addresses in our I/O accessors, and in those load/store instructions we can specify the endianness.
Ah right. So you'd prefer an
ioread8be()interface?Actually, ioread8be is unnecessary, but I was planning to add ioread16/ioread32 and iowritexx be on be variants (equivalent to
_raw_readwet al.)
Not so. There are two different styles of big endian. (Lets just face it, BE is fucked in the head anyway...)
physical bus: 31...24 23...16 15...8 7...0
BE version 1 (word invariant)
byte access byte 0 byte 1 byte 2 byte 3
word access 31-24 23-16 15-8 7-0
BE version 2 (byte invariant)
byte access byte 3 byte 2 byte 1 byte 0
word access 7-0 15-8 23-16 31-24
Depending on this and how your devices are wired up to such a bus, you may need to swap bytes in a word access, or munge the byte/half word address itself.
And guess which architecture implements *both* of these... Grumble.
Signature · 3 lines
Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: 2.6 Serial core
Re: iomapping a big endian area
Quoted 5 lines · Russell King
Not so. There are two different styles of big endian. (Lets just face it, BE is fucked in the head anyway...)
physical bus: 31...24 23...16 15...8 7...0
Quoted 7 lines
BE version 1 (word invariant)
byte access byte 0 byte 1 byte 2 byte 3
word access 31-24 23-16 15-8 7-0BE version 2 (byte invariant)
byte access byte 3 byte 2 byte 1 byte 0
word access 7-0 15-8 23-16 31-24
These are just representations of the same thing. However, I did deliberately elect not to try to solve this problem in the accessors. I know all about the register relayout, because 53c700 has to do that on parisc.
However, I don't think it's the job of the io accessors to remap the register locations (primarily because the remapping depends on the
documentation: a chip that's documented as BE on BE has no remapping required. Hoever, the same chip on LE would need this).
Quoted 1 line
And guess which architecture implements *both* of these... Grumble.
We have this in parisc too ...
James
Re: iomapping a big endian area
Quoted 10 lines · James Bottomley
Quoted 9 lines · Russell King
Not so. There are two different styles of big endian. (Lets just face it, BE is fucked in the head anyway...)
physical bus: 31...24 23...16 15...8 7...0
BE version 1 (word invariant)
byte access byte 0 byte 1 byte 2 byte 3
word access 31-24 23-16 15-8 7-0
Quoted 8 lines
Quoted 3 lines
BE version 2 (byte invariant)
byte access byte 3 byte 2 byte 1 byte 0
word access 7-0 15-8 23-16 31-24These are just representations of the same thing. However, I did deliberately elect not to try to solve this problem in the accessors. I know all about the register relayout, because 53c700 has to do that on parisc.
They aren't. On some of our platforms, we have to exclusive-or the address for byte accesses with 3 to convert to the right endian-ness.
Sure, from the point of view of which byte each byte of a word represents, it's true that they're indentical. But as far as the hardware is concerned, they're definitely different.
See the Intel IXP platforms for an example.
Signature · 3 lines
Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: 2.6 Serial core
Re: iomapping a big endian area
Quoted 10 lines · Russell King
Quoted 10 lines
Quoted 9 lines
physical bus: 31...24 23...16 15...8 7...0
BE version 1 (word invariant)
byte access byte 0 byte 1 byte 2 byte 3
word access 31-24 23-16 15-8 7-0BE version 2 (byte invariant)
byte access byte 3 byte 2 byte 1 byte 0
word access 7-0 15-8 23-16 31-24
Quoted 7 lines
Quoted 4 lines
These are just representations of the same thing. However, I did deliberately elect not to try to solve this problem in the accessors. I know all about the register relayout, because 53c700 has to do that on parisc.
They aren't. On some of our platforms, we have to exclusive-or the address for byte accesses with 3 to convert to the right endian-ness.
The same with certain MIPS configurations. And likewise you need to xor
addresses with 2 for halfword accesses.
Quoted 3 lines
Sure, from the point of view of which byte each byte of a word represents, it's true that they're indentical. But as far as the hardware is concerned, they're definitely different.
To clarify it a bit: both big and little endian representations are
always the same -- it's going to a domain of the reverse endianness that can be done in two different ways, i.e. by preserving either bit or byte ordering (as described above). Depending on the interpretation of data being passed you want one or the other. That's why some systems provide ways of doing both kinds of accesses in hardware (e.g. the host bus to PCI bridge) to save CPU cycles needed for bit shuffling otherwise.
Maciej
Re: iomapping a big endian area
In reply to Matthew WilcoxOK, I sent the patch off to Andrew. To complete the original problem, the attached is the patch that uses it in the parisc lasi driver (although, actually, it sets up 53c700 to work everywhere including BE on a LE system).
I changed some of the flags around to reflect the fact that we now have generic BE support in the driver (rather than the more limited force_le_on_be flag).
James
===== drivers/scsi/53c700.h 1.25 vs edited =====
drivers/scsi/53c700.h +22 -19
@@ -177,10 +177,10 @@struct device *dev;__u32 dmode_extra;/* adjustable bus settings */ __u32 differential:1; /* if we are differential */ -#ifdef CONFIG_53C700_LE_ON_BE +#ifdef CONFIG_53C700_BE /* This option is for HP only. Set it if your chip is wired for * little endian on this platform (which is big endian) */ - __u32 force_le_on_be:1; + __u32 chip_is_be:1;#endif __u32 chip710:1; /* set if really a 710 not 700 */ __u32 burst_disable:1; /* set to 1 to disable 710 bursting */
@@ -229,24 +229,29 @@/* * 53C700 Register Interface - the offset from the Selected base * I/O address */ -#ifdef CONFIG_53C700_LE_ON_BE -#define bE (hostdata->force_le_on_be ? 0 : 3) -#define bSWAP (hostdata->force_le_on_be) -/* This is terrible, but there's no raw version of ioread32. That means -* that on a be board we swap twice (once in ioread32 and once again to -* get the value correct) */ -#define bS_to_io (x) ((hostdata->force_le_on_be) ? (x) : cpu_to_le32(x)) -#elif defined(__BIG_ENDIAN) +#ifdef CONFIG_53C700_BE +#define bE (hostdata->chip_is_be ? 3: 0) +#ifdef __BIG_ENDIAN +#define bSWAP (!hostdata->chip_is_be) +#else +#define bSWAP (hostdata->chip_is_be); +#endif +#define NCR_ioread32 (x) ((hostdata->chip_is_be) ? ioread32be(x) : ioread32(x)) +#define NCR_iowrite32 (v, x) \ + ((hostdata->chip_is_be) ? iowrite32be((v), (x)) : iowrite32((v), (x))) +#else +#define NCR_ioread32 (x) ioread32(x) +#define NCR_iowrite32 (v, x) iowrite32((v), (x)) +#if defined(__BIG_ENDIAN)#define bE 3#define bSWAP 0 -#define bS_to_io (x) (x)#elif defined(__LITTLE_ENDIAN)#define bE 0#define bSWAP 0 -#define bS_to_io (x) (x)#else #error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined, did you include byteorder.h?"#endif +#endif #define bS_to_cpu (x) (bSWAP ? le32_to_cpu(x) : (x))#define bS_to_host (x) (bSWAP ? cpu_to_le32(x) : (x))
@@ -460,14 +465,13 @@ {const struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0 ]; -__u32 value =ioread32 (hostdata->base + reg); +__u32 value =NCR_ioread32 (hostdata->base + reg);#if 1 /* sanity check the register */ -if ((reg &0x3 ) !=0 ) -BUG (); +BUG_ON ((reg &0x3 ) !=0 );#endif -return bS_to_io (value); +return value; } static inline void
@@ -487,11 +491,10 @@#if 1 /* sanity check the register */ -if ((reg &0x3 ) !=0 ) -BUG (); +BUG_ON ((reg &0x3 ) !=0 );#endif - iowrite32(bS_to_io(value), hostdata->base + reg); + NCR_iowrite32(value, hostdata->base + reg); }#endif
===== drivers/scsi/Kconfig 1.88 vs edited =====
drivers/scsi/Kconfig +1 -1
@@ -951,7 +951,7 @@ many PA-RISC workstations & servers. If you do not know whether you have a Lasi chip, it is safe to say "Y" here. -config 53C700_LE_ON_BE +config 53C700_BE bool depends on SCSI_LASI700 default y
===== drivers/scsi/lasi700.c 1.27 vs edited =====
drivers/scsi/lasi700.c +2 -4
@@ -117,15 +117,13 @@if (dev->id.sversion ==LASI_700_SVERSION ) { hostdata->clock =LASI700_CLOCK ; - hostdata->force_le_on_be =1 ; + hostdata->chip_is_be =0 ; }else { hostdata->clock =LASI710_CLOCK ; - hostdata->force_le_on_be =0 ; + hostdata->chip_is_be =1 ; hostdata->chip710 =1 ; hostdata->dmode_extra =DMODE_FC2 ; } - -NCR_700_set_mem_mapped (hostdata); host =NCR_700_detect (&lasi700_template, hostdata, &dev->dev);if (!host)
Re: iomapping a big endian area
Quoted 8 lines · James Bottomley
OK, I sent the patch off to Andrew. To complete the original problem, the attached is the patch that uses it in the parisc lasi driver (although, actually, it sets up 53c700 to work everywhere including BE on a LE system).
I changed some of the flags around to reflect the fact that we now have generic BE support in the driver (rather than the more limited
force_le_on_beflag).
What I really don't like is that you still need ifdefs and wrappers to support BE and LE wired chips in the same driver. Shouldn't you set the BE or LE flag at iomap() time and always use the same accessors?
Re: iomapping a big endian area
Quoted 3 lines · Christoph Hellwig
What I really don't like is that you still need ifdefs and wrappers to support BE and LE wired chips in the same driver. Shouldn't you set the BE or LE flag at
iomap()time and always use the same accessors?
No, if you look how it works. On parisc, it can be either BE or LE depending on the chip wiring. There would be a case for selecting BE or LE by #define, but there's no case I know today where we have a driver that would always be BE.
James