PCI: Add pci_find_ht_capability() for finding Hypertransport capabilities
There are already several places in the kernel that want to search a PCI device for a given Hypertransport capability. Although this is possible using pci_find_capability() etc., it makes sense to encapsulate that logic in a helper - pci_find_ht_capability(). To cater for searching exhaustively for a capability, we also provide pci_find_next_ht_capability(). We also need to cater for the fact that the HT capability fields may be either 3 or 5 bits wide. pci_find_ht_capability() deals with this for you, but callers using the #defines directly must handle that themselves. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
d3bac118fb
Коммит
687d5fe3dc
|
@ -68,12 +68,14 @@ pci_max_busnr(void)
|
|||
|
||||
#endif /* 0 */
|
||||
|
||||
static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
|
||||
#define PCI_FIND_CAP_TTL 48
|
||||
|
||||
static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap, int *ttl)
|
||||
{
|
||||
u8 id;
|
||||
int ttl = 48;
|
||||
|
||||
while (ttl--) {
|
||||
while ((*ttl)--) {
|
||||
pci_bus_read_config_byte(bus, devfn, pos, &pos);
|
||||
if (pos < 0x40)
|
||||
break;
|
||||
|
@ -89,6 +91,14 @@ static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap)
|
||||
{
|
||||
int ttl = PCI_FIND_CAP_TTL;
|
||||
|
||||
return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
|
||||
}
|
||||
|
||||
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
|
||||
{
|
||||
return __pci_find_next_cap(dev->bus, dev->devfn,
|
||||
|
@ -224,6 +234,74 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_ext_capability);
|
||||
|
||||
static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
|
||||
{
|
||||
int rc, ttl = PCI_FIND_CAP_TTL;
|
||||
u8 cap, mask;
|
||||
|
||||
if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
|
||||
mask = HT_3BIT_CAP_MASK;
|
||||
else
|
||||
mask = HT_5BIT_CAP_MASK;
|
||||
|
||||
pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
|
||||
PCI_CAP_ID_HT, &ttl);
|
||||
while (pos) {
|
||||
rc = pci_read_config_byte(dev, pos + 3, &cap);
|
||||
if (rc != PCIBIOS_SUCCESSFUL)
|
||||
return 0;
|
||||
|
||||
if ((cap & mask) == ht_cap)
|
||||
return pos;
|
||||
|
||||
pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
|
||||
PCI_CAP_ID_HT, &ttl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* pci_find_next_ht_capability - query a device's Hypertransport capabilities
|
||||
* @dev: PCI device to query
|
||||
* @pos: Position from which to continue searching
|
||||
* @ht_cap: Hypertransport capability code
|
||||
*
|
||||
* To be used in conjunction with pci_find_ht_capability() to search for
|
||||
* all capabilities matching @ht_cap. @pos should always be a value returned
|
||||
* from pci_find_ht_capability().
|
||||
*
|
||||
* NB. To be 100% safe against broken PCI devices, the caller should take
|
||||
* steps to avoid an infinite loop.
|
||||
*/
|
||||
int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap)
|
||||
{
|
||||
return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_next_ht_capability);
|
||||
|
||||
/**
|
||||
* pci_find_ht_capability - query a device's Hypertransport capabilities
|
||||
* @dev: PCI device to query
|
||||
* @ht_cap: Hypertransport capability code
|
||||
*
|
||||
* Tell if a device supports a given Hypertransport capability.
|
||||
* Returns an address within the device's PCI configuration space
|
||||
* or 0 in case the device does not support the request capability.
|
||||
* The address points to the PCI capability, of type PCI_CAP_ID_HT,
|
||||
* which has a Hypertransport capability matching @ht_cap.
|
||||
*/
|
||||
int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
|
||||
{
|
||||
int pos;
|
||||
|
||||
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
|
||||
if (pos)
|
||||
pos = __pci_find_next_ht_cap(dev, pos, ht_cap);
|
||||
|
||||
return pos;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_ht_capability);
|
||||
|
||||
/**
|
||||
* pci_find_parent_resource - return resource region of parent bus of given region
|
||||
* @dev: PCI device structure contains resources to be searched
|
||||
|
|
|
@ -454,6 +454,8 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
|
|||
int pci_find_capability (struct pci_dev *dev, int cap);
|
||||
int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
|
||||
int pci_find_ext_capability (struct pci_dev *dev, int cap);
|
||||
int pci_find_ht_capability (struct pci_dev *dev, int ht_cap);
|
||||
int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap);
|
||||
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
|
||||
|
||||
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
|
||||
|
|
|
@ -475,9 +475,19 @@
|
|||
#define PCI_PWR_CAP 12 /* Capability */
|
||||
#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
|
||||
|
||||
/* Hypertransport sub capability types */
|
||||
/*
|
||||
* Hypertransport sub capability types
|
||||
*
|
||||
* Unfortunately there are both 3 bit and 5 bit capability types defined
|
||||
* in the HT spec, catering for that is a little messy. You probably don't
|
||||
* want to use these directly, just use pci_find_ht_capability() and it
|
||||
* will do the right thing for you.
|
||||
*/
|
||||
#define HT_3BIT_CAP_MASK 0xE0
|
||||
#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
|
||||
#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
|
||||
|
||||
#define HT_5BIT_CAP_MASK 0xF8
|
||||
#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
|
||||
#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
|
||||
#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
|
||||
|
|
Загрузка…
Ссылка в новой задаче