@ -353,6 +353,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)
return sub_bus ;
}
/**
* 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
*
* Returns the matching pci_device_id structure or % NULL if there is no match .
*/
static bool pci_match_one_id ( const struct pci_device_id * id ,
const struct pci_device_id * find )
{
if ( ( id - > vendor = = PCI_ANY_ID | | id - > vendor = = find - > vendor ) & &
( id - > device = = PCI_ANY_ID | | id - > device = = find - > device ) & &
( id - > subvendor = = PCI_ANY_ID | | id - > subvendor = = find - > subvendor ) & &
( id - > subdevice = = PCI_ANY_ID | | id - > subdevice = = find - > subdevice ) & &
! ( ( id - > class ^ find - > class ) & id - > class_mask ) )
return true ;
return false ;
}
/**
* pci_find_and_bind_driver ( ) - Find and bind the right PCI driver
*
* This only looks at certain fields in the descriptor .
*/
static int pci_find_and_bind_driver ( struct udevice * parent ,
struct pci_device_id * find_id , int devfn ,
struct udevice * * devp )
{
struct pci_driver_entry * start , * entry ;
const char * drv ;
int n_ents ;
int ret ;
char name [ 30 ] , * str ;
* devp = NULL ;
debug ( " %s: Searching for driver: vendor=%x, device=%x \n " , __func__ ,
find_id - > vendor , find_id - > device ) ;
start = ll_entry_start ( struct pci_driver_entry , pci_driver_entry ) ;
n_ents = ll_entry_count ( struct pci_driver_entry , pci_driver_entry ) ;
for ( entry = start ; entry ! = start + n_ents ; entry + + ) {
const struct pci_device_id * id ;
struct udevice * dev ;
const struct driver * drv ;
for ( id = entry - > match ;
id - > vendor | | id - > subvendor | | id - > class_mask ;
id + + ) {
if ( ! pci_match_one_id ( id , find_id ) )
continue ;
drv = entry - > driver ;
/*
* We could pass the descriptor to the driver as
* platdata ( instead of NULL ) and allow its bind ( )
* method to return - ENOENT if it doesn ' t support this
* device . That way we could continue the search to
* find another driver . For now this doesn ' t seem
* necesssary , so just bind the first match .
*/
ret = device_bind ( parent , drv , drv - > name , NULL , - 1 ,
& dev ) ;
if ( ret )
goto error ;
debug ( " %s: Match found: %s \n " , __func__ , drv - > name ) ;
dev - > driver_data = find_id - > driver_data ;
* devp = dev ;
return 0 ;
}
}
/* Bind a generic driver so that the device can be used */
sprintf ( name , " pci_%x:%x.%x " , parent - > seq , PCI_DEV ( devfn ) ,
PCI_FUNC ( devfn ) ) ;
str = strdup ( name ) ;
if ( ! str )
return - ENOMEM ;
drv = ( find_id - > class > > 8 ) = = PCI_CLASS_BRIDGE_PCI ? " pci_bridge_drv " :
" pci_generic_drv " ;
ret = device_bind_driver ( parent , drv , str , devp ) ;
if ( ret ) {
debug ( " %s: Failed to bind generic driver: %d " , __func__ , ret ) ;
return ret ;
}
debug ( " %s: No match found: bound generic driver instead \n " , __func__ ) ;
return 0 ;
error :
debug ( " %s: No match found: error %d \n " , __func__ , ret ) ;
return ret ;
}
int pci_bind_bus_devices ( struct udevice * bus )
{
ulong vendor , device ;
@ -387,25 +482,33 @@ int pci_bind_bus_devices(struct udevice *bus)
bus - > seq , bus - > name , PCI_DEV ( devfn ) , PCI_FUNC ( devfn ) ) ;
pci_bus_read_config ( bus , devfn , PCI_DEVICE_ID , & device ,
PCI_SIZE_16 ) ;
pci_bus_read_config ( bus , devfn , PCI_CLASS_DEVICE , & class ,
PCI_SIZE_16 ) ;
pci_bus_read_config ( bus , devfn , PCI_CLASS_REVISION , & class ,
PCI_SIZE_32 ) ;
class > > = 8 ;
/* Find this device in the device tree */
ret = pci_bus_find_devfn ( bus , devfn , & dev ) ;
/* Search for a driver */
/* If nothing in the device tree, bind a generic device */
if ( ret = = - ENODEV ) {
char name [ 30 ] , * str ;
const char * drv ;
sprintf ( name , " pci_%x:%x.%x " , bus - > seq ,
PCI_DEV ( devfn ) , PCI_FUNC ( devfn ) ) ;
str = strdup ( name ) ;
if ( ! str )
return - ENOMEM ;
drv = class = = PCI_CLASS_BRIDGE_PCI ?
" pci_bridge_drv " : " pci_generic_drv " ;
ret = device_bind_driver ( bus , drv , str , & dev ) ;
struct pci_device_id find_id ;
ulong val ;
memset ( & find_id , ' \0 ' , sizeof ( find_id ) ) ;
find_id . vendor = vendor ;
find_id . device = device ;
find_id . class = class ;
if ( ( header_type & 0x7f ) = = PCI_HEADER_TYPE_NORMAL ) {
pci_bus_read_config ( bus , devfn ,
PCI_SUBSYSTEM_VENDOR_ID ,
& val , PCI_SIZE_32 ) ;
find_id . subvendor = val & 0xffff ;
find_id . subdevice = val > > 16 ;
}
ret = pci_find_and_bind_driver ( bus , & find_id , devfn ,
& dev ) ;
}
if ( ret )
return ret ;