2008-10-13 15:18:07 +04:00
# ifndef DRIVERS_PCI_H
# define DRIVERS_PCI_H
2009-03-20 06:25:16 +03:00
# include <linux/workqueue.h>
2008-10-13 15:18:07 +04:00
# define PCI_CFG_SPACE_SIZE 256
# define PCI_CFG_SPACE_EXP_SIZE 4096
2005-04-17 02:20:36 +04:00
/* Functions internal to the PCI core code */
2007-08-14 17:15:12 +04:00
extern int pci_uevent ( struct device * dev , struct kobj_uevent_env * env ) ;
2005-04-17 02:20:36 +04:00
extern int pci_create_sysfs_dev_files ( struct pci_dev * pdev ) ;
extern void pci_remove_sysfs_dev_files ( struct pci_dev * pdev ) ;
2011-03-02 20:04:17 +03:00
# if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI)
2010-07-26 14:56:50 +04:00
static inline void pci_create_firmware_label_files ( struct pci_dev * pdev )
2010-08-02 16:44:29 +04:00
{ return ; }
2010-07-26 14:56:50 +04:00
static inline void pci_remove_firmware_label_files ( struct pci_dev * pdev )
2010-08-02 16:44:29 +04:00
{ return ; }
2010-07-26 14:56:50 +04:00
# else
extern void pci_create_firmware_label_files ( struct pci_dev * pdev ) ;
extern void pci_remove_firmware_label_files ( struct pci_dev * pdev ) ;
# endif
2005-04-17 02:20:36 +04:00
extern void pci_cleanup_rom ( struct pci_dev * dev ) ;
2008-10-24 21:32:33 +04:00
# ifdef HAVE_PCI_MMAP
2010-11-10 13:03:21 +03:00
enum pci_mmap_api {
PCI_MMAP_SYSFS , /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
PCI_MMAP_PROCFS /* mmap on /proc/bus/pci/<BDF> */
} ;
2008-10-24 21:32:33 +04:00
extern int pci_mmap_fits ( struct pci_dev * pdev , int resno ,
2010-11-10 13:03:21 +03:00
struct vm_area_struct * vmai ,
enum pci_mmap_api mmap_api ) ;
2008-10-24 21:32:33 +04:00
# endif
2009-07-28 00:37:48 +04:00
int pci_probe_reset_function ( struct pci_dev * dev ) ;
2007-07-17 08:27:10 +04:00
2008-07-07 05:32:02 +04:00
/**
2009-01-10 04:04:26 +03:00
* struct pci_platform_pm_ops - Firmware PM callbacks
2008-07-07 05:32:02 +04:00
*
2009-01-10 04:04:26 +03:00
* @ is_manageable : returns ' true ' if given device is power manageable by the
* platform firmware
2008-07-07 05:32:02 +04:00
*
2009-01-10 04:04:26 +03:00
* @ set_state : invokes the platform firmware to set the device ' s power state
2008-07-07 05:32:02 +04:00
*
2009-01-10 04:04:26 +03:00
* @ choose_state : returns PCI power state of given device preferred by the
* platform ; to be used during system - wide transitions from a
* sleeping state to the working state and vice versa
2008-07-07 05:32:02 +04:00
*
2009-01-10 04:04:26 +03:00
* @ can_wakeup : returns ' true ' if given device is capable of waking up the
* system from a sleeping state
2008-07-07 05:34:48 +04:00
*
2009-01-10 04:04:26 +03:00
* @ sleep_wake : enables / disables the system wake up capability of given device
2008-07-07 05:34:48 +04:00
*
2010-02-18 01:44:09 +03:00
* @ run_wake : enables / disables the platform to generate run - time wake - up events
* for given device ( the device ' s wake - up capability has to be
* enabled by @ sleep_wake for this feature to work )
*
2008-07-07 05:32:02 +04:00
* If given platform is generally capable of power managing PCI devices , all of
* these callbacks are mandatory .
*/
struct pci_platform_pm_ops {
bool ( * is_manageable ) ( struct pci_dev * dev ) ;
int ( * set_state ) ( struct pci_dev * dev , pci_power_t state ) ;
pci_power_t ( * choose_state ) ( struct pci_dev * dev ) ;
2008-07-07 05:34:48 +04:00
bool ( * can_wakeup ) ( struct pci_dev * dev ) ;
int ( * sleep_wake ) ( struct pci_dev * dev , bool enable ) ;
2010-02-18 01:44:09 +03:00
int ( * run_wake ) ( struct pci_dev * dev , bool enable ) ;
2008-07-07 05:32:02 +04:00
} ;
extern int pci_set_platform_pm ( struct pci_platform_pm_ops * ops ) ;
PCI PM: Avoid touching devices behind bridges in unknown state
It generally is better to avoid accessing devices behind bridges that
may not be in the D0 power state, because in that case the bridges'
secondary buses may not be accessible. For this reason, during the
early phase of resume (ie. with interrupts disabled), before
restoring the standard config registers of a device, check the power
state of the bridge the device is behind and postpone the restoration
of the device's config space, as well as any other operations that
would involve accessing the device, if that state is not D0.
In such cases the restoration of the device's config space will be
retried during the "normal" phase of resume (ie. with interrupts
enabled), so that the bridge can be put into D0 before that happens.
Also, save standard configuration registers of PCI devices during the
"normal" phase of suspend (ie. with interrupts enabled), so that the
bridges the devices are behind can be put into low power states (we
don't put bridges into low power states at the moment, but we may
want to do it in the future and it seems reasonable to design for
that).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2009-01-07 15:07:15 +03:00
extern void pci_update_current_state ( struct pci_dev * dev , pci_power_t state ) ;
PCI / PM: restore the original behavior of pci_set_power_state()
Commit cc2893b6 (PCI: Ensure we re-enable devices on resume)
addressed the problem with USB not being powered after resume on
recent Lenovo machines, but it did that in a suboptimal way.
Namely, it should have changed the relevant code paths only,
which are pci_pm_resume_noirq() and pci_pm_restore_noirq() supposed
to restore the device's power and standard configuration registers
after system resume from suspend or hibernation. Instead, however,
it modified pci_set_power_state() which is executed in several
other situations too. That resulted in some undesirable effects,
like attempting to change a device's power state in the same way
multiple times in a row (up to as many as 4 times in a row in the
snd_hda_intel driver).
Fix the bug addressed by commit cc2893b6 in an alternative way,
by forcibly powering up all devices in pci_pm_default_resume_early(),
which is called by pci_pm_resume_noirq() and pci_pm_restore_noirq()
to restore the device's power and standard configuration registers,
and modifying pci_pm_runtime_resume() to avoid the forcible power-up
if not necessary. Then, revert the changes made by commit cc2893b6
to make the confusion introduced by it go away.
Acked-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-07-06 01:20:00 +04:00
extern void pci_power_up ( struct pci_dev * dev ) ;
2009-01-07 15:03:42 +03:00
extern void pci_disable_enabled_device ( struct pci_dev * dev ) ;
2010-02-18 01:44:58 +03:00
extern int pci_finish_runtime_suspend ( struct pci_dev * dev ) ;
2010-02-18 01:44:09 +03:00
extern int __pci_pme_wakeup ( struct pci_dev * dev , void * ign ) ;
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 06:23:51 +04:00
extern void pci_wakeup_bus ( struct pci_bus * bus ) ;
2008-07-07 05:34:48 +04:00
extern void pci_pm_init ( struct pci_dev * dev ) ;
2008-12-17 23:10:05 +03:00
extern void platform_pci_wakeup_init ( struct pci_dev * dev ) ;
2008-12-08 00:02:58 +03:00
extern void pci_allocate_cap_save_buffers ( struct pci_dev * dev ) ;
2012-02-11 12:18:30 +04:00
void pci_free_cap_save_buffers ( struct pci_dev * dev ) ;
2009-01-16 23:54:43 +03:00
2010-12-29 15:21:23 +03:00
static inline void pci_wakeup_event ( struct pci_dev * dev )
{
/* Wait 100 ms before the system can be put into a sleep state. */
pm_wakeup_event ( & dev - > dev , 100 ) ;
}
2009-01-16 23:54:43 +03:00
static inline bool pci_is_bridge ( struct pci_dev * pci_dev )
{
return ! ! ( pci_dev - > subordinate ) ;
}
2005-03-19 08:15:48 +03:00
2008-03-05 19:52:39 +03:00
struct pci_vpd_ops {
2008-12-18 20:17:16 +03:00
ssize_t ( * read ) ( struct pci_dev * dev , loff_t pos , size_t count , void * buf ) ;
ssize_t ( * write ) ( struct pci_dev * dev , loff_t pos , size_t count , const void * buf ) ;
2008-03-05 19:52:39 +03:00
void ( * release ) ( struct pci_dev * dev ) ;
} ;
struct pci_vpd {
2008-07-02 21:59:04 +04:00
unsigned int len ;
2008-12-18 20:17:16 +03:00
const struct pci_vpd_ops * ops ;
2008-03-05 19:52:39 +03:00
struct bin_attribute * attr ; /* descriptor for sysfs VPD entry */
} ;
extern int pci_vpd_pci22_init ( struct pci_dev * dev ) ;
static inline void pci_vpd_release ( struct pci_dev * dev )
{
if ( dev - > vpd )
dev - > vpd - > ops - > release ( dev ) ;
}
2005-04-17 02:20:36 +04:00
/* PCI /proc functions */
# ifdef CONFIG_PROC_FS
extern int pci_proc_attach_device ( struct pci_dev * dev ) ;
extern int pci_proc_detach_device ( struct pci_dev * dev ) ;
extern int pci_proc_detach_bus ( struct pci_bus * bus ) ;
# else
static inline int pci_proc_attach_device ( struct pci_dev * dev ) { return 0 ; }
static inline int pci_proc_detach_device ( struct pci_dev * dev ) { return 0 ; }
static inline int pci_proc_detach_bus ( struct pci_bus * bus ) { return 0 ; }
# endif
/* Functions for PCI Hotplug drivers to use */
2012-05-18 23:46:34 +04:00
int pci_hp_add_bridge ( struct pci_dev * dev ) ;
2005-04-17 02:20:36 +04:00
2008-10-03 13:49:32 +04:00
# ifdef HAVE_PCI_LEGACY
extern void pci_create_legacy_files ( struct pci_bus * bus ) ;
2005-04-17 02:20:36 +04:00
extern void pci_remove_legacy_files ( struct pci_bus * bus ) ;
2008-10-03 13:49:32 +04:00
# else
static inline void pci_create_legacy_files ( struct pci_bus * bus ) { return ; }
static inline void pci_remove_legacy_files ( struct pci_bus * bus ) { return ; }
# endif
2005-04-17 02:20:36 +04:00
/* Lock for read/write access to pci device and bus lists */
2006-06-02 08:35:43 +04:00
extern struct rw_semaphore pci_bus_sem ;
2005-04-17 02:20:36 +04:00
2011-11-04 12:46:00 +04:00
extern raw_spinlock_t pci_lock ;
2006-07-12 19:59:00 +04:00
extern unsigned int pci_pm_d3_delay ;
2007-01-25 11:34:07 +03:00
2005-08-17 02:16:05 +04:00
# ifdef CONFIG_PCI_MSI
2006-03-06 08:33:34 +03:00
void pci_no_msi ( void ) ;
2007-04-05 11:19:10 +04:00
extern void pci_msi_init_pci_dev ( struct pci_dev * dev ) ;
2005-08-17 02:16:05 +04:00
# else
2006-03-06 08:33:34 +03:00
static inline void pci_no_msi ( void ) { }
2007-04-05 11:19:10 +04:00
static inline void pci_msi_init_pci_dev ( struct pci_dev * dev ) { }
2005-08-17 02:16:05 +04:00
# endif
2007-01-25 11:34:08 +03:00
2012-02-24 07:23:30 +04:00
void pci_realloc_get_opt ( char * ) ;
2011-07-07 22:19:10 +04:00
2006-07-12 19:59:00 +04:00
static inline int pci_no_d1d2 ( struct pci_dev * dev )
{
unsigned int parent_dstates = 0 ;
2005-08-17 02:16:05 +04:00
2006-07-12 19:59:00 +04:00
if ( dev - > bus - > self )
parent_dstates = dev - > bus - > self - > no_d1d2 ;
return ( dev - > no_d1d2 | | parent_dstates ) ;
}
2005-04-17 02:20:36 +04:00
extern struct device_attribute pci_dev_attrs [ ] ;
2011-05-13 04:11:39 +04:00
extern struct device_attribute pcibus_dev_attrs [ ] ;
2012-11-06 00:20:34 +04:00
extern struct device_type pci_dev_type ;
2009-03-20 23:56:31 +03:00
# ifdef CONFIG_HOTPLUG
extern struct bus_attribute pci_bus_attrs [ ] ;
# else
# define pci_bus_attrs NULL
# endif
2005-04-17 02:20:36 +04:00
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
* PCI device id structure
* @ id : single PCI device id structure to match
* @ dev : the PCI device structure to match against
2008-01-31 02:21:33 +03:00
*
2005-04-17 02:20:36 +04:00
* Returns the matching pci_device_id structure or % NULL if there is no match .
*/
static inline const struct pci_device_id *
pci_match_one_device ( const struct pci_device_id * id , const struct pci_dev * dev )
{
if ( ( id - > vendor = = PCI_ANY_ID | | id - > vendor = = dev - > vendor ) & &
( id - > device = = PCI_ANY_ID | | id - > device = = dev - > device ) & &
( id - > subvendor = = PCI_ANY_ID | | id - > subvendor = = dev - > subsystem_vendor ) & &
( id - > subdevice = = PCI_ANY_ID | | id - > subdevice = = dev - > subsystem_device ) & &
! ( ( id - > class ^ dev - > class ) & id - > class_mask ) )
return id ;
return NULL ;
}
2008-06-11 01:28:50 +04:00
/* PCI slot sysfs helper code */
# define to_pci_slot(s) container_of(s, struct pci_slot, kobj)
extern struct kset * pci_slots_kset ;
struct pci_slot_attribute {
struct attribute attr ;
ssize_t ( * show ) ( struct pci_slot * , char * ) ;
ssize_t ( * store ) ( struct pci_slot * , const char * , size_t ) ;
} ;
# define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
2008-11-21 21:40:40 +03:00
enum pci_bar_type {
pci_bar_unknown , /* Standard PCI BAR probe */
pci_bar_io , /* An io port BAR */
pci_bar_mem32 , /* A 32-bit memory BAR */
pci_bar_mem64 , /* A 64-bit memory BAR */
} ;
2012-01-27 22:55:10 +04:00
bool pci_bus_read_dev_vendor_id ( struct pci_bus * bus , int devfn , u32 * pl ,
int crs_timeout ) ;
2009-03-20 06:25:14 +03:00
extern int pci_setup_device ( struct pci_dev * dev ) ;
2008-11-21 21:40:40 +03:00
extern int __pci_read_base ( struct pci_dev * dev , enum pci_bar_type type ,
struct resource * res , unsigned int reg ) ;
2008-11-21 21:41:27 +03:00
extern int pci_resource_bar ( struct pci_dev * dev , int resno ,
enum pci_bar_type * type ) ;
2008-11-21 21:42:35 +03:00
extern int pci_bus_add_child ( struct pci_bus * bus ) ;
2008-10-14 10:02:53 +04:00
extern void pci_enable_ari ( struct pci_dev * dev ) ;
/**
* pci_ari_enabled - query ARI forwarding status
2008-11-21 21:38:21 +03:00
* @ bus : the PCI bus
2008-10-14 10:02:53 +04:00
*
* Returns 1 if ARI forwarding is enabled , or 0 if not enabled ;
*/
2008-11-21 21:38:21 +03:00
static inline int pci_ari_enabled ( struct pci_bus * bus )
2008-10-14 10:02:53 +04:00
{
2008-11-21 21:38:21 +03:00
return bus - > self & & bus - > self - > ari_enabled ;
2008-10-14 10:02:53 +04:00
}
2012-02-16 09:40:31 +04:00
void pci_reassigndev_resource_alignment ( struct pci_dev * dev ) ;
2009-03-16 11:13:39 +03:00
extern void pci_disable_bridge_window ( struct pci_dev * dev ) ;
2009-03-20 06:25:11 +03:00
/* Single Root I/O Virtualization */
struct pci_sriov {
int pos ; /* capability position */
int nres ; /* number of resources */
u32 cap ; /* SR-IOV Capabilities */
u16 ctrl ; /* SR-IOV Control */
u16 total ; /* total VFs associated with the PF */
2009-03-20 06:25:15 +03:00
u16 initial ; /* initial VFs associated with the PF */
u16 nr_virtfn ; /* number of VFs available */
2009-03-20 06:25:11 +03:00
u16 offset ; /* first VF Routing ID offset */
u16 stride ; /* following VF stride */
u32 pgsz ; /* page size for BAR alignment */
u8 link ; /* Function Dependency Link */
2012-11-06 00:20:37 +04:00
u16 drvttl ; /* max num VFs driver supports */
2009-03-20 06:25:11 +03:00
struct pci_dev * dev ; /* lowest numbered PF */
struct pci_dev * self ; /* this PF */
struct mutex lock ; /* lock for VF bus */
2009-03-20 06:25:16 +03:00
struct work_struct mtask ; /* VF Migration task */
u8 __iomem * mstate ; /* VF Migration State Array */
2009-03-20 06:25:11 +03:00
} ;
2011-12-17 17:24:40 +04:00
# ifdef CONFIG_PCI_ATS
extern void pci_restore_ats_state ( struct pci_dev * dev ) ;
# else
static inline void pci_restore_ats_state ( struct pci_dev * dev )
{
}
# endif /* CONFIG_PCI_ATS */
2009-03-20 06:25:11 +03:00
# ifdef CONFIG_PCI_IOV
extern int pci_iov_init ( struct pci_dev * dev ) ;
extern void pci_iov_release ( struct pci_dev * dev ) ;
extern int pci_iov_resource_bar ( struct pci_dev * dev , int resno ,
enum pci_bar_type * type ) ;
2010-09-08 04:25:20 +04:00
extern resource_size_t pci_sriov_resource_alignment ( struct pci_dev * dev ,
int resno ) ;
2009-03-20 06:25:12 +03:00
extern void pci_restore_iov_state ( struct pci_dev * dev ) ;
2009-03-20 06:25:13 +03:00
extern int pci_iov_bus_range ( struct pci_bus * bus ) ;
2009-05-18 09:51:32 +04:00
2009-03-20 06:25:11 +03:00
# else
static inline int pci_iov_init ( struct pci_dev * dev )
{
return - ENODEV ;
}
static inline void pci_iov_release ( struct pci_dev * dev )
{
}
static inline int pci_iov_resource_bar ( struct pci_dev * dev , int resno ,
enum pci_bar_type * type )
{
return 0 ;
}
2009-03-20 06:25:12 +03:00
static inline void pci_restore_iov_state ( struct pci_dev * dev )
{
}
2009-03-20 06:25:13 +03:00
static inline int pci_iov_bus_range ( struct pci_bus * bus )
{
return 0 ;
}
2009-05-18 09:51:32 +04:00
2009-03-20 06:25:11 +03:00
# endif /* CONFIG_PCI_IOV */
2011-07-26 00:08:41 +04:00
extern unsigned long pci_cardbus_resource_alignment ( struct resource * ) ;
2010-09-08 04:25:20 +04:00
static inline resource_size_t pci_resource_alignment ( struct pci_dev * dev ,
2009-08-29 00:00:06 +04:00
struct resource * res )
{
# ifdef CONFIG_PCI_IOV
int resno = res - dev - > resource ;
if ( resno > = PCI_IOV_RESOURCES & & resno < = PCI_IOV_RESOURCE_END )
return pci_sriov_resource_alignment ( dev , resno ) ;
# endif
2011-07-26 00:08:41 +04:00
if ( dev - > class > > 8 = = PCI_CLASS_BRIDGE_CARDBUS )
return pci_cardbus_resource_alignment ( res ) ;
2009-08-29 00:00:06 +04:00
return resource_alignment ( res ) ;
}
2009-10-07 21:27:17 +04:00
extern void pci_enable_acs ( struct pci_dev * dev ) ;
2009-12-07 08:03:21 +03:00
struct pci_dev_reset_methods {
u16 vendor ;
u16 device ;
int ( * reset ) ( struct pci_dev * dev , int probe ) ;
} ;
2010-01-03 00:57:24 +03:00
# ifdef CONFIG_PCI_QUIRKS
2009-12-31 21:06:35 +03:00
extern int pci_dev_specific_reset ( struct pci_dev * dev , int probe ) ;
2010-01-03 00:57:24 +03:00
# else
static inline int pci_dev_specific_reset ( struct pci_dev * dev , int probe )
{
return - ENOTTY ;
}
# endif
2009-12-07 08:03:21 +03:00
2008-10-13 15:18:07 +04:00
# endif /* DRIVERS_PCI_H */