Chapter 4. PCI System Initialization

As part of the Linux kernel boot process, all PCI buses and devices are scanned, configuration space is initialized, and kernel data structures are created to map to these devices. This process is initiated well before any PCI device drivers are called to initialize their devices.

The Linux kernel creates a data structure to map each discovered PCI bus and a PCI device data structure to map each PCI device on that PCI bus. The following structures are examples of a pci_bus structure created for each PCI bus (Example 4-1) and a pci_dev structure created for each PCI device (Example 4-2), respectively.

Example 4-1. pci_bus structure created for each PCI bus

struct pci_bus {
        struct list_head node;          /* node in list of buses */
        struct pci_bus  *parent;        /* parent bus this bridge is on */
        struct list_head children;      /* list of child buses */
        struct list_head devices;       /* list of devices on this bus */
        struct pci_dev  *self;          /* bridge device as seen by parent */
        struct resource *resource[4];   /* address space routed to this bus */

        struct pci_ops  *ops;           /* configuration access functions */
        void            *sysdata;       /* hook for sys-specific extension */
        struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */

        unsigned char   number;         /* bus number */
        unsigned char   primary;        /* number of primary bridge */
        unsigned char   secondary;      /* number of secondary bridge */
        unsigned char   subordinate;    /* max number of subordinate buses */

        char            name[48];
        unsigned short  vendor;
        unsigned short  device;
        unsigned int    serial;         /* serial number */
        unsigned char   pnpver;         /* Plug & Play version */
        unsigned char   productver;     /* product version */
        unsigned char   checksum;       /* if zero - checksum passed */
        unsigned char   pad1;
};


Example 4-2. pci_dev structure created for each PCI device

struct pci_dev {
        struct list_head global_list;   /* node in list of all PCI devices */
        struct list_head bus_list;      /* node in per-bus list */
        struct pci_bus  *bus;           /* bus this device is on */
        struct pci_bus  *subordinate;   /* bus this device bridges to */

        void            *sysdata;       /* hook for sys-specific extension */
        struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */

        unsigned int    devfn;          /* encoded device & function index */
        unsigned short  vendor;
        unsigned short  device;
        unsigned short  subsystem_vendor;
        unsigned short  subsystem_device;
        unsigned int    class;          /* 3 bytes: (base,sub,prog-if) */
        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */
        u8              rom_base_reg;   /* which config register controls the ROM */

        struct pci_driver *driver;      /* which driver has allocated this device */
        void            *driver_data;   /* data private to the driver */
        u64             dma_mask;       /* Mask of the bits of bus address this
                                           device implements.  Normally this is
                                           0xffffffff.  You only need to change
                                           this if your device has broken DMA
                                           or supports 64-bit transfers.  */

        u32             current_state;  /* Current operating state. In ACPI-speak,
                                           this is D0-D3, D0 being fully functional,
                                           and D3 being off. */

        /* device is compatible with these IDs */
        unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
        unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];

        /*
         * Instead of touching interrupt line and base address registers
         * directly, use the values stored here. They might be different!
         */
        unsigned int    irq;
        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O, memory, ROMS regions*/
        struct resource dma_resource[DEVICE_COUNT_DMA];
        struct resource irq_resource[DEVICE_COUNT_IRQ];

        char            name[80];       /* device name */
        char            slot_name[8];   /* slot name */
        int             active;         /* ISAPnP: device is active */
        int             ro;             /* ISAPnP: read only */
        unsigned short  regs;           /* ISAPnP: supported registers */

        int (*prepare)(struct pci_dev *dev);    /* ISAPnP hooks */
        int (*activate)(struct pci_dev *dev);
        int (*deactivate)(struct pci_dev *dev);
};


A PCI bus is uniquely identified by a PCI bus number ( pci_dev.number) A PCI device is uniquely identified by its device and function number ( pci_ dev.devfn) and the bus it is on ( pci_dev.bus->number).

As you can observe from the data structures in Example 4-1, and Example 4-2, the PCI buses are linked together and each pci_bus structure is also linked to its own PCI devices. All the PCI devices are also linked.

At the end of the system PCI initialization, the Linux kernel has the following initialization status: