diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2006-11-22 02:26:18 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-20 13:54:42 -0500 |
commit | 687d5fe3dc33794efb500f42164a0588e2647914 (patch) | |
tree | 9d344d790ae2e9d6214c2b2941360e5c0ef97f7b | |
parent | d3bac118fb27a365d5e9f54f4a078eb9b42f968f (diff) |
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>
-rw-r--r-- | drivers/pci/pci.c | 84 | ||||
-rw-r--r-- | include/linux/pci.h | 2 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 12 |
3 files changed, 94 insertions, 4 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4627a51d1d6c..6bfb942428e4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -68,12 +68,14 @@ pci_max_busnr(void) | |||
68 | 68 | ||
69 | #endif /* 0 */ | 69 | #endif /* 0 */ |
70 | 70 | ||
71 | static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) | 71 | #define PCI_FIND_CAP_TTL 48 |
72 | |||
73 | static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, | ||
74 | u8 pos, int cap, int *ttl) | ||
72 | { | 75 | { |
73 | u8 id; | 76 | u8 id; |
74 | int ttl = 48; | ||
75 | 77 | ||
76 | while (ttl--) { | 78 | while ((*ttl)--) { |
77 | pci_bus_read_config_byte(bus, devfn, pos, &pos); | 79 | pci_bus_read_config_byte(bus, devfn, pos, &pos); |
78 | if (pos < 0x40) | 80 | if (pos < 0x40) |
79 | break; | 81 | break; |
@@ -89,6 +91,14 @@ static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, | |||
89 | return 0; | 91 | return 0; |
90 | } | 92 | } |
91 | 93 | ||
94 | static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, | ||
95 | u8 pos, int cap) | ||
96 | { | ||
97 | int ttl = PCI_FIND_CAP_TTL; | ||
98 | |||
99 | return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); | ||
100 | } | ||
101 | |||
92 | int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) | 102 | int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) |
93 | { | 103 | { |
94 | return __pci_find_next_cap(dev->bus, dev->devfn, | 104 | return __pci_find_next_cap(dev->bus, dev->devfn, |
@@ -224,6 +234,74 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) | |||
224 | } | 234 | } |
225 | EXPORT_SYMBOL_GPL(pci_find_ext_capability); | 235 | EXPORT_SYMBOL_GPL(pci_find_ext_capability); |
226 | 236 | ||
237 | static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) | ||
238 | { | ||
239 | int rc, ttl = PCI_FIND_CAP_TTL; | ||
240 | u8 cap, mask; | ||
241 | |||
242 | if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST) | ||
243 | mask = HT_3BIT_CAP_MASK; | ||
244 | else | ||
245 | mask = HT_5BIT_CAP_MASK; | ||
246 | |||
247 | pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos, | ||
248 | PCI_CAP_ID_HT, &ttl); | ||
249 | while (pos) { | ||
250 | rc = pci_read_config_byte(dev, pos + 3, &cap); | ||
251 | if (rc != PCIBIOS_SUCCESSFUL) | ||
252 | return 0; | ||
253 | |||
254 | if ((cap & mask) == ht_cap) | ||
255 | return pos; | ||
256 | |||
257 | pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos, | ||
258 | PCI_CAP_ID_HT, &ttl); | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | /** | ||
264 | * pci_find_next_ht_capability - query a device's Hypertransport capabilities | ||
265 | * @dev: PCI device to query | ||
266 | * @pos: Position from which to continue searching | ||
267 | * @ht_cap: Hypertransport capability code | ||
268 | * | ||
269 | * To be used in conjunction with pci_find_ht_capability() to search for | ||
270 | * all capabilities matching @ht_cap. @pos should always be a value returned | ||
271 | * from pci_find_ht_capability(). | ||
272 | * | ||
273 | * NB. To be 100% safe against broken PCI devices, the caller should take | ||
274 | * steps to avoid an infinite loop. | ||
275 | */ | ||
276 | int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap) | ||
277 | { | ||
278 | return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap); | ||
279 | } | ||
280 | EXPORT_SYMBOL_GPL(pci_find_next_ht_capability); | ||
281 | |||
282 | /** | ||
283 | * pci_find_ht_capability - query a device's Hypertransport capabilities | ||
284 | * @dev: PCI device to query | ||
285 | * @ht_cap: Hypertransport capability code | ||
286 | * | ||
287 | * Tell if a device supports a given Hypertransport capability. | ||
288 | * Returns an address within the device's PCI configuration space | ||
289 | * or 0 in case the device does not support the request capability. | ||
290 | * The address points to the PCI capability, of type PCI_CAP_ID_HT, | ||
291 | * which has a Hypertransport capability matching @ht_cap. | ||
292 | */ | ||
293 | int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) | ||
294 | { | ||
295 | int pos; | ||
296 | |||
297 | pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); | ||
298 | if (pos) | ||
299 | pos = __pci_find_next_ht_cap(dev, pos, ht_cap); | ||
300 | |||
301 | return pos; | ||
302 | } | ||
303 | EXPORT_SYMBOL_GPL(pci_find_ht_capability); | ||
304 | |||
227 | /** | 305 | /** |
228 | * pci_find_parent_resource - return resource region of parent bus of given region | 306 | * pci_find_parent_resource - return resource region of parent bus of given region |
229 | * @dev: PCI device structure contains resources to be searched | 307 | * @dev: PCI device structure contains resources to be searched |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 769e132b78d3..b20ffb65300f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -454,6 +454,8 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); | |||
454 | int pci_find_capability (struct pci_dev *dev, int cap); | 454 | int pci_find_capability (struct pci_dev *dev, int cap); |
455 | int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); | 455 | int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); |
456 | int pci_find_ext_capability (struct pci_dev *dev, int cap); | 456 | int pci_find_ext_capability (struct pci_dev *dev, int cap); |
457 | int pci_find_ht_capability (struct pci_dev *dev, int ht_cap); | ||
458 | int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap); | ||
457 | struct pci_bus *pci_find_next_bus(const struct pci_bus *from); | 459 | struct pci_bus *pci_find_next_bus(const struct pci_bus *from); |
458 | 460 | ||
459 | struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, | 461 | struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 064b1dc71c22..a54b48f7cee2 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
@@ -475,9 +475,19 @@ | |||
475 | #define PCI_PWR_CAP 12 /* Capability */ | 475 | #define PCI_PWR_CAP 12 /* Capability */ |
476 | #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ | 476 | #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ |
477 | 477 | ||
478 | /* Hypertransport sub capability types */ | 478 | /* |
479 | * Hypertransport sub capability types | ||
480 | * | ||
481 | * Unfortunately there are both 3 bit and 5 bit capability types defined | ||
482 | * in the HT spec, catering for that is a little messy. You probably don't | ||
483 | * want to use these directly, just use pci_find_ht_capability() and it | ||
484 | * will do the right thing for you. | ||
485 | */ | ||
486 | #define HT_3BIT_CAP_MASK 0xE0 | ||
479 | #define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ | 487 | #define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ |
480 | #define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ | 488 | #define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ |
489 | |||
490 | #define HT_5BIT_CAP_MASK 0xF8 | ||
481 | #define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ | 491 | #define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ |
482 | #define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ | 492 | #define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ |
483 | #define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ | 493 | #define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ |