Browse Source

[pci] Add pci_find_next() to iterate over existent PCI devices

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
6d910559b3
2 changed files with 46 additions and 21 deletions
  1. 44
    21
      src/drivers/bus/pci.c
  2. 2
    0
      src/include/ipxe/pci.h

+ 44
- 21
src/drivers/bus/pci.c View File

@@ -171,8 +171,20 @@ void adjust_pci_device ( struct pci_device *pci ) {
171 171
  * @ret rc		Return status code
172 172
  */
173 173
 int pci_read_config ( struct pci_device *pci ) {
174
+	uint16_t busdevfn;
175
+	uint8_t hdrtype;
174 176
 	uint32_t tmp;
175 177
 
178
+	/* Ignore all but the first function on non-multifunction devices */
179
+	if ( PCI_FUNC ( pci->busdevfn ) != 0 ) {
180
+		busdevfn = pci->busdevfn;
181
+		pci->busdevfn = PCI_FIRST_FUNC ( pci->busdevfn );
182
+		pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
183
+		pci->busdevfn = busdevfn;
184
+		if ( ! ( hdrtype & 0x80 ) )
185
+			return -ENODEV;
186
+	}
187
+
176 188
 	/* Check for physical device presence */
177 189
 	pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
178 190
 	if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
@@ -203,6 +215,32 @@ int pci_read_config ( struct pci_device *pci ) {
203 215
 	return 0;
204 216
 }
205 217
 
218
+/**
219
+ * Find next device on PCI bus
220
+ *
221
+ * @v pci		PCI device to fill in
222
+ * @v busdevfn		Starting bus:dev.fn address
223
+ * @ret busdevfn	Bus:dev.fn address of next PCI device, or negative error
224
+ */
225
+int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
226
+	static unsigned int end;
227
+	int rc;
228
+
229
+	/* Determine number of PCI buses */
230
+	if ( ! end )
231
+		end = PCI_BUSDEVFN ( pci_num_bus(), 0, 0 );
232
+
233
+	/* Find next PCI device, if any */
234
+	for ( ; busdevfn < end ; busdevfn++ ) {
235
+		memset ( pci, 0, sizeof ( *pci ) );
236
+		pci_init ( pci, busdevfn );
237
+		if ( ( rc = pci_read_config ( pci ) ) == 0 )
238
+			return busdevfn;
239
+	}
240
+
241
+	return -ENODEV;
242
+}
243
+
206 244
 /**
207 245
  * Find driver for PCI device
208 246
  *
@@ -276,14 +314,10 @@ void pci_remove ( struct pci_device *pci ) {
276 314
  */
277 315
 static int pcibus_probe ( struct root_device *rootdev ) {
278 316
 	struct pci_device *pci = NULL;
279
-	unsigned int num_bus;
280
-	unsigned int busdevfn;
281
-	uint8_t hdrtype = 0;
317
+	int busdevfn = 0;
282 318
 	int rc;
283 319
 
284
-	num_bus = pci_num_bus();
285
-	for ( busdevfn = 0 ; busdevfn < PCI_BUSDEVFN ( num_bus, 0, 0 ) ;
286
-	      busdevfn++ ) {
320
+	for ( busdevfn = 0 ; 1 ; busdevfn++ ) {
287 321
 
288 322
 		/* Allocate struct pci_device */
289 323
 		if ( ! pci )
@@ -292,22 +326,11 @@ static int pcibus_probe ( struct root_device *rootdev ) {
292 326
 			rc = -ENOMEM;
293 327
 			goto err;
294 328
 		}
295
-		memset ( pci, 0, sizeof ( *pci ) );
296
-		pci_init ( pci, busdevfn );
297
-			
298
-		/* Skip all but the first function on
299
-		 * non-multifunction cards
300
-		 */
301
-		if ( PCI_FUNC ( busdevfn ) == 0 ) {
302
-			pci_read_config_byte ( pci, PCI_HEADER_TYPE,
303
-					       &hdrtype );
304
-		} else if ( ! ( hdrtype & 0x80 ) ) {
305
-			continue;
306
-		}
307 329
 
308
-		/* Read device configuration */
309
-		if ( ( rc = pci_read_config ( pci ) ) != 0 )
310
-			continue;
330
+		/* Find next PCI device, if any */
331
+		busdevfn = pci_find_next ( pci, busdevfn );
332
+		if ( busdevfn < 0 )
333
+			break;
311 334
 
312 335
 		/* Look for a driver */
313 336
 		if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {

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

@@ -351,6 +351,7 @@ struct pci_driver {
351 351
 #define PCI_FUNC( busdevfn )		( ( (busdevfn) >> 0 ) & 0x07 )
352 352
 #define PCI_BUSDEVFN( bus, slot, func )	\
353 353
 	( ( (bus) << 8 ) | ( (slot) << 3 ) | ( (func) << 0 ) )
354
+#define PCI_FIRST_FUNC( busdevfn )	( (busdevfn) & ~0x07 )
354 355
 
355 356
 #define PCI_BASE_CLASS( class )		( (class) >> 16 )
356 357
 #define PCI_SUB_CLASS( class )		( ( (class) >> 8 ) & 0xff )
@@ -385,6 +386,7 @@ extern void adjust_pci_device ( struct pci_device *pci );
385 386
 extern unsigned long pci_bar_start ( struct pci_device *pci,
386 387
 				     unsigned int reg );
387 388
 extern int pci_read_config ( struct pci_device *pci );
389
+extern int pci_find_next ( struct pci_device *pci, unsigned int busdevfn );
388 390
 extern int pci_find_driver ( struct pci_device *pci );
389 391
 extern int pci_probe ( struct pci_device *pci );
390 392
 extern void pci_remove ( struct pci_device *pci );

Loading…
Cancel
Save