|  | The U-Boot Driver Model Project | 
|  | =============================== | 
|  | PCI subsystem analysis | 
|  | ====================== | 
|  |  | 
|  | Pavel Herrmann <morpheus.ibis@gmail.com> | 
|  | 2012-03-17 | 
|  |  | 
|  | I) Overview | 
|  | ----------- | 
|  |  | 
|  | U-Boot already supports multiple PCI busses, stored in a linked-list of | 
|  | pci_controller structures. This structure contains generic driver data, bus | 
|  | interface operations and private data for the driver. | 
|  |  | 
|  | Bus interface operations for PCI are (names are self-explanatory): | 
|  |  | 
|  | read_byte() | 
|  | read_word() | 
|  | read_dword() | 
|  | write_byte() | 
|  | write_word() | 
|  | write_dword() | 
|  |  | 
|  | Each driver has to implement dword operations, and either implement word and | 
|  | byte operations, or use shared $operation_config_$type_via_dword (eg. | 
|  | read_config_byte_via_dword and similar) function. These functions are used | 
|  | for config space I/O (read_config_dword and similar functions of the PCI | 
|  | subsystem), which is used to configure the connected devices for standard MMIO | 
|  | operations. All data transfers by respective device drivers are then done by | 
|  | MMIO | 
|  |  | 
|  | Each driver also defines a separate init function, which has unique symbol | 
|  | name, and thus more drivers can be compiled in without colliding. This init | 
|  | function is typically called from pci_init_board(), different for each | 
|  | particular board. | 
|  |  | 
|  | Some boards also define a function called fixup_irq, which gets called after | 
|  | scanning the PCI bus for devices, and should dismiss any interrupts. | 
|  |  | 
|  | Several drivers are also located in arch/ and should be moved to drivers/pci. | 
|  |  | 
|  | II) Approach | 
|  | ------------ | 
|  |  | 
|  | The pci_controller structure needs to be broken down to fit the new driver | 
|  | model. Due to a large number of members, this will be done through three | 
|  | distinct accessors, one for memory regions, one for config table and one for | 
|  | everything else. That will make the pci_ops structure look like this: | 
|  |  | 
|  | struct pci_ops { | 
|  | int (*read_byte)(struct instance *bus, pci_dev_t *dev, int addr, | 
|  | u8 *buf); | 
|  | int (*read_word)(struct instance *bus, pci_dev_t *dev, int addr, | 
|  | u16 *buf); | 
|  | int (*read_dword)(struct instance *bus, pci_dev_t *dev, int addr, | 
|  | u32 *buf); | 
|  | int (*write_byte)(struct instance *bus, pci_dev_t *dev, int addr, | 
|  | u8 val); | 
|  | int (*write_byte)(struct instance *bus, pci_dev_t *dev, int addr, | 
|  | u8 val); | 
|  | int (*write_dword)(struct instance *bus, pci_dev_t *dev, int addr, | 
|  | u32 val); | 
|  | void (*fixup_irq)(struct instance *bus, pci_dev_t *dev); | 
|  | struct pci_region* (*get_region)(struct instance *, uint num); | 
|  | struct pci_config_table* (*get_cfg_table)(struct instance *bus); | 
|  | uint (*get_option)(struct instance * bus, enum pci_option_code op); | 
|  | } | 
|  |  | 
|  | enum pci_option_code { | 
|  | PCI_OPT_BUS_NUMBER=0, | 
|  | PCI_OPT_REGION_COUNT, | 
|  | PCI_OPT_INDIRECT_TYPE, | 
|  | PCI_OPT_AUTO_MEM, | 
|  | PCI_OPT_AUTO_IO, | 
|  | PCI_OPT_AUTO_PREFETCH, | 
|  | PCI_OPT_AUTO_FB, | 
|  | PCI_OPT_CURRENT_BUS, | 
|  | PCI_OPT_CFG_ADDR, | 
|  | } | 
|  |  | 
|  | The return value for get_option will be an unsigned integer value for any | 
|  | option code. If the option currently is a pointer to pci_region, it will | 
|  | return an index for get_region function. Special case has to be made for | 
|  | PCI_OPT_CFG_ADDR, which should be interpreted as a pointer, but it is only | 
|  | used for equality in find_hose_by_cfg_addr, and thus can be returned as an | 
|  | uint. Other function using cfg_addr value are read/write functions for | 
|  | specific drivers (especially ops for indirect bridges), and thus have access | 
|  | to private_data of the driver instance. | 
|  |  | 
|  | The config table accessor will return a pointer to a NULL-terminated array of | 
|  | pci_config_table, which is supplied by the board in platform_data, or NULL if | 
|  | the board didn't specify one. This table is used to override PnP | 
|  | auto-initialization, or to specific initialization functions for non-PNP | 
|  | devices. | 
|  |  | 
|  | Transparent PCI-PCI bridges will get their own driver, and will forward all | 
|  | operations to operations of their parent bus. This however makes it | 
|  | impossible to use instances to identify devices, as not all devices will be | 
|  | directly visible to the respective bus driver. | 
|  |  | 
|  | Init functions of controller drivers will be moved to their respective | 
|  | probe() functions, in accordance to the driver model. | 
|  |  | 
|  | The PCI core will handle all mapping functions currently found in pci.c, as | 
|  | well as proxy functions for read/write operations of the drivers. The PCI | 
|  | core will also handle bus scanning and device configuration. | 
|  |  | 
|  | The PnP helper functions currently in pci_auto.c will also be a part of PCI | 
|  | core, but they will be exposed only to PCI controller drivers, not to other | 
|  | device drivers. | 
|  |  | 
|  | The PCI API for device drivers will remain largely unchanged, most drivers | 
|  | will require no changes at all, and all modifications will be limited to | 
|  | changing the pci_controlle into instance*. | 
|  |  | 
|  | III) Analysis of in-tree drivers | 
|  | -------------------------------- | 
|  |  | 
|  | A) drivers in drivers/pci/ | 
|  | -------------------------- | 
|  |  | 
|  | pci_indirect.c | 
|  | -------------- | 
|  | Shared driver for indirect PCI bridges, several CONFIG macros - will | 
|  | require significant cleanup. | 
|  |  | 
|  | pci_ixp.c | 
|  | --------- | 
|  | Standard driver, specifies all read/write functions separately. | 
|  |  | 
|  | pci_sh4.c | 
|  | --------- | 
|  | Shared init function for SH4 drivers, uses dword for read/write ops. | 
|  |  | 
|  | pci_sh7751.c | 
|  | ------------ | 
|  | Standard driver, uses SH4 shared init. | 
|  |  | 
|  | pci_sh7780.c | 
|  | ------------ | 
|  | Standard driver, uses SH4 shared init. | 
|  |  | 
|  | tsi108_pci.c | 
|  | ------------ | 
|  | Standard driver, uses dword for read/write ops. | 
|  |  | 
|  | fsl_pci_init.c | 
|  | -------------- | 
|  | Driver for PCI and PCI-e, uses indirect functions. | 
|  |  | 
|  | pci_ftpci100.c | 
|  | -------------- | 
|  | Standard driver, uses indirect functions, has separate scan/setup | 
|  | functions. | 
|  |  | 
|  | B) driver in arch/ | 
|  | ------------------ | 
|  |  | 
|  | x86/lib/pci_type1.c | 
|  | ------------------- | 
|  | Standard driver, specifies all read/write functions separately. | 
|  |  | 
|  | m68k/cpu/mcf5445x/pci.c | 
|  | ----------------------- | 
|  | Standard driver, specifies all read/write functions separately. | 
|  |  | 
|  | m68k/cpu/mcf547x_8x/pci.c | 
|  | ------------------------- | 
|  | Standard driver, specifies all read/write functions separately. | 
|  |  | 
|  | powerpc/cpu/mpc824x/pci.c | 
|  | ------------------------- | 
|  | Standard driver, uses indirect functions, does not setup HW. | 
|  |  | 
|  | powerpc/cpu/mpc8260/pci.c | 
|  | ------------------------- | 
|  | Standard driver, uses indirect functions. | 
|  |  | 
|  | powerpc/cpu/ppc4xx/4xx_pci.c | 
|  | ---------------------------- | 
|  | Standard driver, uses indirect functions. | 
|  |  | 
|  | powerpc/cpu/ppc4xx/4xx_pcie.c | 
|  | ----------------------------- | 
|  | PCI-e driver, specifies all read/write functions separately. | 
|  |  | 
|  | powerpc/cpu/mpc83xx/pci.c | 
|  | ------------------------- | 
|  | Standard driver, uses indirect functions. | 
|  |  | 
|  | powerpc/cpu/mpc83xx/pcie.c | 
|  | -------------------------- | 
|  | PCI-e driver, specifies all read/write functions separately. | 
|  |  | 
|  | powerpc/cpu/mpc5xxx/pci_mpc5200.c | 
|  | --------------------------------- | 
|  | Standard driver, uses dword for read/write ops. | 
|  |  | 
|  | powerpc/cpu/mpc512x/pci.c | 
|  | ------------------------- | 
|  | Standard driver, uses indirect functions. | 
|  |  | 
|  | powerpc/cpu/mpc85xx/pci.c | 
|  | ------------------------- | 
|  | Standard driver, uses indirect functions, has two busses. | 
|  |  | 
|  | C) drivers in board/ | 
|  | -------------------- | 
|  |  | 
|  | eltec/elppc/pci.c | 
|  | ----------------- | 
|  | Standard driver, uses indirect functions. | 
|  |  | 
|  | amirix/ap1000/pci.c | 
|  | ------------------- | 
|  | Standard driver, specifies all read/write functions separately. | 
|  |  | 
|  | prodrive/p3mx/pci.c | 
|  | ------------------- | 
|  | Standard driver, uses dword for read/write ops, has two busses. | 
|  |  | 
|  | esd/cpci750/pci.c | 
|  | ----------------- | 
|  | Standard driver, uses dword for read/write ops, has two busses. | 
|  |  | 
|  | esd/common/pci.c | 
|  | ---------------- | 
|  | Standard driver, uses dword for read/write ops. | 
|  |  | 
|  | dave/common/pci.c | 
|  | ----------------- | 
|  | Standard driver, uses dword for read/write ops. | 
|  |  | 
|  | ppmc7xx/pci.c | 
|  | ------------- | 
|  | Standard driver, uses indirect functions. | 
|  |  | 
|  | Marvell/db64360/pci.c | 
|  | --------------------- | 
|  | Standard driver, uses dword for read/write ops, has two busses. | 
|  |  | 
|  | Marvell/db64460/pci.c | 
|  | --------------------- | 
|  | Standard driver, uses dword for read/write ops, has two busses. | 
|  |  | 
|  | evb64260/pci.c | 
|  | -------------- | 
|  | Standard driver, uses dword for read/write ops, has two busses. | 
|  |  | 
|  | armltd/integrator/pci.c | 
|  | ----------------------- | 
|  | Standard driver, specifies all read/write functions separately. | 
|  |  | 
|  | All drivers will be moved to drivers/pci. Several drivers seem | 
|  | similar/identical, especially those located under board, and may be merged | 
|  | into one. |