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

[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 роки тому
джерело
коміт
e8e9ca3613
1 змінених файлів з 163 додано та 0 видалено
  1. 163
    0
      src/drivers/net/efi/nii.c

+ 163
- 0
src/drivers/net/efi/nii.c Переглянути файл

25
 
25
 
26
 #include <string.h>
26
 #include <string.h>
27
 #include <strings.h>
27
 #include <strings.h>
28
+#include <stdlib.h>
28
 #include <unistd.h>
29
 #include <unistd.h>
29
 #include <errno.h>
30
 #include <errno.h>
30
 #include <ipxe/netdevice.h>
31
 #include <ipxe/netdevice.h>
137
  */
138
  */
138
 #define PCI_MAX_BAR 6
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
 /** An NII NIC */
151
 /** An NII NIC */
141
 struct nii_nic {
152
 struct nii_nic {
142
 	/** EFI device */
153
 	/** EFI device */
179
 	struct io_buffer *txbuf;
190
 	struct io_buffer *txbuf;
180
 	/** Current receive buffer */
191
 	/** Current receive buffer */
181
 	struct io_buffer *rxbuf;
192
 	struct io_buffer *rxbuf;
193
+
194
+	/** Mapping list */
195
+	struct list_head mappings;
182
 };
196
 };
183
 
197
 
184
 /** Maximum number of received packets per poll */
198
 /** Maximum number of received packets per poll */
280
  */
294
  */
281
 static void nii_pci_close ( struct nii_nic *nii ) {
295
 static void nii_pci_close ( struct nii_nic *nii ) {
282
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
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
 	bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid,
310
 	bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid,
285
 			    efi_image_handle, nii->efidev->device );
311
 			    efi_image_handle, nii->efidev->device );
286
 }
312
 }
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
  * Delay callback
494
  * Delay callback
336
  *
495
  *
499
 	cpb.Delay = ( ( intptr_t ) nii_delay );
658
 	cpb.Delay = ( ( intptr_t ) nii_delay );
500
 	cpb.Block = ( ( intptr_t ) nii_block );
659
 	cpb.Block = ( ( intptr_t ) nii_block );
501
 	cpb.Mem_IO = ( ( intptr_t ) nii_io );
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
 	cpb.Unique_ID = ( ( intptr_t ) nii );
664
 	cpb.Unique_ID = ( ( intptr_t ) nii );
503
 
665
 
504
 	/* Issue command */
666
 	/* Issue command */
1063
 	netdev_init ( netdev, &nii_operations );
1225
 	netdev_init ( netdev, &nii_operations );
1064
 	nii = netdev->priv;
1226
 	nii = netdev->priv;
1065
 	nii->efidev = efidev;
1227
 	nii->efidev = efidev;
1228
+	INIT_LIST_HEAD ( &nii->mappings );
1066
 	netdev->ll_broadcast = nii->broadcast;
1229
 	netdev->ll_broadcast = nii->broadcast;
1067
 	efidev_set_drvdata ( efidev, netdev );
1230
 	efidev_set_drvdata ( efidev, netdev );
1068
 
1231
 

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