PCMCIA on ppc64, and the joys of io port ranges on mmio-only platforms

Olof Johansson olof at lixom.net
Wed May 9 20:32:29 EDT 2007


Hi,

We've got a very simple CF interface on our eval board, sitting on
localbus with a couple of gpios for control. mem and i/o port ranges
are mapped to two mmio ranges, i.e. 0xf0000000 and 0xf1000000 in our case.

I've got a pcmcia driver for the slot to handle all the probing, etc. It ioremaps both
the mem and io ranges, and provides that with the registered device:

        cf->mem_base = ioremap(mem->start, mem->end - mem->start);
        cf->io_base = ioremap(io->start, io->end - io->start);
[...]
        /* pcmcia layer only remaps "real" memory not iospace */
        cf->socket.io_offset = (unsigned long)cf->io_base;

        /* reserve chip-select regions */
        if (!request_mem_region(mem->start, mem->end + 1 - mem->start,
[...]
        if (!request_mem_region(io->start, io->end + 1 - io->start, driver_name))
[...]
        cf->socket.dev.parent = &ofdev->dev;
        cf->socket.ops = &electra_cf_ops;
        cf->socket.resource_ops = &pccard_static_ops;
        cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP | SS_CAP_MEM_ALIGN;
[...]

(I'll post the full driver separately, but wanted to bring this up first).

Bottom line is that io_offset points to the ioremap()ed memory, i.e a
64-bit kernel address.

The problems show up further up the stack, in this case in the
pata_pcmcia driver, where pcmcia_request_io() is used to handle the
address allocation. That in turn calls alloc_io_space(), which takes an
ioaddr_t * as argument and does math on it.

ioaddr_t is 32-bit, causing obvious problems since io_offset is
64-bit. There's a compatible kio_addr_t available, but I'm guessing it's
already not used because of ABI requiremenets given the big warning at
the definition of ioaddr_t.

Since ppc64 never has had pcmcia before (We're the first platform with
it), changing the type under ifdef like mips/arm shouldn't be a problem,
at least it won't lead to regressions -- there's no previous user apps
to regress.


However, that's not enough in this case: Next thing that will fail is
ioport_map() in ppc-specific code, called from devm_ioport_map(). It
currently assumes to be passed the bus-local port number and adding
it to the ioremap base of the (normally only) bus with I/O ports,
i.e. ISA/LPC. Since we already use that for other devices (UARTS, etc),
we now have more than one base register.

I see two ways to solve this:

1. Create infrastructure to track the various io-port ranges, register
them and let the infrastructure take care of the ioremap, pick the right
ioport_map(), etc. I.e. create virtual io port ranges.

2. Make ioport_map() detect already mapped arguments (i.e.:
+       if (port >= IMALLOC_BASE && (port+len) < IMALLOC_END)
+               return (void __iomem *)port;

(1) would be appealing if it was the only change needed, and if that
meant that I didn't have to change ioaddr_t. It doesn't though, since
the pcmcia code still stores the ioport_map():ed value in an ioaddr_t,
so it really just adds complexity without that much benefit.

I'm tempted to go with (2) + type change but if someone has a third
option I'm all ears.


-Olof



More information about the linux-pcmcia mailing list