Переглянути джерело

[pci] Support systems with multiple PCI root bridges

Extend the 16-bit PCI bus:dev.fn address to a 32-bit seg:bus:dev.fn
address, assuming a segment value of zero in contexts where multiple
segments are unsupported by the underlying data structures (e.g. in
the iBFT or BOFM tables).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 роки тому
джерело
коміт
f76210961c

+ 4
- 2
src/arch/x86/core/pcidirect.c Переглянути файл

@@ -36,10 +36,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
36 36
  * Prepare for Type 1 PCI configuration space access
37 37
  *
38 38
  * @v pci		PCI device
39
- * @v where	Location within PCI configuration space
39
+ * @v where		Location within PCI configuration space
40 40
  */
41 41
 void pcidirect_prepare ( struct pci_device *pci, int where ) {
42
-	outl ( ( 0x80000000 | ( pci->busdevfn << 8 ) | ( where & ~3 ) ),
42
+	uint16_t busdevfn = ( pci->busdevfn & 0xffff );
43
+
44
+	outl ( ( 0x80000000 | ( busdevfn << 8 ) | ( where & ~3 ) ),
43 45
 	       PCIDIRECT_CONFIG_ADDRESS );
44 46
 }
45 47
 

+ 11
- 2
src/core/settings.c Переглянути файл

@@ -2232,6 +2232,10 @@ static int format_busdevfn_setting ( const struct setting_type *type __unused,
2232 2232
 				     const void *raw, size_t raw_len, char *buf,
2233 2233
 				     size_t len ) {
2234 2234
 	unsigned long busdevfn;
2235
+	unsigned int seg;
2236
+	unsigned int bus;
2237
+	unsigned int slot;
2238
+	unsigned int func;
2235 2239
 	int check_len;
2236 2240
 
2237 2241
 	/* Extract numeric value */
@@ -2240,9 +2244,14 @@ static int format_busdevfn_setting ( const struct setting_type *type __unused,
2240 2244
 		return check_len;
2241 2245
 	assert ( check_len == ( int ) raw_len );
2242 2246
 
2247
+	/* Extract PCI address components */
2248
+	seg = PCI_SEG ( busdevfn );
2249
+	bus = PCI_BUS ( busdevfn );
2250
+	slot = PCI_SLOT ( busdevfn );
2251
+	func = PCI_FUNC ( busdevfn );
2252
+
2243 2253
 	/* Format value */
2244
-	return snprintf ( buf, len, "%02lx:%02lx.%lx", PCI_BUS ( busdevfn ),
2245
-			  PCI_SLOT ( busdevfn ), PCI_FUNC ( busdevfn ) );
2254
+	return snprintf ( buf, len, "%04x:%02x:%02x.%x", seg, bus, slot, func );
2246 2255
 }
2247 2256
 
2248 2257
 /** PCI bus:dev.fn setting type */

+ 4
- 4
src/drivers/bus/pci.c Переглянути файл

@@ -175,7 +175,7 @@ void adjust_pci_device ( struct pci_device *pci ) {
175 175
  * @ret rc		Return status code
176 176
  */
177 177
 int pci_read_config ( struct pci_device *pci ) {
178
-	uint16_t busdevfn;
178
+	uint32_t busdevfn;
179 179
 	uint8_t hdrtype;
180 180
 	uint32_t tmp;
181 181
 
@@ -203,8 +203,8 @@ int pci_read_config ( struct pci_device *pci ) {
203 203
 	pci_read_bases ( pci );
204 204
 
205 205
 	/* Initialise generic device component */
206
-	snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
207
-		   "PCI%02x:%02x.%x", PCI_BUS ( pci->busdevfn ),
206
+	snprintf ( pci->dev.name, sizeof ( pci->dev.name ), "%04x:%02x:%02x.%x",
207
+		   PCI_SEG ( pci->busdevfn ), PCI_BUS ( pci->busdevfn ),
208 208
 		   PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) );
209 209
 	pci->dev.desc.bus_type = BUS_TYPE_PCI;
210 210
 	pci->dev.desc.location = pci->busdevfn;
@@ -232,7 +232,7 @@ int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
232 232
 
233 233
 	/* Determine number of PCI buses */
234 234
 	if ( ! end )
235
-		end = PCI_BUSDEVFN ( pci_num_bus(), 0, 0 );
235
+		end = PCI_BUSDEVFN ( 0, pci_num_bus(), 0, 0 );
236 236
 
237 237
 	/* Find next PCI device, if any */
238 238
 	for ( ; busdevfn < end ; busdevfn++ ) {

+ 1
- 1
src/drivers/bus/pci_settings.c Переглянути файл

@@ -70,7 +70,7 @@ static int pci_settings_fetch ( struct settings *settings __unused,
70 70
 	unsigned int i;
71 71
 
72 72
 	/* Extract busdevfn, offset, and length from tag */
73
-	tag_busdevfn = ( ( setting->tag >> 16 ) & 0xffff );
73
+	tag_busdevfn = ( setting->tag >> 16 );
74 74
 	tag_offset = ( ( setting->tag >> 8 ) & 0xff );
75 75
 	tag_len = ( ( setting->tag >> 0 ) & 0xff );
76 76
 

+ 7
- 5
src/drivers/net/phantom/phantom.c Переглянути файл

@@ -2060,6 +2060,7 @@ static int phantom_probe ( struct pci_device *pci ) {
2060 2060
 	struct net_device *netdev;
2061 2061
 	struct phantom_nic *phantom;
2062 2062
 	struct settings *parent_settings;
2063
+	unsigned int busdevfn;
2063 2064
 	int rc;
2064 2065
 
2065 2066
 	/* Allocate Phantom device */
@@ -2090,19 +2091,20 @@ static int phantom_probe ( struct pci_device *pci ) {
2090 2091
 	 * B2 will have this fixed; remove this hack when B1 is no
2091 2092
 	 * longer in use.
2092 2093
 	 */
2093
-	if ( PCI_FUNC ( pci->busdevfn ) == 0 ) {
2094
+	busdevfn = pci->busdevfn;
2095
+	if ( PCI_FUNC ( busdevfn ) == 0 ) {
2094 2096
 		unsigned int i;
2095 2097
 		for ( i = 0 ; i < 8 ; i++ ) {
2096 2098
 			uint32_t temp;
2097 2099
 			pci->busdevfn =
2098
-				PCI_BUSDEVFN ( PCI_BUS ( pci->busdevfn ),
2099
-					       PCI_SLOT ( pci->busdevfn ), i );
2100
+				PCI_BUSDEVFN ( PCI_SEG ( busdevfn ),
2101
+					       PCI_BUS ( busdevfn ),
2102
+					       PCI_SLOT ( busdevfn ), i );
2100 2103
 			pci_read_config_dword ( pci, 0xc8, &temp );
2101 2104
 			pci_read_config_dword ( pci, 0xc8, &temp );
2102 2105
 			pci_write_config_dword ( pci, 0xc8, 0xf1000 );
2103 2106
 		}
2104
-		pci->busdevfn = PCI_BUSDEVFN ( PCI_BUS ( pci->busdevfn ),
2105
-					       PCI_SLOT ( pci->busdevfn ), 0 );
2107
+		pci->busdevfn = busdevfn;
2106 2108
 	}
2107 2109
 
2108 2110
 	/* Initialise the command PEG */

+ 9
- 7
src/include/ipxe/pci.h Переглянути файл

@@ -195,8 +195,8 @@ struct pci_device {
195 195
 	uint32_t class;
196 196
 	/** Interrupt number */
197 197
 	uint8_t irq;
198
-	/** Bus, device, and function (bus:dev.fn) number */
199
-	uint16_t busdevfn;
198
+	/** Segment, bus, device, and function (bus:dev.fn) number */
199
+	uint32_t busdevfn;
200 200
 	/** Driver for this device */
201 201
 	struct pci_driver *driver;
202 202
 	/** Driver-private data
@@ -241,11 +241,13 @@ struct pci_driver {
241 241
 /** Declare a fallback PCI driver */
242 242
 #define __pci_driver_fallback __table_entry ( PCI_DRIVERS, 02 )
243 243
 
244
+#define PCI_SEG( busdevfn )		( ( (busdevfn) >> 16 ) & 0xffff )
244 245
 #define PCI_BUS( busdevfn )		( ( (busdevfn) >> 8 ) & 0xff )
245 246
 #define PCI_SLOT( busdevfn )		( ( (busdevfn) >> 3 ) & 0x1f )
246 247
 #define PCI_FUNC( busdevfn )		( ( (busdevfn) >> 0 ) & 0x07 )
247
-#define PCI_BUSDEVFN( bus, slot, func )	\
248
-	( ( (bus) << 8 ) | ( (slot) << 3 ) | ( (func) << 0 ) )
248
+#define PCI_BUSDEVFN( segment, bus, slot, func )			\
249
+	( ( (segment) << 16 ) | ( (bus) << 8 ) |			\
250
+	  ( (slot) << 3 ) | ( (func) << 0 ) )
249 251
 #define PCI_FIRST_FUNC( busdevfn )	( (busdevfn) & ~0x07 )
250 252
 #define PCI_LAST_FUNC( busdevfn )	( (busdevfn) | 0x07 )
251 253
 
@@ -271,12 +273,12 @@ struct pci_driver {
271 273
 	PCI_ID( _vendor, _device, _name, _description, _data )
272 274
 
273 275
 /** PCI device debug message format */
274
-#define PCI_FMT "PCI %02x:%02x.%x"
276
+#define PCI_FMT "%04x:%02x:%02x.%x"
275 277
 
276 278
 /** PCI device debug message arguments */
277 279
 #define PCI_ARGS( pci )							\
278
-	PCI_BUS ( (pci)->busdevfn ), PCI_SLOT ( (pci)->busdevfn ),	\
279
-	PCI_FUNC ( (pci)->busdevfn )
280
+	PCI_SEG ( (pci)->busdevfn ), PCI_BUS ( (pci)->busdevfn ),	\
281
+	PCI_SLOT ( (pci)->busdevfn ), PCI_FUNC ( (pci)->busdevfn )
280 282
 
281 283
 extern void adjust_pci_device ( struct pci_device *pci );
282 284
 extern unsigned long pci_bar_start ( struct pci_device *pci,

+ 2
- 2
src/interface/bofm/bofm.c Переглянути файл

@@ -313,12 +313,12 @@ int bofm ( userptr_t bofmtab, struct pci_device *pci ) {
313 313
 		}
314 314
 		DBG ( "BOFM: slot %d port %d%s is " PCI_FMT " mport %d\n",
315 315
 		      en.slot, ( en.port + 1 ),
316
-		      ( ( en.slot || en.port ) ? "" : "(?)" ),
316
+		      ( ( en.slot || en.port ) ? "" : "(?)" ), 0,
317 317
 		      PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
318 318
 		      PCI_FUNC ( en.busdevfn ), en.mport );
319 319
 		bofm = bofm_find_busdevfn ( en.busdevfn );
320 320
 		if ( ! bofm ) {
321
-			DBG ( "BOFM: " PCI_FMT " mport %d ignored\n",
321
+			DBG ( "BOFM: " PCI_FMT " mport %d ignored\n", 0,
322 322
 			      PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
323 323
 			      PCI_FUNC ( en.busdevfn ), en.mport );
324 324
 			continue;

+ 119
- 18
src/interface/efi/efi_pci.c Переглянути файл

@@ -61,58 +61,157 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
61 61
  ******************************************************************************
62 62
  */
63 63
 
64
-/** PCI root bridge I/O protocol */
65
-static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci;
66
-EFI_REQUEST_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci );
64
+/**
65
+ * Locate EFI PCI root bridge I/O protocol
66
+ *
67
+ * @v pci		PCI device
68
+ * @ret handle		EFI PCI root bridge handle
69
+ * @ret root		EFI PCI root bridge I/O protocol, or NULL if not found
70
+ * @ret rc		Return status code
71
+ */
72
+static int efipci_root ( struct pci_device *pci, EFI_HANDLE *handle,
73
+			 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) {
74
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
75
+	EFI_HANDLE *handles;
76
+	UINTN num_handles;
77
+	union {
78
+		void *interface;
79
+		EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
80
+	} u;
81
+	EFI_STATUS efirc;
82
+	UINTN i;
83
+	int rc;
84
+
85
+	/* Enumerate all handles */
86
+	if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol,
87
+			&efi_pci_root_bridge_io_protocol_guid,
88
+			NULL, &num_handles, &handles ) ) != 0 ) {
89
+		rc = -EEFI ( efirc );
90
+		DBGC ( pci, "EFIPCI cannot locate root bridges: %s\n",
91
+		       strerror ( rc ) );
92
+		goto err_locate;
93
+	}
94
+
95
+	/* Look for matching root bridge I/O protocol */
96
+	for ( i = 0 ; i < num_handles ; i++ ) {
97
+		*handle = handles[i];
98
+		if ( ( efirc = bs->OpenProtocol ( *handle,
99
+				&efi_pci_root_bridge_io_protocol_guid,
100
+				&u.interface, efi_image_handle, *handle,
101
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
102
+			rc = -EEFI ( efirc );
103
+			DBGC ( pci, "EFIPCI cannot open %s: %s\n",
104
+			       efi_handle_name ( *handle ), strerror ( rc ) );
105
+			continue;
106
+		}
107
+		if ( u.root->SegmentNumber == PCI_SEG ( pci->busdevfn ) ) {
108
+			*root = u.root;
109
+			bs->FreePool ( handles );
110
+			return 0;
111
+		}
112
+		bs->CloseProtocol ( *handle,
113
+				    &efi_pci_root_bridge_io_protocol_guid,
114
+				    efi_image_handle, *handle );
115
+	}
116
+	DBGC ( pci, "EFIPCI found no root bridge for " PCI_FMT "\n",
117
+	       PCI_ARGS ( pci ) );
118
+	rc = -ENOENT;
119
+
120
+	bs->FreePool ( handles );
121
+ err_locate:
122
+	return rc;
123
+}
67 124
 
125
+/**
126
+ * Calculate EFI PCI configuration space address
127
+ *
128
+ * @v pci		PCI device
129
+ * @v location		Encoded offset and width
130
+ * @ret address		EFI PCI address
131
+ */
68 132
 static unsigned long efipci_address ( struct pci_device *pci,
69 133
 				      unsigned long location ) {
134
+
70 135
 	return EFI_PCI_ADDRESS ( PCI_BUS ( pci->busdevfn ),
71 136
 				 PCI_SLOT ( pci->busdevfn ),
72 137
 				 PCI_FUNC ( pci->busdevfn ),
73 138
 				 EFIPCI_OFFSET ( location ) );
74 139
 }
75 140
 
141
+/**
142
+ * Read from PCI configuration space
143
+ *
144
+ * @v pci		PCI device
145
+ * @v location		Encoded offset and width
146
+ * @ret value		Value
147
+ * @ret rc		Return status code
148
+ */
76 149
 int efipci_read ( struct pci_device *pci, unsigned long location,
77 150
 		  void *value ) {
151
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
152
+	EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
153
+	EFI_HANDLE handle;
78 154
 	EFI_STATUS efirc;
79 155
 	int rc;
80 156
 
81
-	if ( ! efipci )
82
-		return -ENOTSUP;
157
+	/* Identify root bridge */
158
+	if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
159
+		goto err_root;
83 160
 
84
-	if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ),
85
-					  efipci_address ( pci, location ), 1,
86
-					  value ) ) != 0 ) {
161
+	/* Read from configuration space */
162
+	if ( ( efirc = root->Pci.Read ( root, EFIPCI_WIDTH ( location ),
163
+					efipci_address ( pci, location ), 1,
164
+					value ) ) != 0 ) {
87 165
 		rc = -EEFI ( efirc );
88 166
 		DBG ( "EFIPCI config read from " PCI_FMT " offset %02lx "
89 167
 		      "failed: %s\n", PCI_ARGS ( pci ),
90 168
 		      EFIPCI_OFFSET ( location ), strerror ( rc ) );
91
-		return -EIO;
169
+		goto err_read;
92 170
 	}
93 171
 
94
-	return 0;
172
+ err_read:
173
+	bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
174
+			    efi_image_handle, handle );
175
+ err_root:
176
+	return rc;
95 177
 }
96 178
 
179
+/**
180
+ * Write to PCI configuration space
181
+ *
182
+ * @v pci		PCI device
183
+ * @v location		Encoded offset and width
184
+ * @v value		Value
185
+ * @ret rc		Return status code
186
+ */
97 187
 int efipci_write ( struct pci_device *pci, unsigned long location,
98 188
 		   unsigned long value ) {
189
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
190
+	EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
191
+	EFI_HANDLE handle;
99 192
 	EFI_STATUS efirc;
100 193
 	int rc;
101 194
 
102
-	if ( ! efipci )
103
-		return -ENOTSUP;
195
+	/* Identify root bridge */
196
+	if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
197
+		goto err_root;
104 198
 
105
-	if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
106
-					   efipci_address ( pci, location ), 1,
107
-					   &value ) ) != 0 ) {
199
+	/* Read from configuration space */
200
+	if ( ( efirc = root->Pci.Write ( root, EFIPCI_WIDTH ( location ),
201
+					 efipci_address ( pci, location ), 1,
202
+					 &value ) ) != 0 ) {
108 203
 		rc = -EEFI ( efirc );
109 204
 		DBG ( "EFIPCI config write to " PCI_FMT " offset %02lx "
110 205
 		      "failed: %s\n", PCI_ARGS ( pci ),
111 206
 		      EFIPCI_OFFSET ( location ), strerror ( rc ) );
112
-		return -EIO;
207
+		goto err_write;
113 208
 	}
114 209
 
115
-	return 0;
210
+ err_write:
211
+	bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
212
+			    efi_image_handle, handle );
213
+ err_root:
214
+	return rc;
116 215
 }
117 216
 
118 217
 PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
@@ -146,6 +245,7 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes,
146 245
 		void *interface;
147 246
 	} pci_io;
148 247
 	UINTN pci_segment, pci_bus, pci_dev, pci_fn;
248
+	unsigned int busdevfn;
149 249
 	EFI_STATUS efirc;
150 250
 	int rc;
151 251
 
@@ -190,7 +290,8 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes,
190 290
 				    EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
191 291
 
192 292
 	/* Populate PCI device */
193
-	pci_init ( pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
293
+	busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn );
294
+	pci_init ( pci, busdevfn );
194 295
 	if ( ( rc = pci_read_config ( pci ) ) != 0 ) {
195 296
 		DBGC ( device, "EFIPCI %s cannot read PCI configuration: %s\n",
196 297
 		       efi_handle_name ( device ), strerror ( rc ) );

+ 3
- 1
src/tests/settings_test.c Переглянути файл

@@ -422,7 +422,9 @@ static void settings_test_exec ( void ) {
422 422
 
423 423
 	/* "busdevfn" setting type (no store capability) */
424 424
 	fetchf_ok ( &test_settings, &test_busdevfn_setting,
425
-		    RAW ( 0x03, 0x45 ), "03:08.5" );
425
+		    RAW ( 0x03, 0x45 ), "0000:03:08.5" );
426
+	fetchf_ok ( &test_settings, &test_busdevfn_setting,
427
+		    RAW ( 0x00, 0x02, 0x0a, 0x21 ), "0002:0a:04.1" );
426 428
 
427 429
 	/* Clear and unregister test settings block */
428 430
 	clear_settings ( &test_settings );

Завантаження…
Відмінити
Зберегти