On Wed, Mar 09, 2016 at 07:20:00PM +0100, Ladi Prosek wrote: > PCI devices may support more capabilities of the same type (for > example PCI_CAP_ID_VNDR) and there was no way to discover all of > them. This commit adds a new API pci_find_next_capability which > provides this functionality. It would typically be used like so: > > for (pos = pci_find_capability(pci, PCI_CAP_ID_VNDR); > pos > 0; > pos = pci_find_next_capability(pci, pos, PCI_CAP_ID_VNDR)) { > ... > } > > Signed-off-by: Ladi Prosek <lpro...@redhat.com>
Reviewed-by: Michael S. Tsirkin <m...@redhat.com> > --- > src/drivers/bus/pciextra.c | 54 > +++++++++++++++++++++++++++++++++++----------- > src/include/ipxe/pci.h | 2 ++ > 2 files changed, 43 insertions(+), 13 deletions(-) > > diff --git a/src/drivers/bus/pciextra.c b/src/drivers/bus/pciextra.c > index 82287fb..15f79c9 100644 > --- a/src/drivers/bus/pciextra.c > +++ b/src/drivers/bus/pciextra.c > @@ -3,6 +3,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); > #include <stdint.h> > #include <ipxe/pci.h> > > +static int pci_find_capability_common ( struct pci_device *pci, > + uint8_t pos, int cap ) { > + uint8_t id; > + int ttl = 48; > + > + while ( ttl-- && pos >= 0x40 > ) { > + pos &= ~3; > + pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id ); > + DBG ( "PCI Capability: %d\n", id ); > + if ( id == 0xff ) > + break; > + if ( id == cap ) > + return pos; > + pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos ); > + } > + return 0; > +} > + > /** > * Look for a PCI capability > * > @@ -17,9 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); > */ > int pci_find_capability ( struct pci_device *pci, int cap ) { > uint16_t status; > - uint8_t pos, id; > + uint8_t pos; > uint8_t hdr_type; > - int ttl = 48; > > pci_read_config_word ( pci, PCI_STATUS, &status ); > if ( ! ( status & PCI_STATUS_CAP_LIST ) ) > @@ -36,17 +53,28 @@ int pci_find_capability ( struct pci_device *pci, int cap > ) { > pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos ); > break; > } > - while ( ttl-- && pos >= 0x40 ) { > - pos &= ~3; > - pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id ); > - DBG ( "PCI Capability: %d\n", id ); > - if ( id == 0xff ) > - break; > - if ( id == cap ) > - return pos; > - pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos ); > - } > - return 0; > + return pci_find_capability_common ( pci, pos, cap ); > +} > + > +/** > + * Look for another PCI capability > + * > + * @v pci PCI device to query > + * @v pos Address of the current capability > + * @v cap Capability code > + * @ret address Address of capability, or 0 if not found > + * > + * Determine whether or not a device supports a given PCI capability > + * starting the search at a given address within the device's PCI > + * configuration space. Returns the address of the next capability > + * structure within the device's PCI configuration space, or 0 if the > + * device does not support another such capability. > + */ > +int pci_find_next_capability ( struct pci_device *pci, int pos, int cap ) { > + u8 new_pos; > + > + pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &new_pos ); > + return pci_find_capability_common ( pci, new_pos, cap ); > } > > /** > diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h > index 89d9d80..0c6bc7e 100644 > --- a/src/include/ipxe/pci.h > +++ b/src/include/ipxe/pci.h > @@ -286,6 +286,8 @@ extern int pci_find_driver ( struct pci_device *pci ); > extern int pci_probe ( struct pci_device *pci ); > extern void pci_remove ( struct pci_device *pci ); > extern int pci_find_capability ( struct pci_device *pci, int capability ); > +extern int pci_find_next_capability ( struct pci_device *pci, > + int pos, int capability ); > extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg > ); > > /** > -- > 2.5.0 _______________________________________________ ipxe-devel mailing list ipxe-devel@lists.ipxe.org https://lists.ipxe.org/mailman/listinfo.cgi/ipxe-devel