|
@@ -164,23 +164,54 @@ void adjust_pci_device ( struct pci_device *pci ) {
|
164
|
164
|
}
|
165
|
165
|
|
166
|
166
|
/**
|
167
|
|
- * Probe a PCI device
|
|
167
|
+ * Read PCI device configuration
|
168
|
168
|
*
|
169
|
169
|
* @v pci PCI device
|
170
|
170
|
* @ret rc Return status code
|
|
171
|
+ */
|
|
172
|
+int pci_read_config ( struct pci_device *pci ) {
|
|
173
|
+ uint32_t tmp;
|
|
174
|
+
|
|
175
|
+ /* Check for physical device presence */
|
|
176
|
+ pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
|
|
177
|
+ if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
|
|
178
|
+ return -ENODEV;
|
|
179
|
+
|
|
180
|
+ /* Populate struct pci_device */
|
|
181
|
+ pci->vendor = ( tmp & 0xffff );
|
|
182
|
+ pci->device = ( tmp >> 16 );
|
|
183
|
+ pci_read_config_dword ( pci, PCI_REVISION, &tmp );
|
|
184
|
+ pci->class = ( tmp >> 8 );
|
|
185
|
+ pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
|
|
186
|
+ pci_read_bases ( pci );
|
|
187
|
+
|
|
188
|
+ /* Initialise generic device component */
|
|
189
|
+ snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
|
|
190
|
+ "PCI%02x:%02x.%x", PCI_BUS ( pci->busdevfn ),
|
|
191
|
+ PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) );
|
|
192
|
+ pci->dev.desc.bus_type = BUS_TYPE_PCI;
|
|
193
|
+ pci->dev.desc.location = pci->busdevfn;
|
|
194
|
+ pci->dev.desc.vendor = pci->vendor;
|
|
195
|
+ pci->dev.desc.device = pci->device;
|
|
196
|
+ pci->dev.desc.class = pci->class;
|
|
197
|
+ pci->dev.desc.ioaddr = pci->ioaddr;
|
|
198
|
+ pci->dev.desc.irq = pci->irq;
|
|
199
|
+ INIT_LIST_HEAD ( &pci->dev.siblings );
|
|
200
|
+ INIT_LIST_HEAD ( &pci->dev.children );
|
|
201
|
+
|
|
202
|
+ return 0;
|
|
203
|
+}
|
|
204
|
+
|
|
205
|
+/**
|
|
206
|
+ * Find driver for PCI device
|
171
|
207
|
*
|
172
|
|
- * Searches for a driver for the PCI device. If a driver is found,
|
173
|
|
- * its probe() routine is called.
|
|
208
|
+ * @v pci PCI device
|
|
209
|
+ * @ret rc Return status code
|
174
|
210
|
*/
|
175
|
|
-static int pci_probe ( struct pci_device *pci ) {
|
|
211
|
+int pci_find_driver ( struct pci_device *pci ) {
|
176
|
212
|
struct pci_driver *driver;
|
177
|
213
|
struct pci_device_id *id;
|
178
|
214
|
unsigned int i;
|
179
|
|
- int rc;
|
180
|
|
-
|
181
|
|
- DBGC ( pci, PCI_FMT " is %04x:%04x mem %lx io %lx irq %d\n",
|
182
|
|
- PCI_ARGS ( pci ), pci->vendor, pci->device, pci->membase,
|
183
|
|
- pci->ioaddr, pci->irq );
|
184
|
215
|
|
185
|
216
|
for_each_table_entry ( driver, PCI_DRIVERS ) {
|
186
|
217
|
for ( i = 0 ; i < driver->id_count ; i++ ) {
|
|
@@ -191,21 +222,37 @@ static int pci_probe ( struct pci_device *pci ) {
|
191
|
222
|
if ( ( id->device != PCI_ANY_ID ) &&
|
192
|
223
|
( id->device != pci->device ) )
|
193
|
224
|
continue;
|
194
|
|
- pci->driver = driver;
|
195
|
|
- pci->id = id;
|
196
|
|
- DBGC ( pci, "...using driver %s\n", pci->id->name );
|
197
|
|
- if ( ( rc = driver->probe ( pci ) ) != 0 ) {
|
198
|
|
- DBGC ( pci, "......probe failed: %s\n",
|
199
|
|
- strerror ( rc ) );
|
200
|
|
- continue;
|
201
|
|
- }
|
202
|
|
- DBGC ( pci, PCI_FMT " added\n", PCI_ARGS ( pci ) );
|
|
225
|
+ pci_set_driver ( pci, driver, id );
|
203
|
226
|
return 0;
|
204
|
227
|
}
|
205
|
228
|
}
|
|
229
|
+ return -ENOENT;
|
|
230
|
+}
|
206
|
231
|
|
207
|
|
- DBGC ( pci, "...no driver found\n" );
|
208
|
|
- return -ENOTTY;
|
|
232
|
+/**
|
|
233
|
+ * Probe a PCI device
|
|
234
|
+ *
|
|
235
|
+ * @v pci PCI device
|
|
236
|
+ * @ret rc Return status code
|
|
237
|
+ *
|
|
238
|
+ * Searches for a driver for the PCI device. If a driver is found,
|
|
239
|
+ * its probe() routine is called.
|
|
240
|
+ */
|
|
241
|
+int pci_probe ( struct pci_device *pci ) {
|
|
242
|
+ int rc;
|
|
243
|
+
|
|
244
|
+ DBGC ( pci, PCI_FMT " (%04x:%04x) has driver \"%s\"\n",
|
|
245
|
+ PCI_ARGS ( pci ), pci->vendor, pci->device, pci->id->name );
|
|
246
|
+ DBGC ( pci, PCI_FMT " has mem %lx io %lx irq %d\n",
|
|
247
|
+ PCI_ARGS ( pci ), pci->membase, pci->ioaddr, pci->irq );
|
|
248
|
+
|
|
249
|
+ if ( ( rc = pci->driver->probe ( pci ) ) != 0 ) {
|
|
250
|
+ DBGC ( pci, PCI_FMT " probe failed: %s\n",
|
|
251
|
+ PCI_ARGS ( pci ), strerror ( rc ) );
|
|
252
|
+ return rc;
|
|
253
|
+ }
|
|
254
|
+
|
|
255
|
+ return 0;
|
209
|
256
|
}
|
210
|
257
|
|
211
|
258
|
/**
|
|
@@ -213,7 +260,7 @@ static int pci_probe ( struct pci_device *pci ) {
|
213
|
260
|
*
|
214
|
261
|
* @v pci PCI device
|
215
|
262
|
*/
|
216
|
|
-static void pci_remove ( struct pci_device *pci ) {
|
|
263
|
+void pci_remove ( struct pci_device *pci ) {
|
217
|
264
|
pci->driver->remove ( pci );
|
218
|
265
|
DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) );
|
219
|
266
|
}
|
|
@@ -231,7 +278,6 @@ static int pcibus_probe ( struct root_device *rootdev ) {
|
231
|
278
|
unsigned int num_bus;
|
232
|
279
|
unsigned int busdevfn;
|
233
|
280
|
uint8_t hdrtype = 0;
|
234
|
|
- uint32_t tmp;
|
235
|
281
|
int rc;
|
236
|
282
|
|
237
|
283
|
num_bus = pci_num_bus();
|
|
@@ -246,7 +292,7 @@ static int pcibus_probe ( struct root_device *rootdev ) {
|
246
|
292
|
goto err;
|
247
|
293
|
}
|
248
|
294
|
memset ( pci, 0, sizeof ( *pci ) );
|
249
|
|
- pci->busdevfn = busdevfn;
|
|
295
|
+ pci_init ( pci, busdevfn );
|
250
|
296
|
|
251
|
297
|
/* Skip all but the first function on
|
252
|
298
|
* non-multifunction cards
|
|
@@ -258,37 +304,23 @@ static int pcibus_probe ( struct root_device *rootdev ) {
|
258
|
304
|
continue;
|
259
|
305
|
}
|
260
|
306
|
|
261
|
|
- /* Check for physical device presence */
|
262
|
|
- pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
|
263
|
|
- if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
|
|
307
|
+ /* Read device configuration */
|
|
308
|
+ if ( ( rc = pci_read_config ( pci ) ) != 0 )
|
264
|
309
|
continue;
|
265
|
|
-
|
266
|
|
- /* Populate struct pci_device */
|
267
|
|
- pci->vendor = ( tmp & 0xffff );
|
268
|
|
- pci->device = ( tmp >> 16 );
|
269
|
|
- pci_read_config_dword ( pci, PCI_REVISION, &tmp );
|
270
|
|
- pci->class = ( tmp >> 8 );
|
271
|
|
- pci_read_config_byte ( pci, PCI_INTERRUPT_LINE,
|
272
|
|
- &pci->irq );
|
273
|
|
- pci_read_bases ( pci );
|
|
310
|
+
|
|
311
|
+ /* Look for a driver */
|
|
312
|
+ if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
|
|
313
|
+ DBGC ( pci, PCI_FMT " (%04x:%04x) has no driver\n",
|
|
314
|
+ PCI_ARGS ( pci ), pci->vendor, pci->device );
|
|
315
|
+ continue;
|
|
316
|
+ }
|
274
|
317
|
|
275
|
318
|
/* Add to device hierarchy */
|
276
|
|
- snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
|
277
|
|
- "PCI%02x:%02x.%x", PCI_BUS ( busdevfn ),
|
278
|
|
- PCI_SLOT ( busdevfn ), PCI_FUNC ( busdevfn ) );
|
279
|
|
- pci->dev.desc.bus_type = BUS_TYPE_PCI;
|
280
|
|
- pci->dev.desc.location = pci->busdevfn;
|
281
|
|
- pci->dev.desc.vendor = pci->vendor;
|
282
|
|
- pci->dev.desc.device = pci->device;
|
283
|
|
- pci->dev.desc.class = pci->class;
|
284
|
|
- pci->dev.desc.ioaddr = pci->ioaddr;
|
285
|
|
- pci->dev.desc.irq = pci->irq;
|
286
|
319
|
pci->dev.parent = &rootdev->dev;
|
287
|
320
|
list_add ( &pci->dev.siblings, &rootdev->dev.children);
|
288
|
|
- INIT_LIST_HEAD ( &pci->dev.children );
|
289
|
321
|
|
290
|
322
|
/* Look for a driver */
|
291
|
|
- if ( pci_probe ( pci ) == 0 ) {
|
|
323
|
+ if ( ( rc = pci_probe ( pci ) ) == 0 ) {
|
292
|
324
|
/* pcidev registered, we can drop our ref */
|
293
|
325
|
pci = NULL;
|
294
|
326
|
} else {
|