2005-04-16 15:20:36 -07:00
/*
* drivers / pci / pci - driver . c
*
*/
# include <linux/pci.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/device.h>
2005-07-06 19:56:03 +02:00
# include <linux/mempolicy.h>
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
# include <linux/slab.h>
2005-11-07 00:59:43 -08:00
# include <linux/sched.h>
2005-04-16 15:20:36 -07:00
# include "pci.h"
/*
* Registration of PCI drivers and handling of hot - pluggable devices .
*/
/*
* Dynamic device IDs are disabled for ! CONFIG_HOTPLUG
*/
2005-06-30 02:18:12 -07:00
struct pci_dynid {
struct list_head node ;
struct pci_device_id id ;
} ;
2005-04-16 15:20:36 -07:00
2005-07-06 09:09:38 -07:00
# ifdef CONFIG_HOTPLUG
2005-04-16 15:20:36 -07:00
/**
2005-10-23 11:57:38 -07:00
* store_new_id - add a new PCI device ID to this driver and re - probe devices
* @ driver : target device driver
* @ buf : buffer for scanning device ID data
* @ count : input size
2005-04-16 15:20:36 -07:00
*
* Adds a new dynamic pci device ID to this driver ,
* and causes the driver to probe for all devices again .
*/
2005-10-28 20:36:51 -07:00
static ssize_t
2005-04-16 15:20:36 -07:00
store_new_id ( struct device_driver * driver , const char * buf , size_t count )
{
2005-06-30 02:18:12 -07:00
struct pci_dynid * dynid ;
2005-04-16 15:20:36 -07:00
struct pci_driver * pdrv = to_pci_driver ( driver ) ;
__u32 vendor = PCI_ANY_ID , device = PCI_ANY_ID , subvendor = PCI_ANY_ID ,
subdevice = PCI_ANY_ID , class = 0 , class_mask = 0 ;
unsigned long driver_data = 0 ;
int fields = 0 ;
fields = sscanf ( buf , " %x %x %x %x %x %x %lux " ,
& vendor , & device , & subvendor , & subdevice ,
& class , & class_mask , & driver_data ) ;
if ( fields < 0 )
return - EINVAL ;
dynid = kmalloc ( sizeof ( * dynid ) , GFP_KERNEL ) ;
if ( ! dynid )
return - ENOMEM ;
memset ( dynid , 0 , sizeof ( * dynid ) ) ;
INIT_LIST_HEAD ( & dynid - > node ) ;
dynid - > id . vendor = vendor ;
dynid - > id . device = device ;
dynid - > id . subvendor = subvendor ;
dynid - > id . subdevice = subdevice ;
dynid - > id . class = class ;
dynid - > id . class_mask = class_mask ;
dynid - > id . driver_data = pdrv - > dynids . use_driver_data ?
driver_data : 0UL ;
spin_lock ( & pdrv - > dynids . lock ) ;
list_add_tail ( & pdrv - > dynids . list , & dynid - > node ) ;
spin_unlock ( & pdrv - > dynids . lock ) ;
2005-06-30 02:18:12 -07:00
if ( get_driver ( & pdrv - > driver ) ) {
driver_attach ( & pdrv - > driver ) ;
put_driver ( & pdrv - > driver ) ;
2005-04-16 15:20:36 -07:00
}
return count ;
}
static DRIVER_ATTR ( new_id , S_IWUSR , NULL , store_new_id ) ;
static void
pci_free_dynids ( struct pci_driver * drv )
{
2005-06-30 02:18:12 -07:00
struct pci_dynid * dynid , * n ;
2005-04-16 15:20:36 -07:00
spin_lock ( & drv - > dynids . lock ) ;
2005-06-30 02:18:12 -07:00
list_for_each_entry_safe ( dynid , n , & drv - > dynids . list , node ) {
2005-04-16 15:20:36 -07:00
list_del ( & dynid - > node ) ;
kfree ( dynid ) ;
}
spin_unlock ( & drv - > dynids . lock ) ;
}
static int
pci_create_newid_file ( struct pci_driver * drv )
{
int error = 0 ;
if ( drv - > probe ! = NULL )
error = sysfs_create_file ( & drv - > driver . kobj ,
& driver_attr_new_id . attr ) ;
return error ;
}
# else /* !CONFIG_HOTPLUG */
static inline void pci_free_dynids ( struct pci_driver * drv ) { }
static inline int pci_create_newid_file ( struct pci_driver * drv )
{
return 0 ;
}
# endif
/**
2005-06-30 02:18:12 -07:00
* pci_match_id - See if a pci device matches a given pci_id table
2005-04-16 15:20:36 -07:00
* @ ids : array of PCI device id structures to search in
2005-06-30 02:18:12 -07:00
* @ dev : the PCI device structure to match against .
*
2005-04-16 15:20:36 -07:00
* Used by a driver to check whether a PCI device present in the
2005-06-30 02:18:12 -07:00
* system is in its list of supported devices . Returns the matching
2005-04-16 15:20:36 -07:00
* pci_device_id structure or % NULL if there is no match .
2005-06-30 02:18:12 -07:00
*
* Depreciated , don ' t use this as it will not catch any dynamic ids
* that a driver might want to check for .
2005-04-16 15:20:36 -07:00
*/
2005-06-30 02:18:12 -07:00
const struct pci_device_id * pci_match_id ( const struct pci_device_id * ids ,
struct pci_dev * dev )
2005-04-16 15:20:36 -07:00
{
2005-06-30 02:18:12 -07:00
if ( ids ) {
while ( ids - > vendor | | ids - > subvendor | | ids - > class_mask ) {
if ( pci_match_one_device ( ids , dev ) )
return ids ;
ids + + ;
}
2005-04-16 15:20:36 -07:00
}
return NULL ;
}
/**
2005-06-30 02:18:12 -07:00
* pci_match_device - Tell if a PCI device structure has a matching
* PCI device id structure
* @ ids : array of PCI device id structures to search in
* @ dev : the PCI device structure to match against
* @ drv : the PCI driver to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices . Returns the matching
* pci_device_id structure or % NULL if there is no match .
2005-04-16 15:20:36 -07:00
*/
2005-06-30 02:18:12 -07:00
const struct pci_device_id * pci_match_device ( struct pci_driver * drv ,
struct pci_dev * dev )
{
2005-04-16 15:20:36 -07:00
const struct pci_device_id * id ;
2005-06-30 02:18:12 -07:00
struct pci_dynid * dynid ;
2005-04-16 15:20:36 -07:00
2005-06-30 02:18:12 -07:00
id = pci_match_id ( drv - > id_table , dev ) ;
2005-04-16 15:20:36 -07:00
if ( id )
2005-06-30 02:18:12 -07:00
return id ;
/* static ids didn't match, lets look at the dynamic ones */
spin_lock ( & drv - > dynids . lock ) ;
list_for_each_entry ( dynid , & drv - > dynids . list , node ) {
if ( pci_match_one_device ( & dynid - > id , dev ) ) {
spin_unlock ( & drv - > dynids . lock ) ;
return & dynid - > id ;
}
2005-04-16 15:20:36 -07:00
}
2005-06-30 02:18:12 -07:00
spin_unlock ( & drv - > dynids . lock ) ;
return NULL ;
2005-04-16 15:20:36 -07:00
}
2005-07-06 19:56:03 +02:00
static int pci_call_probe ( struct pci_driver * drv , struct pci_dev * dev ,
const struct pci_device_id * id )
{
int error ;
# ifdef CONFIG_NUMA
/* Execute driver initialization on node where the
device ' s bus is attached to . This way the driver likely
allocates its local memory on the right node without
any need to change it . */
struct mempolicy * oldpol ;
cpumask_t oldmask = current - > cpus_allowed ;
int node = pcibus_to_node ( dev - > bus ) ;
if ( node > = 0 & & node_online ( node ) )
set_cpus_allowed ( current , node_to_cpumask ( node ) ) ;
/* And set default memory allocation policy */
oldpol = current - > mempolicy ;
current - > mempolicy = & default_policy ;
mpol_get ( current - > mempolicy ) ;
# endif
error = drv - > probe ( dev , id ) ;
# ifdef CONFIG_NUMA
set_cpus_allowed ( current , oldmask ) ;
mpol_free ( current - > mempolicy ) ;
current - > mempolicy = oldpol ;
# endif
return error ;
}
2005-04-16 15:20:36 -07:00
/**
* __pci_device_probe ( )
2005-10-23 11:57:38 -07:00
* @ drv : driver to call to check if it wants the PCI device
* @ pci_dev : PCI device being probed
2005-04-16 15:20:36 -07:00
*
2005-10-23 11:57:38 -07:00
* returns 0 on success , else error .
2005-04-16 15:20:36 -07:00
* side - effect : pci_dev - > driver is set to drv when drv claims pci_dev .
*/
static int
__pci_device_probe ( struct pci_driver * drv , struct pci_dev * pci_dev )
2005-06-30 02:18:12 -07:00
{
const struct pci_device_id * id ;
2005-04-16 15:20:36 -07:00
int error = 0 ;
if ( ! pci_dev - > driver & & drv - > probe ) {
2005-06-30 02:18:12 -07:00
error = - ENODEV ;
id = pci_match_device ( drv , pci_dev ) ;
if ( id )
2005-07-06 19:56:03 +02:00
error = pci_call_probe ( drv , pci_dev , id ) ;
2005-06-30 02:18:12 -07:00
if ( error > = 0 ) {
pci_dev - > driver = drv ;
error = 0 ;
}
2005-04-16 15:20:36 -07:00
}
return error ;
}
static int pci_device_probe ( struct device * dev )
{
int error = 0 ;
struct pci_driver * drv ;
struct pci_dev * pci_dev ;
drv = to_pci_driver ( dev - > driver ) ;
pci_dev = to_pci_dev ( dev ) ;
pci_dev_get ( pci_dev ) ;
error = __pci_device_probe ( drv , pci_dev ) ;
if ( error )
pci_dev_put ( pci_dev ) ;
return error ;
}
static int pci_device_remove ( struct device * dev )
{
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct pci_driver * drv = pci_dev - > driver ;
if ( drv ) {
if ( drv - > remove )
drv - > remove ( pci_dev ) ;
pci_dev - > driver = NULL ;
}
/*
* We would love to complain here if pci_dev - > is_enabled is set , that
* the driver should have called pci_disable_device ( ) , but the
* unfortunate fact is there are too many odd BIOS and bridge setups
* that don ' t like drivers doing that all of the time .
* Oh well , we can dream of sane hardware when we sleep , no matter how
* horrible the crap we have to deal with is when we are awake . . .
*/
pci_dev_put ( pci_dev ) ;
return 0 ;
}
static int pci_device_suspend ( struct device * dev , pm_message_t state )
{
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct pci_driver * drv = pci_dev - > driver ;
int i = 0 ;
if ( drv & & drv - > suspend )
i = drv - > suspend ( pci_dev , state ) ;
else
pci_save_state ( pci_dev ) ;
return i ;
}
2005-07-28 11:37:33 -07:00
/*
2005-04-16 15:20:36 -07:00
* Default resume method for devices that have no driver provided resume ,
* or not even a driver at all .
*/
static void pci_default_resume ( struct pci_dev * pci_dev )
{
2005-07-28 11:37:33 -07:00
int retval ;
2005-04-16 15:20:36 -07:00
/* restore the PCI config space */
pci_restore_state ( pci_dev ) ;
/* if the device was enabled before suspend, reenable */
if ( pci_dev - > is_enabled )
2005-07-28 11:37:33 -07:00
retval = pci_enable_device ( pci_dev ) ;
2005-04-16 15:20:36 -07:00
/* if the device was busmaster before the suspend, make it busmaster again */
if ( pci_dev - > is_busmaster )
pci_set_master ( pci_dev ) ;
}
static int pci_device_resume ( struct device * dev )
{
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct pci_driver * drv = pci_dev - > driver ;
if ( drv & & drv - > resume )
drv - > resume ( pci_dev ) ;
else
pci_default_resume ( pci_dev ) ;
return 0 ;
}
2005-04-08 14:53:31 +09:00
static void pci_device_shutdown ( struct device * dev )
{
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct pci_driver * drv = pci_dev - > driver ;
if ( drv & & drv - > shutdown )
drv - > shutdown ( pci_dev ) ;
}
2005-04-16 15:20:36 -07:00
# define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
# define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
static ssize_t
pci_driver_attr_show ( struct kobject * kobj , struct attribute * attr , char * buf )
{
struct device_driver * driver = kobj_to_pci_driver ( kobj ) ;
struct driver_attribute * dattr = attr_to_driver_attribute ( attr ) ;
2005-04-29 01:26:27 -05:00
ssize_t ret ;
2005-04-16 15:20:36 -07:00
2005-04-29 01:26:27 -05:00
if ( ! get_driver ( driver ) )
return - ENODEV ;
ret = dattr - > show ? dattr - > show ( driver , buf ) : - EIO ;
put_driver ( driver ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
static ssize_t
pci_driver_attr_store ( struct kobject * kobj , struct attribute * attr ,
const char * buf , size_t count )
{
struct device_driver * driver = kobj_to_pci_driver ( kobj ) ;
struct driver_attribute * dattr = attr_to_driver_attribute ( attr ) ;
2005-04-29 01:26:27 -05:00
ssize_t ret ;
2005-04-16 15:20:36 -07:00
2005-04-29 01:26:27 -05:00
if ( ! get_driver ( driver ) )
return - ENODEV ;
ret = dattr - > store ? dattr - > store ( driver , buf , count ) : - EIO ;
put_driver ( driver ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
static struct sysfs_ops pci_driver_sysfs_ops = {
. show = pci_driver_attr_show ,
. store = pci_driver_attr_store ,
} ;
static struct kobj_type pci_driver_kobj_type = {
. sysfs_ops = & pci_driver_sysfs_ops ,
} ;
/**
2005-10-27 23:12:54 +02:00
* __pci_register_driver - register a new pci driver
2005-04-16 15:20:36 -07:00
* @ drv : the driver structure to register
2005-10-27 23:12:54 +02:00
* @ owner : owner module of drv
2005-04-16 15:20:36 -07:00
*
* Adds the driver structure to the list of registered drivers .
* Returns a negative value on error , otherwise 0.
2005-05-03 18:38:30 -06:00
* If no error occurred , the driver remains registered even if
2005-04-16 15:20:36 -07:00
* no device was claimed during registration .
*/
2005-10-27 23:12:54 +02:00
int __pci_register_driver ( struct pci_driver * drv , struct module * owner )
2005-04-16 15:20:36 -07:00
{
int error ;
/* initialize common driver fields */
drv - > driver . name = drv - > name ;
drv - > driver . bus = & pci_bus_type ;
drv - > driver . probe = pci_device_probe ;
drv - > driver . remove = pci_device_remove ;
2005-06-17 12:25:25 -07:00
/* FIXME, once all of the existing PCI drivers have been fixed to set
* the pci shutdown function , this test can go away . */
if ( ! drv - > driver . shutdown )
2005-06-18 22:49:56 +03:00
drv - > driver . shutdown = pci_device_shutdown ;
2005-10-16 21:31:36 +01:00
else
printk ( KERN_WARNING " Warning: PCI driver %s has a struct "
" device_driver shutdown method, please update! \n " ,
drv - > name ) ;
2005-10-27 23:12:54 +02:00
drv - > driver . owner = owner ;
2005-04-16 15:20:36 -07:00
drv - > driver . kobj . ktype = & pci_driver_kobj_type ;
2005-06-30 02:18:12 -07:00
spin_lock_init ( & drv - > dynids . lock ) ;
INIT_LIST_HEAD ( & drv - > dynids . list ) ;
2005-04-16 15:20:36 -07:00
/* register with core */
error = driver_register ( & drv - > driver ) ;
if ( ! error )
2005-06-30 02:18:12 -07:00
error = pci_create_newid_file ( drv ) ;
2005-04-16 15:20:36 -07:00
return error ;
}
/**
* pci_unregister_driver - unregister a pci driver
* @ drv : the driver structure to unregister
*
* Deletes the driver structure from the list of registered PCI drivers ,
* gives it a chance to clean up by calling its remove ( ) function for
* each device it was responsible for , and marks those devices as
* driverless .
*/
void
pci_unregister_driver ( struct pci_driver * drv )
{
driver_unregister ( & drv - > driver ) ;
pci_free_dynids ( drv ) ;
}
static struct pci_driver pci_compat_driver = {
. name = " compat "
} ;
/**
* pci_dev_driver - get the pci_driver of a device
* @ dev : the device to query
*
* Returns the appropriate pci_driver structure or % NULL if there is no
* registered driver for the device .
*/
struct pci_driver *
pci_dev_driver ( const struct pci_dev * dev )
{
if ( dev - > driver )
return dev - > driver ;
else {
int i ;
for ( i = 0 ; i < = PCI_ROM_RESOURCE ; i + + )
if ( dev - > resource [ i ] . flags & IORESOURCE_BUSY )
return & pci_compat_driver ;
}
return NULL ;
}
/**
* pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure
* @ dev : the PCI device structure to match against
2005-10-23 11:57:38 -07:00
* @ drv : the device driver to search for matching PCI device id structures
2005-04-16 15:20:36 -07:00
*
* Used by a driver to check whether a PCI device present in the
2005-10-23 11:57:38 -07:00
* system is in its list of supported devices . Returns the matching
2005-04-16 15:20:36 -07:00
* pci_device_id structure or % NULL if there is no match .
*/
2005-06-30 02:18:12 -07:00
static int pci_bus_match ( struct device * dev , struct device_driver * drv )
2005-04-16 15:20:36 -07:00
{
2005-06-30 02:18:12 -07:00
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct pci_driver * pci_drv = to_pci_driver ( drv ) ;
2005-04-16 15:20:36 -07:00
const struct pci_device_id * found_id ;
2005-06-30 02:18:12 -07:00
found_id = pci_match_device ( pci_drv , pci_dev ) ;
2005-04-16 15:20:36 -07:00
if ( found_id )
return 1 ;
2005-06-30 02:18:12 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
/**
* pci_dev_get - increments the reference count of the pci device structure
* @ dev : the device being referenced
*
* Each live reference to a device should be refcounted .
*
* Drivers for PCI devices should normally record such references in
* their probe ( ) methods , when they bind to a device , and release
* them by calling pci_dev_put ( ) , in their disconnect ( ) methods .
*
* A pointer to the device with the incremented reference counter is returned .
*/
struct pci_dev * pci_dev_get ( struct pci_dev * dev )
{
if ( dev )
get_device ( & dev - > dev ) ;
return dev ;
}
/**
* pci_dev_put - release a use of the pci device structure
* @ dev : device that ' s been disconnected
*
* Must be called when a user of a device is finished with it . When the last
* user of the device calls this function , the memory of the device is freed .
*/
void pci_dev_put ( struct pci_dev * dev )
{
if ( dev )
put_device ( & dev - > dev ) ;
}
# ifndef CONFIG_HOTPLUG
int pci_hotplug ( struct device * dev , char * * envp , int num_envp ,
char * buffer , int buffer_size )
{
return - ENODEV ;
}
# endif
struct bus_type pci_bus_type = {
. name = " pci " ,
. match = pci_bus_match ,
. hotplug = pci_hotplug ,
. suspend = pci_device_suspend ,
. resume = pci_device_resume ,
. dev_attrs = pci_dev_attrs ,
} ;
static int __init pci_driver_init ( void )
{
return bus_register ( & pci_bus_type ) ;
}
postcore_initcall ( pci_driver_init ) ;
2005-06-30 02:18:12 -07:00
EXPORT_SYMBOL ( pci_match_id ) ;
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( pci_match_device ) ;
2005-10-27 23:12:54 +02:00
EXPORT_SYMBOL ( __pci_register_driver ) ;
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( pci_unregister_driver ) ;
EXPORT_SYMBOL ( pci_dev_driver ) ;
EXPORT_SYMBOL ( pci_bus_type ) ;
EXPORT_SYMBOL ( pci_dev_get ) ;
EXPORT_SYMBOL ( pci_dev_put ) ;