4

I am trying to communicate with a custom (not designed by me) ISA board with an x86 single board computer running redhat 6.2. The only information I have for how to communicate with this custom board are the ISA bus addresses and data that this custom board responds to (and this I only found out by hooking the ISA bus to a logic analyzer).

For example, one common bus address I'd see is 0xE30000, which accesses an FPGA on the custom board. Originally I had hoped that the bus address and physical address for the single board computer were the same. That would allow me to mmap/ioremap the assumed physical address 0xE30000 to some virtual address that I could write to. Unfortunately redhat's kernel doesn't allow userspace to mmap to an address that high. When I tried getting access to it in a kernel module I wrote, I eventually found out that that physical address is already reserved for system RAM:

[root@rheldev ~]# cat /proc/iomem
00000000-00000fff : reserved
00001000-0009dfff : System RAM
0009e000-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000cbfff : Video ROM
000e0000-000fffff : reserved
  000f0000-000fffff : System ROM
00100000-07ffffff : System RAM  // <--- 0xE30000 sits in there
  00400000-008364e2 : Kernel code
  008364e3-00a917c7 : Kernel data
  00b15000-00c3af6f : Kernel bss
c0000000-c3ffffff : 0000:00:00.0
e0000000-e0000fff : 0000:00:0f.0
  e0000000-e0000fff : e100
e0020000-e003ffff : 0000:00:0f.0
  e0020000-e003ffff : e100
ff000000-ff00ffff : 0000:00:0f.0
fff00000-ffffffff : reserved

So now I'm back to square one looking for a way to write to the ISA bus. I haven't found much as far as ISA drivers go, though I did find an open source PC/104 driver here. Looking into it, however, it uses port mapping to write to the bus, and I couldn't see how to make sure writing to port X puts the desired bus address 0xE30000 on the ISA (and/or PC/104) bus.

I'll admit this is an area completely outside my area of understanding. This seems incredibly basic and simple that it shouldn't be too much of an issue, but it's old enough protocols that finding info on them has not been as straightforward as I had hoped. Thanks in advance for any resources/tutorials/examples you can point me towards!

Update:

Thank you @dirkt for the reply pointing me in the right direction! I was trying to get at the ISA bus directly, when it's actually a bridge connected to the PCI bus:

[root@rheldev ~]# lspci
00:00.0 Host bridge: VIA Technologies, Inc. VT8605 [ProSavage PM133]
00:01.0 PCI bridge: VIA Technologies, Inc. VT8605 [PM133 AGP]
00:07.0 ISA bridge: VIA Technologies, Inc. VT82C686 [Apollo Super South] (rev 40)
00:07.1 IDE interface: VIA Technologies, Inc. VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06)
00:07.4 Non-VGA unclassified device: VIA Technologies, Inc. VT82C686 [Apollo Super ACPI] (rev 40)
00:0f.0 Ethernet controller: Intel Corporation 8255xER/82551IT Fast Ethernet Controller (rev 10)

Digging around, there wasn't much in /sys/bus/isa/, but the 00:07:0 ISA Bridge does show up under /sys/bus/pci/devices/. Here are the contents of that folder:

[root@rheldev 0000:00:07.0]# ls
broken_parity_status  enable         msi_bus  reset             uevent
class                 irq            power    resource          vendor
config                local_cpulist  ppdev    subsystem
device                local_cpus     remove   subsystem_device
driver                modalias       rescan   subsystem_vendor

So now to update my question: How do I read from and write to an ISA bus via an ISA bridge attached to a PCI bus?

I've seen a couple sites talking about using lower memory/ports to get at the ISA bus, but I don't feel that will work for me since I need to work with much higher ISA addresses (Starting at 0xE00000). (see also my comment on @dirkt's answer)

Again, any resources you can point me to on how to tell the PCI bus that I want to talk to that ISA bridge so I can put higher ISA bus addresses on the ISA bus is greatly appreciated. Thanks!

Update 2:

While looking into lilo as suggested by @dirkt, I noticed that my redhat 6 installation was using legacy grub instead of grub 2, so I decided to see what grub 2 would do with the memory hole enabled first. After locally compiling and manually installing it on my machine (since there was no redhat 6 package for it), things seem to be working better than I had hoped!

I added kernel line arguments in grub to mark the memory from 14MB-16MB as reserved, and the kernel seems to honor that request and marks those addresses as reserved in /proc/iomem/. As indicated in my comment to @dirkt, I did not expect the kernel to correctly mark it as reserved, but it would seem that I was looking at older kernel source code than what redhat 6.2 uses.

With a simple C program and a logic analyzer I can see data go across the reading/writing to those addresses! The next step is to write a proper kernel module to correctly handle reading and writing to the ISA bus, but now that it's working that should be a relative breeze!

  • 2
    Why the close vote? This is a question about how the Linux kernel handles low-level I/O, which is perfectly on-topic. – dirkt May 11 '17 at 10:06
2

I can only give a somewhat generic answer, but that hopefully will point you in the right direction.

You didn't say what x86 board you use, but on non-ancient systems, the ISA bus will be behind a PCI-to-ISA bridge. You can use lspci to find this bridge. The bridge will provide a mapping of the main memory and I/O space to the ISA bus memory and I/O space. This is set up by the kernel on boot according to the information given in the BIOS, namely ACPI including legacy PNP. You can see information about this process in dmesg after boot.

Even on modern system, there are still legacy ISA devices, though they are now on the LPC bus, and not on a real ISA bus. The Linux kernel drivers for such device, i.e. the 8042 PS/2 keyboard/mouse driver (see drivers/input/serio) then reserve the ports they need (request_region) on init (i8042_platform_init in i8042-io.h), release them on exit, and to port I/O (inb, outb etc.) to communicate with it. I don't know how it works for memory access, but probably similar. The reserved ports show up in /proc/ioports.

The bridge should show up in /sys/bus/pci/devices, maybe you can find additional information there. There's also /sys/bus/isa, but I'm not sure under which circumstances the kernel will populate this with information.

So first I'd try to see if the board reacts to some I/O ports. Also try the PNP enumeration procedure (or check dmesg if this isn't done at boot already), if it responds to that, the rest will be a lot easier.

Finally, I'd try figure out how your PCI-to-ISA bridge maps memory space, what kernel operations you need to reserve this memory space, and then you can again probe it and see if anything happens.

Edit:

The book Linux Device Drivers, 3rd edition has some information about accessing ISA memory in section 9.4.5.

Edit:

Things to try:

1) Boot with lilo instead of grub, enable "hole" (ISA-mapping) in BIOS, see if it boots. Yes, lilo still works.

2) Google for VIA VT82C686A South Bridge data sheet. In the PCI configuration space if the PCI-to-ISA bridge, there's the following register:

Offset 43 - ROM Decode Control  

Setting these bits enables the indicated address range to be
included in the ROMCS# decode:  

7    FFFE0000h-FFFEFFFFh  
6    FFF80000h-FFFDFFFFh 
5    000E8000h-000EFFFFh  
4    000E0000h-000E7FFFh 
3    000D8000h-000DFFFFh  
2    000D0000h-000D7FFFh  
1    000C8000h-000CFFFFh 
0    000C0000h-000C7FFFh  

So I guess you can try to enable the "hole" (ISA mapping) after boot, and check with the logicanalyser if it works. Using FFFE0000h instead of 000E0000h is also worth a try if the card doesn't decode high bits.

I don't know how to properly do this, and inform the Linux kernel of the changed mapping. Maybe there are also boot options for this.

I know you can access the PCI configuration space via the pseudo-file /sys/bus/pci/devices/0000:00:07.0/config, so you can even try this outside of a kernel driver.

3) Definitely check dmesg and /sys/bus/pnp to see if your card already enumerates. If you can't make sense of the dmesg output, put it in a pastebin and post a link; I can have a look.

  • Fun fact: Linux Devices Drivers talks about that chunk of lower memory from 640KB to 1MB. There's actually another memory hole higher up between 14MB and 16MB that can be enabled to directly routed to the ISA bus, and those are the addresses I need (0xE00000 -> 14MB). Unfortunately GRUB won't boot linux when that hole is enabled in the BIOS, and apparently linux doesn't really know how to properly handle the memory hole and treats it like normal system memory. If that hole were an option I'd know exactly how to talk on the bus with the addresses I need, but without it I need an alternate way.. – cjameston May 11 '17 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.