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,6 +3,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3 3
 #include <stdint.h>
4 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 25
  * Look for a PCI capability
8 26
  *
@@ -17,9 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
17 35
  */
18 36
 int pci_find_capability ( struct pci_device *pci, int cap ) {
19 37
 	uint16_t status;
20
-	uint8_t pos, id;
38
+	uint8_t pos;
21 39
 	uint8_t hdr_type;
22
-	int ttl = 48;
23 40
 
24 41
 	pci_read_config_word ( pci, PCI_STATUS, &status );
25 42
 	if ( ! ( status & PCI_STATUS_CAP_LIST ) )
@@ -36,17 +53,28 @@ int pci_find_capability ( struct pci_device *pci, int cap ) {
36 53
 		pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos );
37 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,6 +286,8 @@ extern int pci_find_driver ( struct pci_device *pci );
286 286
 extern int pci_probe ( struct pci_device *pci );
287 287
 extern void pci_remove ( struct pci_device *pci );
288 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 291
 extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
290 292
 
291 293
 /**

Loading…
Cancel
Save