Browse Source

[pci] Add pci_find_next_capability()

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 <lprosek@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Ladi Prosek 8 years ago
parent
commit
2379494918
2 changed files with 43 additions and 13 deletions
  1. 41
    13
      src/drivers/bus/pciextra.c
  2. 2
    0
      src/include/ipxe/pci.h

+ 41
- 13
src/drivers/bus/pciextra.c View File

3
 #include <stdint.h>
3
 #include <stdint.h>
4
 #include <ipxe/pci.h>
4
 #include <ipxe/pci.h>
5
 
5
 
6
+static int pci_find_capability_common ( struct pci_device *pci,
7
+					uint8_t pos, int cap ) {
8
+	uint8_t id;
9
+	int ttl = 48;
10
+
11
+	while ( ttl-- && pos >= 0x40 ) {
12
+		pos &= ~3;
13
+		pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id );
14
+		DBG ( "PCI Capability: %d\n", id );
15
+		if ( id == 0xff )
16
+			break;
17
+		if ( id == cap )
18
+			return pos;
19
+		pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos );
20
+	}
21
+	return 0;
22
+}
23
+
6
 /**
24
 /**
7
  * Look for a PCI capability
25
  * Look for a PCI capability
8
  *
26
  *
17
  */
35
  */
18
 int pci_find_capability ( struct pci_device *pci, int cap ) {
36
 int pci_find_capability ( struct pci_device *pci, int cap ) {
19
 	uint16_t status;
37
 	uint16_t status;
20
-	uint8_t pos, id;
38
+	uint8_t pos;
21
 	uint8_t hdr_type;
39
 	uint8_t hdr_type;
22
-	int ttl = 48;
23
 
40
 
24
 	pci_read_config_word ( pci, PCI_STATUS, &status );
41
 	pci_read_config_word ( pci, PCI_STATUS, &status );
25
 	if ( ! ( status & PCI_STATUS_CAP_LIST ) )
42
 	if ( ! ( status & PCI_STATUS_CAP_LIST ) )
36
 		pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos );
53
 		pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos );
37
 		break;
54
 		break;
38
 	}
55
 	}
39
-	while ( ttl-- && pos >= 0x40 ) {
40
-		pos &= ~3;
41
-		pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id );
42
-		DBG ( "PCI Capability: %d\n", id );
43
-		if ( id == 0xff )
44
-			break;
45
-		if ( id == cap )
46
-			return pos;
47
-		pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos );
48
-	}
49
-	return 0;
56
+	return pci_find_capability_common ( pci, pos, cap );
57
+}
58
+
59
+/**
60
+ * Look for another PCI capability
61
+ *
62
+ * @v pci		PCI device to query
63
+ * @v pos		Address of the current capability
64
+ * @v cap		Capability code
65
+ * @ret address		Address of capability, or 0 if not found
66
+ *
67
+ * Determine whether or not a device supports a given PCI capability
68
+ * starting the search at a given address within the device's PCI
69
+ * configuration space. Returns the address of the next capability
70
+ * structure within the device's PCI configuration space, or 0 if the
71
+ * device does not support another such capability.
72
+ */
73
+int pci_find_next_capability ( struct pci_device *pci, int pos, int cap ) {
74
+	uint8_t new_pos;
75
+
76
+	pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &new_pos );
77
+	return pci_find_capability_common ( pci, new_pos, cap );
50
 }
78
 }
51
 
79
 
52
 /**
80
 /**

+ 2
- 0
src/include/ipxe/pci.h View File

286
 extern int pci_probe ( struct pci_device *pci );
286
 extern int pci_probe ( struct pci_device *pci );
287
 extern void pci_remove ( struct pci_device *pci );
287
 extern void pci_remove ( struct pci_device *pci );
288
 extern int pci_find_capability ( struct pci_device *pci, int capability );
288
 extern int pci_find_capability ( struct pci_device *pci, int capability );
289
+extern int pci_find_next_capability ( struct pci_device *pci,
290
+				      int pos, int capability );
289
 extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
291
 extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
290
 
292
 
291
 /**
293
 /**

Loading…
Cancel
Save