6.4 About the Bus Model

The device driver model in Oracle Linux uses global data structures to present data and control operations to the bus drivers for bridges and other devices. This uniform data model for describing a bus and its devices defines the bus attributes and callbacks for bus probing, device discovery, shutdown, power management, and other control operations. The model supports plug and play, power management, and hot plug functionality specified by the Advanced Configuration and Power Interface (ACPI) model, which applies to most devices in a modern x86 or x86-64 architecture system. A device driver registers its driver object with the bus subsystem. It can then use the vendor and product identifiers to determine if the hardware is present.

The kernel defines a common data structure for each bus that can be accessed by individual layers of a bus or by individual device drivers.

For example, the pci_bus data structure represents a 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 list_head slots;         /* list of slots on this bus */
        struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
        struct list_head resources;     /* 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 */
        unsigned char   max_bus_speed;  /* enum pci_bus_speed */
        unsigned char   cur_bus_speed;  /* enum pci_bus_speed */

        char            name[48];

        unsigned short  bridge_ctl;     /* manage NO_ISA/FBB/et al behaviors */
        pci_bus_flags_t bus_flags;      /* Inherited by child busses */
        struct device           *bridge;
        struct device           dev;
        struct bin_attribute    *legacy_io; /* legacy I/O for this bus */
        struct bin_attribute    *legacy_mem; /* legacy mem */
        unsigned int            is_added:1;
};

The pci_slot structure represents a slot on a PCI bus:

struct pci_slot {
        struct pci_bus *bus;            /* The bus this slot is on */
        struct list_head list;          /* node in list of slots on this bus */
        struct hotplug_slot *hotplug;   /* Hotplug info (migrate over time) */
        unsigned char number;           /* PCI_SLOT(pci_dev->devfn) */
        struct kobject kobj;
};

The pci_dev structure defines each device on a PCI bus:

struct pci_dev {
        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 */
        struct pci_slot *slot;          /* Physical slot this device is in */

        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) */
        ...
        struct pci_driver *driver;      /* which driver has allocated this device */
        ...
        pci_channel_state_t error_state;        /* current connectivity state */
        struct  device  dev;            /* Generic device interface */

        int             cfg_size;       /* Size of configuration space */

        /*
         * 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 and memory regions
                                                            & expansion ROMs */
        resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
        ...
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
        /* Several lines omitted */
};

Only some of the more important structure members are shown here.

There is one pci_dev structure for each combination of slot and function number. Every PCI device in a system, including PCI-PCI and PCI-ISA bridge devices, is represented by a pci_dev structure.

The struct device dev member of pci_dev represents the generic interface for a device. A PCI bus layer can access the members of this structure. However, individual PCI device drivers do not usually need to be able to access the structure. This abstraction prevents downstream drivers from breaking if a member of the structure is altered or removed. Only the code for the bus layer need be modified.

As with other bus-based subsystems, a PCI device driver registers its driver object with the PCI subsystem. It can then use vendor and device identifiers to determine if the hardware is present.