You copied the Doc URL to your clipboard.

8.7. Example PCI device driver

The PCI component of the ARM Firmware Suite contains an example PCI device driver (in AFSv1_4\Source\Pci\Sources\example-driver.c). This demonstrates how a device driver:

  • finds the device

  • examines its registers

  • takes control of its interrupt.

These steps are carried out as follows:

  1. Check that the system supports PCI (or is a PCI host):

    /* Must be PCI host to initialise the bus */
      if (!uHALr_PCIHost ()) {	
        uHALr_printf ("Not PCI host - can't scan the bus \n");	
        return (OK);	
    }
    
  2. If the system is a PCI host, initialize the PCI subsystem:

    /* initialise the bus */
      uHALr_printf ("Initialising PCI");
      PCIr_Init ();
      uHALr_printf ("...done \n");
    
  3. Scan the system for the PCI device of interest. In this example, a Digital 21142 ethernet device (with a vendor ID of 0x1011 and a device ID of 0x0019):

    /* look for the Digital 21142 ethernet device */
    if (PCIr_FindDevice(DIGITAL, TULIP21142, 0, &bus, &slot,
                        &func) == 0) {
        unsigned int ioaddr, memaddr, irq ;
        int i ;
    

    The instance number in this case is 0 because the code is looking for the first instance. To find the next instance, make another call to PCIr_FindDevice() but with an instance of 1.

  4. If the device is found, print out the location of its command and status registers (CSRs) in PCI I/O and PCI Memory. The code is shown in Example 8.2.

    The addresses are from the PCI configuration header for the device. The device is addressed using the PCI bus number, slot number and function number returned by the call to PCIr_FindDevice() in the previous step.

    /* found it, tell the world */
    uHALr_printf("Found Digital 21142 ethernet device [%02d:%02d:%02d]\n",
           bus, slot, func) ;
    /* work out the location of its CSRs in PCI IO and PCI Memory */
    ioaddr = uHALr_PCICfgRead32 (bus, slot, func, PCI_MEM_BAR);
    ioaddr &= ~0x0F ;
    memaddr = uHALr_PCICfgRead32 (bus, slot, func, PCI_MEM_BAR+ 4);
    memaddr &= ~0xF ;
    uHALr_printf("\tCSRs are at 0x%08X (IO) and 0x%08X (Memory)\n",ioaddr, 
            memaddr) ;
    
  5. Make calls to read the device CSRs from PCI I/O space. The CSRs are 64-bit aligned:

    /* print out its CSRs (all 15) */
    for (i = 0; i < 15; i++) {
       uHALr_printf("\t\tCSR %02d: %08X\n", i, 
         uHALr_PCIIORead32(ioaddr + (i << 3))) ;
    }
    
  6. Find the interrupt number associated with this device from the PCI configuration header.

    /* Find its interrupt number and assign it */
    irq = uHALr_PCICfgRead8 (bus, slot, func,
                          PCI_INTERRUPT_LINE);
    uHALr_printf("\tIRQ is @ %d\n", irq) ;
    
  7. Initialize the µHAL interrupt subsystem and request control of the interrupts. At this point, if the device generates an interrupt, tulipInterrupt() is called.

    /* init the irq subsystem in uHAL */
    uHALr_InitInterrupts() ;
    /* assign the interrupt */
    uHALr_RequestInterrupt(irq, tulipInterrupt, 
      (unsigned char *)"Digital 21142 interrupt handler") ;
    

When the above program is run on a PCI supporting system, the output is similar to that shown in Example 8.3.

ARM Firmware Suite (uHAL v1.4)
Copyright ARM Ltd 1999-2002. All rights reserved.
Initialising...done 
Found Digital 21142 ethernet device [00:11:00]
CSRs are at 0x00000000 (IO) and 0x40000000 (Memory)
CSR 00: FE000000
CSR 01: FFFFFFFF
CSR 02: FFFFFFFF
CSR 03: B96998AD
CSR 04: 354F9D62
CSR 05: F0000000
CSR 06: 32000040
CSR 07: F3FE0000
CSR 08: E0000000
CSR 09: FFF483FF
CSR 10: FFFFFFFF
CSR 11: FFFE0000
CSR 12: 000000C6
CSR 13: FFFF0000
CSR 14: FFFFFFFF
IRQ is @ 15

This shows that the 21142 was found in slot 11 on bus 0. On this system (an Integrator) this means that the device generates interrupts using bit 15 of the interrupt controller. If it is moved to another PCI slot, it might generate a different interrupt.

Was this page helpful? Yes No