PCI documentation update for 2.3.42

From: Martin Mares (mj@suse.cz)
Date: Mon Feb 07 2000 - 14:53:49 EST


Hi Linus!

   This patch updates Documentation/pci.txt to the new PCI interface.

                                Have a nice fortnight

-- 
Martin `MJ' Mares <mj@ucw.cz> <mj@suse.cz> http://atrey.karlin.mff.cuni.cz/~mj/
"First law of socio-genetics: Celibacy is not hereditary."

--- Documentation/pci.txt.mj Mon Feb 7 20:07:35 2000 +++ Documentation/pci.txt Mon Feb 7 20:52:41 2000 @@ -1,52 +1,130 @@ - Few Notes About The PCI Subsystem + How To Write Linux PCI Drivers - or - - "What should you avoid when writing PCI drivers" - - by Martin Mares <mj@suse.cz> on 21-Nov-1999 + by Martin Mares <mj@suse.cz> on 07-Feb-2000 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The world of PCI is vast and it's full of (mostly unpleasant) surprises. +Different PCI devices have different requirements and different bugs -- +because of this, the PCI support layer in Linux kernel is not as trivial +as one would wish. This short pamphlet tries to help all potential driver +authors to find their way through the deep forests of PCI handling. + 0. Structure of PCI drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Aa typical PCI device driver needs to perform the following actions: +There exist two kinds of PCI drivers: new-style ones (which leave most of +probing for devices to the PCI layer and support online insertion and removal +of devices [thus supporting PCI, hot-pluggable PCI and CardBus in single +driver]) and old-style ones which just do all the probing themselves. Unless +you have a very good reason to do so, please don't use the old way of probing +in any new code. After the driver finds the devices it wishes to operate +on (either the old or the new way), it needs to perform the following steps: + + Enable the device + Access device configuration space + Discover resources (addresses and IRQ numbers) provided by the device + Allocate these resources + Communicate with the device + +Most of these topics are covered by the following sections, for the rest +look at <linux/pci.h>, it's hopefully well commented. + +If the PCI subsystem is not configured (CONFIG_PCI is not set), most of +the functions described below are defined as inline functions either completely +empty or just returning an appropriate error codes to avoid lots of ifdefs +in the drivers. + + +1. New-style drivers +~~~~~~~~~~~~~~~~~~~~ +The new-style drivers just call pci_register_driver during their initialization +with a pointer to a structure describing the driver (struct pci_driver) which +contains: + + name Name of the driver + id_table Pointer to table of device ID's the driver is + interested in + probe Pointer to a probing function which gets called (during + execution of pci_register_driver for already existing + devices or later if a new device gets inserted) for all + PCI devices which match the ID table and are not handled + by the other drivers yet. This function gets passed a pointer + to the pci_dev structure representing the device and also + which entry in the ID table did the device match. It returns + zero when the driver has accepted the device or an error + code (negative number) otherwise. This function always gets + called from process context, so it can sleep. + remove Pointer to a function which gets called whenever a device + being handled by this driver is removed (either during + deregistration of the driver or when it's manually pulled + out of a hot-pluggable slot). This function can be called + from interrupt context. + suspend, Power management hooks (currently used only for CardBus + resume cards) -- called when the device goes to sleep or is + resumed. + +The ID table is an array of struct pci_device_id ending with a all-zero entry. +Each entry consists of: + + vendor, device Vendor and device ID to match (or PCI_ANY_ID) + subvendor, Subsystem vendor and device ID to match (or PCI_ANY_ID) + subdevice + class, Device class to match. The class_mask tells which bits + class_mask of the class are honored during the comparison. + driver_data Data private to the driver. + +When the driver exits, it just calls pci_deregister_driver() and the PCI layer +automatically calls the remove hook for all devices handled by the driver. + +Please mark the initialization and cleanup functions where appropriate +(the corresponding macros are defined in <linux/init.h>): + + __init Initialization code. Thrown away after the driver + initializes. + __exit Exit code. Ignored for non-modular drivers. + __devinit Device initialization code. Identical to __init if + the kernel is not compiled with CONFIG_HOTPLUG, normal + function otherwise. + __devexit The same for __exit. + + +2. How to find PCI devices manually (the old style) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +PCI drivers not using the pci_register_driver() interface search +for PCI devices manually using the following constructs: + +Searching by vendor and device ID: + + struct pci_dev *dev = NULL; + while (dev = pci_find_device(VENDOR_ID, DEVICE_ID, dev)) + configure_device(dev); + +Searching by class ID (iterate in a similar way): - 1. Find PCI devices it's able to handle - 2. Enable them - 3. Access their configuration space - 4. Discover addresses and IRQ numbers - -1. How to find PCI devices -~~~~~~~~~~~~~~~~~~~~~~~~~~ - In case your driver wants to search for all devices with given vendor/device -ID, it should use: - - struct pci_dev *dev = NULL; - while (dev = pci_find_device(VENDOR_ID, DEVICE_ID, dev)) - configure_device(dev); + pci_find_class(CLASS_ID, dev) - For class-based search, use pci_find_class(CLASS_ID, dev). +Searching by both vendor/device and subsystem vendor/device ID: - If you need to match by subsystem vendor/device ID, use -pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). + pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). You can use the constant PCI_ANY_ID as a wildcard replacement for VENDOR_ID or DEVICE_ID. This allows searching for any device from a specific vendor, for example. - In case you want to do some complex matching, you can walk the list of all -known PCI devices: + In case you need to decide according to some more complex criteria, +you can walk the list of all known PCI devices yourself: - struct pci_dev *dev; - pci_for_each_dev(dev) { - ... do anything you want with dev ... - } + struct pci_dev *dev; + pci_for_each_dev(dev) { + ... do anything you want with dev ... + } - The `struct pci_dev *' pointer serves as an identification of a PCI device -and is passed to all other functions operating on PCI devices. +For compatibility with device ordering in older kernels, you can also +use pci_for_each_dev_reverse(dev) for walking the list in the opposite +direction. -2. Enabling devices + +3. Enabling devices ~~~~~~~~~~~~~~~~~~~ Before you do anything with the device you've found, you need to enable it by calling pci_enable_device() which enables I/O and memory regions of @@ -57,7 +135,8 @@ which enables the bus master bit in PCI_COMMAND register and also fixes the latency timer value if it's set to something bogus by the BIOS. -3. How to access PCI config space + +4. How to access PCI config space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use pci_(read|write)_config_(byte|word|dword) to access the config space of a device represented by struct pci_dev *. All these functions return 0 @@ -72,7 +151,8 @@ pci_find_capability() for the particular capability and it will find the corresponding register block for you. -4. Addresses and interrupts + +5. Addresses and interrupts ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Memory and port addresses and interrupt numbers should NOT be read from the config space. You should use the values in the pci_dev structure as they might @@ -86,13 +166,33 @@ All interrupt handlers should be registered with SA_SHIRQ and use the devid to map IRQs to devices (remember that all PCI interrupts are shared). -5. Other interesting functions + +6. Other interesting functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pci_find_slot() Find pci_dev corresponding to given bus and slot numbers. pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) +pci_find_capability() Find specified capability in device's capability + list. + + +7. Miscellaneous hints +~~~~~~~~~~~~~~~~~~~~~~ +When displaying PCI slot names to the user (for example when a driver wants +to tell the user what card has it found), please use pci_dev->slot_name +for this purpose. + +Always refer to the PCI devices by a pointer to the pci_dev structure. +All PCI layer functions use this identification and it's the only +reasonable one. Don't use bus/slot/function numbers except for very +special purposes -- on systems with multiple primary buses their semantics +can be pretty complex. + +If you're going to use PCI bus mastering DMA, take a look at +Documentation/DMA-mapping.txt. + -6. Obsolete functions +8. Obsolete functions ~~~~~~~~~~~~~~~~~~~~~ There are several functions kept only for compatibility with old drivers not updated to the new PCI interface. Please don't use them in new code.

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Feb 07 2000 - 21:00:15 EST