Browse Source

[efi] Provide Map_Mem() and associated UNDI callbacks

Some drivers are known to call the optional Map_Mem() callback without
first checking that the callback exists.  Provide a usable basic
implementation of Map_Mem() along with the other callbacks that become
mandatory if Map_Mem() is provided.

Note that in theory the PCI I/O protocol is allowed to require
multiple calls to Map(), with each call handling only a subset of the
overall mapped range.  However, the reference implementation in EDK2
assumes that a single Map() will always suffice, so we can probably
make the same simplifying assumption here.

Tested with the Intel E3522X2.EFI driver (which, incidentally, fails
to cleanly remove one of its mappings).

Originally-implemented-by: Maor Dickman <maord@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 6 years ago
parent
commit
e8e9ca3613
1 changed files with 163 additions and 0 deletions
  1. 163
    0
      src/drivers/net/efi/nii.c

+ 163
- 0
src/drivers/net/efi/nii.c View File

@@ -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
 

Loading…
Cancel
Save