Messages in this thread | | | From | "Petr Vandrovec Ing. VTEI" <> | Date | Thu, 12 Nov 1998 18:59:02 MET-1 | Subject | Accessing MMIO PCI space - crossplatform |
| |
Hello Linus, hello everyone, I asked few days ago about correct way to crossplatform accesses to PCI MMIO - specifically how to access MMIO with same code on Alpha and PPC. Unfortunately, there was only one reply - whether I'm porting matroxfb to Alpha. Yes, I'm. So again, currently I'm using char* virtual = ioremap(pcidev->base_address[x], 8MB); and then virtual[y*size + x] = pixel; for writting or pixel = virtual[y*size + x]; for reading and iounmap(virtual); at the end for release resources. But I was pointed to that this does not work on Alpha - driver must use writex and readx macros. Unfortunately, these macros DO NOT work for me: 1) they probably works on Alpha as expected, so no problem there 2) they do not work at all on PPC because of they swap bytes to little endian format. While it is (I'm not too much sure) probably correct for accesses to other hardware, it is not correct for access to Matrox devices. They (Matroxes) know about PPC and expect bytes in big-endian ordering. So I cannot use writel/readl on PPC. Except that, it is not possible to tell to memcpy_toio whether it should swap nothing (byte stream), words or dwords while copying... On __arm__ (Arm does not have PCI, so no problem) it copies memory byte-by-byte, so it is completely unusable if hardware expects only 32-bit (or 64-bit) accesses :-( 3) writel/readl even DOES NOT work on ia32 with 2GB of memory. When someone sets PAGE_OFFSET to 0x70000000, and then has machine with (f.e.) 512MB of memory, physical memory is mapped from 0x70000000 to 0x8FFFFFFF. So ioremap() returns some value around 0x90000000. After oring it with 0x70000000, driver gets 0xF0000000 and dies very quickly :-( Whole concept of PAGE_OFFSET (and or-ing whith PAGE_OFFSET) works only if you restrict PAGE_OFFSET that value must be valid as "ipv4 netmask" (0x80000000, 0xC0000000, 0xE0000000 ...), so it is a bit useless (0x80000000 is not enough for 2GB of memory). I think, that, at least on Intel: a) every driver should be fixed to use ioremap b) readl/writel should not do anything with address c) virt_to_phys and virt_to_bus should walk through pagetables instead of anding/oring with something with something (or explicitly say that they cannot be used for shared (adaptor) memory... after reading up and down through IO-mapping it looks clear to me, but...) (after this change, you can do DMA I/O directly to/from userspace much easier) d) phys_to_virt, bus_to_virt should be removed, it cannot be done in linear time (I'm not aware of such solution (on ia32)) and ioremap is already here and should be used instead of this one-time translation) (or explicitly say that for shared (adaptor) memory it cannot be used) e) that means: 1) clear readl/writel interface that passed address must be obtained from ioremap (so first example fro IO-mapping.txt - - readl(0xC0000) - is wrong). On ia32, ioremap can return virtual address and readl/writel are simple reading/writting (no playing with PAGE_OFFSET), on alpha, ioremap can return bus address and readl/writel are complicated function as they are now. 2) same for memcpy_toio, memcpy_fromio, memset_io, so examples for these functions in IO-mapping.txt are no longer valid. f) it must be done before 2.2, because of otherwise it is not possible to have more than 1.8 GB of memory in an Intel box (you can have it... but you cannot use it as system memory) (I know that no one real user uses ia32 this time, but there are such) So unless someone has more correct solution (please, please), I have to use #ifdef __alpha__ #define mga_readl(x) readl(x) #else #define mga_readl(x) (*(volatile u_int32_t*)(x)) #endif But I do not want to have this crappy code in my driver because of I think that it should not be there (I've found only four #ifdef __alpha__ in drivers subtree of kernel, so I think that it is not right way to go). Thanks, Petr Vandrovec vandrove@vc.cvut.cz P.S.: I cannot believe to (3f), so I'm probably wrong... But I'm searching solution for more than week and I still have nothing. P.P.S.: For Dave and/or Jakub (and others): On __sparc__, __sparc64__ (one PCI sparc is probably coming here next year) and other non-listed ports (__m68k__), what is better, safe and working - (*(volatile u_int32_t*)(x)) or readl(x) ? P.P.P.S.: Yes, I read Documentation/IO-mapping.txt couple of times. P.P.P.P.S.: It (IO-mapping.txt) is a bit outdated, isn't it? unsigned long signature = *(unsigned int*)0xC0000; (at the end of doc) never worked in 2.1, isn't it? P.P.P.P.P.S.: While I'm talking about ioremap, is there any chance that ioremap_nocache or __ioremap will exist on non-ia32? Otherwise I have to use #ifdef __i386__ ... Can I achieve same (similar) effect by MTRR on non-Intel or non-PII (non-P6)? I do not believe that every PC hardware around can handle this correctly without _nocache.
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |