• Inaky Perez-Gonzalez's avatar
    PCI: switch pci_{enable,disable}_device() to be nestable · bae94d02
    Inaky Perez-Gonzalez authored
    Changes the pci_{enable,disable}_device() functions to work in a
    nested basis, so that eg, three calls to enable_device() require three
    calls to disable_device().
    
    The reason for this is to simplify PCI drivers for
    multi-interface/capability devices. These are devices that cram more
    than one interface in a single function. A relevant example of that is
    the Wireless [USB] Host Controller Interface (similar to EHCI) [see
    http://www.intel.com/technology/comms/wusb/whci.htm]. 
    
    In these kind of devices, multiple interfaces are accessed through a
    single bar and IRQ line. For that, the drivers map only the smallest
    area of the bar to access their register banks and use shared IRQ
    handlers. 
    
    However, because the order at which those drivers load cannot be known
    ahead of time, the sequence in which the calls to pci_enable_device()
    and pci_disable_device() cannot be predicted. Thus:
    
    1. driverA     starts     pci_enable_device()
    2. driverB     starts     pci_enable_device()
    3. driverA     shutdown   pci_disable_device()
    4. driverB     shutdown   pci_disable_device()
    
    between steps 3 and 4, driver B would loose access to it's device,
    even if it didn't intend to.
    
    By using this modification, the device won't be disabled until all the
    callers to enable() have called disable().
    
    This is implemented by replacing 'struct pci_dev->is_enabled' from a
    bitfield to an atomic use count. Each caller to enable increments it,
    each caller to disable decrements it. When the count increments from 0
    to 1, __pci_enable_device() is called to actually enable the
    device. When it drops to zero, pci_disable_device() actually does the
    disabling.
    
    We keep the backend __pci_enable_device() for pci_default_resume() to
    use and also change the sysfs method implementation, so that userspace
    enabling/disabling the device doesn't disable it one time too much.
    Signed-off-by: default avatarInaky Perez-Gonzalez <inaky@linux.intel.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    bae94d02
pci.c 29 KB