aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2006-11-22 02:26:18 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-20 13:54:42 -0500
commit687d5fe3dc33794efb500f42164a0588e2647914 (patch)
tree9d344d790ae2e9d6214c2b2941360e5c0ef97f7b
parentd3bac118fb27a365d5e9f54f4a078eb9b42f968f (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.c84
-rw-r--r--include/linux/pci.h2
-rw-r--r--include/linux/pci_regs.h12
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
71static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) 71#define PCI_FIND_CAP_TTL 48
72
73static 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
94static 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
92int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) 102int 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}
225EXPORT_SYMBOL_GPL(pci_find_ext_capability); 235EXPORT_SYMBOL_GPL(pci_find_ext_capability);
226 236
237static 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 */
276int 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}
280EXPORT_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 */
293int 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}
303EXPORT_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);
454int pci_find_capability (struct pci_dev *dev, int cap); 454int pci_find_capability (struct pci_dev *dev, int cap);
455int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); 455int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
456int pci_find_ext_capability (struct pci_dev *dev, int cap); 456int pci_find_ext_capability (struct pci_dev *dev, int cap);
457int pci_find_ht_capability (struct pci_dev *dev, int ht_cap);
458int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap);
457struct pci_bus *pci_find_next_bus(const struct pci_bus *from); 459struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
458 460
459struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, 461struct 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 */