|
@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
25
|
25
|
|
26
|
26
|
#include <string.h>
|
27
|
27
|
#include <strings.h>
|
|
28
|
+#include <stdlib.h>
|
28
|
29
|
#include <unistd.h>
|
29
|
30
|
#include <errno.h>
|
30
|
31
|
#include <ipxe/netdevice.h>
|
|
@@ -137,6 +138,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
137
|
138
|
*/
|
138
|
139
|
#define PCI_MAX_BAR 6
|
139
|
140
|
|
|
141
|
+/** An NII memory mapping */
|
|
142
|
+struct nii_mapping {
|
|
143
|
+ /** List of mappings */
|
|
144
|
+ struct list_head list;
|
|
145
|
+ /** Mapped address */
|
|
146
|
+ UINT64 addr;
|
|
147
|
+ /** Mapping cookie created by PCI I/O protocol */
|
|
148
|
+ VOID *mapping;
|
|
149
|
+};
|
|
150
|
+
|
140
|
151
|
/** An NII NIC */
|
141
|
152
|
struct nii_nic {
|
142
|
153
|
/** EFI device */
|
|
@@ -179,6 +190,9 @@ struct nii_nic {
|
179
|
190
|
struct io_buffer *txbuf;
|
180
|
191
|
/** Current receive buffer */
|
181
|
192
|
struct io_buffer *rxbuf;
|
|
193
|
+
|
|
194
|
+ /** Mapping list */
|
|
195
|
+ struct list_head mappings;
|
182
|
196
|
};
|
183
|
197
|
|
184
|
198
|
/** Maximum number of received packets per poll */
|
|
@@ -280,7 +294,19 @@ static int nii_pci_open ( struct nii_nic *nii ) {
|
280
|
294
|
*/
|
281
|
295
|
static void nii_pci_close ( struct nii_nic *nii ) {
|
282
|
296
|
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
|
297
|
+ struct nii_mapping *map;
|
|
298
|
+ struct nii_mapping *tmp;
|
|
299
|
+
|
|
300
|
+ /* Remove any stale mappings */
|
|
301
|
+ list_for_each_entry_safe ( map, tmp, &nii->mappings, list ) {
|
|
302
|
+ DBGC ( nii, "NII %s removing stale mapping %#llx\n",
|
|
303
|
+ nii->dev.name, ( ( unsigned long long ) map->addr ) );
|
|
304
|
+ nii->pci_io->Unmap ( nii->pci_io, map->mapping );
|
|
305
|
+ list_del ( &map->list );
|
|
306
|
+ free ( map );
|
|
307
|
+ }
|
283
|
308
|
|
|
309
|
+ /* Close protocols */
|
284
|
310
|
bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid,
|
285
|
311
|
efi_image_handle, nii->efidev->device );
|
286
|
312
|
}
|
|
@@ -331,6 +357,139 @@ static EFIAPI VOID nii_io ( UINT64 unique_id, UINT8 op, UINT8 len, UINT64 addr,
|
331
|
357
|
}
|
332
|
358
|
}
|
333
|
359
|
|
|
360
|
+/**
|
|
361
|
+ * Map callback
|
|
362
|
+ *
|
|
363
|
+ * @v unique_id NII NIC
|
|
364
|
+ * @v addr Address of memory to be mapped
|
|
365
|
+ * @v len Length of memory to be mapped
|
|
366
|
+ * @v dir Direction of data flow
|
|
367
|
+ * @v mapped Device mapped address to fill in
|
|
368
|
+ */
|
|
369
|
+static EFIAPI VOID nii_map ( UINT64 unique_id, UINT64 addr, UINT32 len,
|
|
370
|
+ UINT32 dir, UINT64 mapped ) {
|
|
371
|
+ struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id );
|
|
372
|
+ EFI_PHYSICAL_ADDRESS *phys = ( ( void * ) ( intptr_t ) mapped );
|
|
373
|
+ EFI_PCI_IO_PROTOCOL_OPERATION op;
|
|
374
|
+ struct nii_mapping *map;
|
|
375
|
+ UINTN count = len;
|
|
376
|
+ EFI_STATUS efirc;
|
|
377
|
+ int rc;
|
|
378
|
+
|
|
379
|
+ /* Return a zero mapped address on failure */
|
|
380
|
+ *phys = 0;
|
|
381
|
+
|
|
382
|
+ /* Determine PCI mapping operation */
|
|
383
|
+ switch ( dir ) {
|
|
384
|
+ case TO_AND_FROM_DEVICE:
|
|
385
|
+ op = EfiPciIoOperationBusMasterCommonBuffer;
|
|
386
|
+ break;
|
|
387
|
+ case FROM_DEVICE:
|
|
388
|
+ op = EfiPciIoOperationBusMasterWrite;
|
|
389
|
+ break;
|
|
390
|
+ case TO_DEVICE:
|
|
391
|
+ op = EfiPciIoOperationBusMasterRead;
|
|
392
|
+ break;
|
|
393
|
+ default:
|
|
394
|
+ DBGC ( nii, "NII %s unsupported mapping direction %d\n",
|
|
395
|
+ nii->dev.name, dir );
|
|
396
|
+ goto err_dir;
|
|
397
|
+ }
|
|
398
|
+
|
|
399
|
+ /* Allocate a mapping record */
|
|
400
|
+ map = zalloc ( sizeof ( *map ) );
|
|
401
|
+ if ( ! map )
|
|
402
|
+ goto err_alloc;
|
|
403
|
+ map->addr = addr;
|
|
404
|
+
|
|
405
|
+ /* Create map */
|
|
406
|
+ if ( ( efirc = nii->pci_io->Map ( nii->pci_io, op,
|
|
407
|
+ ( ( void * ) ( intptr_t ) addr ),
|
|
408
|
+ &count, phys, &map->mapping ) ) != 0){
|
|
409
|
+ rc = -EEFI ( efirc );
|
|
410
|
+ DBGC ( nii, "NII %s map operation failed: %s\n",
|
|
411
|
+ nii->dev.name, strerror ( rc ) );
|
|
412
|
+ goto err_map;
|
|
413
|
+ }
|
|
414
|
+
|
|
415
|
+ /* Add to list of mappings */
|
|
416
|
+ list_add ( &map->list, &nii->mappings );
|
|
417
|
+ DBGC2 ( nii, "NII %s mapped %#llx+%#x->%#llx\n",
|
|
418
|
+ nii->dev.name, ( ( unsigned long long ) addr ),
|
|
419
|
+ len, ( ( unsigned long long ) *phys ) );
|
|
420
|
+ return;
|
|
421
|
+
|
|
422
|
+ list_del ( &map->list );
|
|
423
|
+ err_map:
|
|
424
|
+ free ( map );
|
|
425
|
+ err_alloc:
|
|
426
|
+ err_dir:
|
|
427
|
+ return;
|
|
428
|
+}
|
|
429
|
+
|
|
430
|
+/**
|
|
431
|
+ * Unmap callback
|
|
432
|
+ *
|
|
433
|
+ * @v unique_id NII NIC
|
|
434
|
+ * @v addr Address of mapped memory
|
|
435
|
+ * @v len Length of mapped memory
|
|
436
|
+ * @v dir Direction of data flow
|
|
437
|
+ * @v mapped Device mapped address
|
|
438
|
+ */
|
|
439
|
+static EFIAPI VOID nii_unmap ( UINT64 unique_id, UINT64 addr, UINT32 len,
|
|
440
|
+ UINT32 dir __unused, UINT64 mapped ) {
|
|
441
|
+ struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id );
|
|
442
|
+ struct nii_mapping *map;
|
|
443
|
+
|
|
444
|
+ /* Locate mapping record */
|
|
445
|
+ list_for_each_entry ( map, &nii->mappings, list ) {
|
|
446
|
+ if ( map->addr == addr ) {
|
|
447
|
+ nii->pci_io->Unmap ( nii->pci_io, map->mapping );
|
|
448
|
+ list_del ( &map->list );
|
|
449
|
+ free ( map );
|
|
450
|
+ DBGC2 ( nii, "NII %s unmapped %#llx+%#x->%#llx\n",
|
|
451
|
+ nii->dev.name, ( ( unsigned long long ) addr ),
|
|
452
|
+ len, ( ( unsigned long long ) mapped ) );
|
|
453
|
+ return;
|
|
454
|
+ }
|
|
455
|
+ }
|
|
456
|
+
|
|
457
|
+ DBGC ( nii, "NII %s non-existent mapping %#llx+%#x->%#llx\n",
|
|
458
|
+ nii->dev.name, ( ( unsigned long long ) addr ),
|
|
459
|
+ len, ( ( unsigned long long ) mapped ) );
|
|
460
|
+}
|
|
461
|
+
|
|
462
|
+/**
|
|
463
|
+ * Sync callback
|
|
464
|
+ *
|
|
465
|
+ * @v unique_id NII NIC
|
|
466
|
+ * @v addr Address of mapped memory
|
|
467
|
+ * @v len Length of mapped memory
|
|
468
|
+ * @v dir Direction of data flow
|
|
469
|
+ * @v mapped Device mapped address
|
|
470
|
+ */
|
|
471
|
+static EFIAPI VOID nii_sync ( UINT64 unique_id __unused, UINT64 addr,
|
|
472
|
+ UINT32 len, UINT32 dir, UINT64 mapped ) {
|
|
473
|
+ const void *src;
|
|
474
|
+ void *dst;
|
|
475
|
+
|
|
476
|
+ /* Do nothing if this is an identity mapping */
|
|
477
|
+ if ( addr == mapped )
|
|
478
|
+ return;
|
|
479
|
+
|
|
480
|
+ /* Determine direction */
|
|
481
|
+ if ( dir == FROM_DEVICE ) {
|
|
482
|
+ src = ( ( void * ) ( intptr_t ) mapped );
|
|
483
|
+ dst = ( ( void * ) ( intptr_t ) addr );
|
|
484
|
+ } else {
|
|
485
|
+ src = ( ( void * ) ( intptr_t ) addr );
|
|
486
|
+ dst = ( ( void * ) ( intptr_t ) mapped );
|
|
487
|
+ }
|
|
488
|
+
|
|
489
|
+ /* Copy data */
|
|
490
|
+ memcpy ( dst, src, len );
|
|
491
|
+}
|
|
492
|
+
|
334
|
493
|
/**
|
335
|
494
|
* Delay callback
|
336
|
495
|
*
|
|
@@ -499,6 +658,9 @@ static int nii_start_undi ( struct nii_nic *nii ) {
|
499
|
658
|
cpb.Delay = ( ( intptr_t ) nii_delay );
|
500
|
659
|
cpb.Block = ( ( intptr_t ) nii_block );
|
501
|
660
|
cpb.Mem_IO = ( ( intptr_t ) nii_io );
|
|
661
|
+ cpb.Map_Mem = ( ( intptr_t ) nii_map );
|
|
662
|
+ cpb.UnMap_Mem = ( ( intptr_t ) nii_unmap );
|
|
663
|
+ cpb.Sync_Mem = ( ( intptr_t ) nii_sync );
|
502
|
664
|
cpb.Unique_ID = ( ( intptr_t ) nii );
|
503
|
665
|
|
504
|
666
|
/* Issue command */
|
|
@@ -1063,6 +1225,7 @@ int nii_start ( struct efi_device *efidev ) {
|
1063
|
1225
|
netdev_init ( netdev, &nii_operations );
|
1064
|
1226
|
nii = netdev->priv;
|
1065
|
1227
|
nii->efidev = efidev;
|
|
1228
|
+ INIT_LIST_HEAD ( &nii->mappings );
|
1066
|
1229
|
netdev->ll_broadcast = nii->broadcast;
|
1067
|
1230
|
efidev_set_drvdata ( efidev, netdev );
|
1068
|
1231
|
|