瀏覽代碼

[myri10ge] Add NonVolatile Option (nvo) support

Add NonVolatile Option (nvo) and NonVolatile Storage (nvs) support to
the myri10ge driver using the EEPROM read/write mechanism provided by
the NIC's Vendor Specific PCI capability.

The myri10ge NIC is capabile of storing 64KB or more of nonvolatile
options, but this patch advertises only 512 bytes of nvo storage
because iPXE malloc's a buffer matching the total size we advertise.
512 is plenty without wasting malloc'd memory.  (The 2 other drivers
currently supporting nvo advertise 256 bytes or less.)

Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Glenn Brown 14 年之前
父節點
當前提交
66df967cb4
共有 1 個檔案被更改,包括 314 行新增11 行删除
  1. 314
    11
      src/drivers/net/myri10ge.c

+ 314
- 11
src/drivers/net/myri10ge.c 查看文件

@@ -55,6 +55,12 @@ FILE_LICENCE ( GPL2_ONLY );
55 55
  * myri10ge_net_poll() polls for these receive notifications, posts
56 56
  * replacement receive buffers to the NIC, and passes received frames
57 57
  * to netdev_rx().
58
+ *
59
+ * NonVolatile Storage
60
+ *
61
+ * This driver supports NonVolatile Storage (nvs) in the NIC EEPROM.
62
+ * If the last EEPROM block is not otherwise filled, we tell
63
+ * iPXE it may store NonVolatile Options (nvo) there.
58 64
  */
59 65
 
60 66
 /*
@@ -75,6 +81,8 @@ FILE_LICENCE ( GPL2_ONLY );
75 81
 #include <ipxe/iobuf.h>
76 82
 #include <ipxe/malloc.h>
77 83
 #include <ipxe/netdevice.h>
84
+#include <ipxe/nvo.h>
85
+#include <ipxe/nvs.h>
78 86
 #include <ipxe/pci.h>
79 87
 #include <ipxe/timer.h>
80 88
 
@@ -169,6 +177,18 @@ struct myri10ge_private
169 177
 	   BEWARE: the value must be written 32 bits at a time. */
170 178
 
171 179
 	mcp_cmd_t	*command;
180
+
181
+	/*
182
+	 * Nonvolatile Storage for configuration options.
183
+	 */
184
+
185
+	struct nvs_device	nvs;
186
+	struct nvo_fragment	nvo_fragment[2];
187
+	struct nvo_block	nvo;
188
+
189
+	/* Cached PCI capability locations. */
190
+
191
+	uint8			pci_cap_vs;
172 192
 };
173 193
 
174 194
 /****************************************************************
@@ -198,6 +218,28 @@ static inline struct myri10ge_private *myri10ge_priv ( struct net_device *nd )
198 218
 	return ( struct myri10ge_private * ) ( nd + 1 );
199 219
 }
200 220
 
221
+/*
222
+ * Convert a Myri10ge driver private data pointer to a netdev pointer.
223
+ *
224
+ * @v p		Myri10ge device private data.
225
+ * @ret r	The corresponding network device.
226
+ */
227
+static inline struct net_device *myri10ge_netdev ( struct myri10ge_private *p )
228
+{
229
+	return ( ( struct net_device * ) p ) - 1;
230
+}
231
+
232
+/*
233
+ * Convert a network device pointer to a PCI device pointer.
234
+ *
235
+ * @v netdev	A Network Device.
236
+ * @ret r	The corresponding PCI device.
237
+ */
238
+static inline struct pci_device *myri10ge_pcidev ( struct net_device *netdev )
239
+{
240
+	return container_of (netdev->dev, struct pci_device, dev);
241
+}
242
+
201 243
 /*
202 244
  * Pass a receive buffer to the NIC to be filled.
203 245
  *
@@ -381,12 +423,16 @@ static void myri10ge_interrupt_handler ( struct net_device *netdev )
381 423
 /* Constants for reading the STRING_SPECS via the Myricom
382 424
    Vendor Specific PCI configuration space capability. */
383 425
 
426
+#define VS_EEPROM_READ_ADDR ( vs + 0x04 )
427
+#define VS_EEPROM_READ_DATA ( vs + 0x08 )
428
+#define VS_EEPROM_WRITE     ( vs + 0x0C )
384 429
 #define VS_ADDR ( vs + 0x18 )
385 430
 #define VS_DATA ( vs + 0x14 )
386 431
 #define VS_MODE ( vs + 0x10 )
387 432
 #define 	VS_MODE_READ32 0x3
388 433
 #define 	VS_MODE_LOCATE 0x8
389 434
 #define 		VS_LOCATE_STRING_SPECS 0x3
435
+#define		VS_MODE_EEPROM_STREAM_WRITE 0xB
390 436
 
391 437
 /*
392 438
  * Read MAC address from its 'string specs' via the vendor-specific
@@ -394,28 +440,21 @@ static void myri10ge_interrupt_handler ( struct net_device *netdev )
394 440
  * before it is mapped.)
395 441
  *
396 442
  * @v pci		The device.
443
+ * @v vs		Offset of the PCI Vendor-Specific Capability.
397 444
  * @v mac		Buffer to store the MAC address.
398 445
  * @ret rc		Returns 0 on success, else an error code.
399 446
  */
400 447
 static int mac_address_from_string_specs ( struct pci_device *pci,
401
-						   uint8 mac[ETH_ALEN] )
448
+					   unsigned int vs,
449
+					   uint8 mac[ETH_ALEN] )
402 450
 {
403 451
 	char string_specs[256];
404 452
 	char *ptr, *limit;
405 453
 	char *to = string_specs;
406 454
 	uint32 addr;
407 455
 	uint32 len;
408
-	unsigned int vs;
409 456
 	int mac_set = 0;
410 457
 
411
-	/* Find the "vendor specific" capability. */
412
-
413
-	vs = pci_find_capability ( pci, 9 );
414
-	if ( vs == 0 ) {
415
-		DBG ( "no VS\n" );
416
-		return -ENOTSUP;
417
-	}
418
-
419 458
 	/* Locate the String specs in LANai SRAM. */
420 459
 
421 460
 	pci_write_config_byte ( pci, VS_MODE, VS_MODE_LOCATE );
@@ -427,6 +466,7 @@ static int mac_address_from_string_specs ( struct pci_device *pci,
427 466
 	/* Copy in the string specs.  Use 32-bit reads for performance. */
428 467
 
429 468
 	if ( len > sizeof ( string_specs ) || ( len & 3 ) ) {
469
+		pci_write_config_byte ( pci, VS_MODE, 0 );
430 470
 		DBG ( "SS too big\n" );
431 471
 		return -ENOTSUP;
432 472
 	}
@@ -483,6 +523,247 @@ static int mac_address_from_string_specs ( struct pci_device *pci,
483 523
 	return 0;
484 524
 }
485 525
 
526
+/****************************************************************
527
+ * NonVolatile Storage support
528
+ ****************************************************************/
529
+
530
+/*
531
+ * Fill a buffer with data read from nonvolatile storage.
532
+ *
533
+ * @v nvs	The NonVolatile Storage device to be read.
534
+ * @v addr      The first NonVolatile Storage address to be read.
535
+ * @v _buf	Pointer to the data buffer to be filled.
536
+ * @v len	The number of bytes to copy.
537
+ * @ret rc	0 on success, else nonzero.
538
+ */
539
+static int myri10ge_nvs_read ( struct nvs_device *nvs,
540
+			       unsigned int addr,
541
+			       void *_buf,
542
+			       size_t len )
543
+{
544
+	struct myri10ge_private *priv =
545
+		container_of (nvs, struct myri10ge_private, nvs);
546
+	struct pci_device *pci = myri10ge_pcidev ( myri10ge_netdev ( priv ) );
547
+	unsigned int vs = priv->pci_cap_vs;
548
+	unsigned char *buf = (unsigned char *) _buf;
549
+	unsigned int data;
550
+	unsigned int i, j;
551
+
552
+	DBGP ( "myri10ge_nvs_read\n" );
553
+
554
+	/* Issue the first read address. */
555
+
556
+	pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 3, addr>>16 );
557
+	pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 2, addr>>8 );
558
+	pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
559
+	addr++;
560
+
561
+	/* Issue all the reads, and harvest the results every 4th issue. */
562
+
563
+	for ( i=0; i<len; ++i,addr++ ) {
564
+
565
+		/* Issue the next read address, updating only the
566
+		   bytes that need updating.  We always update the
567
+		   LSB, which triggers the read. */
568
+
569
+		if ( ( addr & 0xff ) == 0 ) {
570
+			if ( ( addr & 0xffff ) == 0 ) {
571
+				pci_write_config_byte ( pci,
572
+							VS_EEPROM_READ_ADDR + 3,
573
+							addr >> 16 );
574
+			}
575
+			pci_write_config_byte ( pci,
576
+					        VS_EEPROM_READ_ADDR + 2,
577
+						addr >> 8 );
578
+		}
579
+		pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
580
+
581
+		/* If 4 data bytes are available, read them with a single read. */
582
+
583
+		if ( ( i & 3 ) == 3 ) {
584
+			pci_read_config_dword ( pci,
585
+						VS_EEPROM_READ_DATA,
586
+						&data );
587
+			for ( j=0; j<4; j++ ) {
588
+				buf[i-j] = data;
589
+				data >>= 8;
590
+			}
591
+		}
592
+	}
593
+
594
+	/* Harvest any remaining results. */
595
+
596
+	if ( ( i & 3 ) != 0 ) {
597
+		pci_read_config_dword ( pci, VS_EEPROM_READ_DATA, &data );
598
+		for ( j=1; j<=(i&3); j++ ) {
599
+			buf[i-j] = data;
600
+			data >>= 8;
601
+		}
602
+	}
603
+
604
+	DBGP_HDA ( addr - len, _buf, len );
605
+	return 0;
606
+}
607
+
608
+/*
609
+ * Write a buffer into nonvolatile storage.
610
+ *
611
+ * @v nvs	The NonVolatile Storage device to be written.
612
+ * @v address   The NonVolatile Storage address to be written.
613
+ * @v _buf	Pointer to the data to be written.
614
+ * @v len	Length of the buffer to be written.
615
+ * @ret rc	0 on success, else nonzero.
616
+ */
617
+static int myri10ge_nvs_write ( struct nvs_device *nvs,
618
+				unsigned int addr,
619
+				const void *_buf,
620
+				size_t len )
621
+{
622
+	struct myri10ge_private *priv =
623
+		container_of (nvs, struct myri10ge_private, nvs);
624
+	struct pci_device *pci = myri10ge_pcidev ( myri10ge_netdev ( priv ) );
625
+	unsigned int vs = priv->pci_cap_vs;
626
+	const unsigned char *buf = (const unsigned char *)_buf;
627
+	unsigned int i;
628
+	uint8 verify;
629
+
630
+	DBGP ( "nvs_write " );
631
+	DBGP_HDA ( addr, _buf, len );
632
+
633
+	/* Start erase of the NonVolatile Options block. */
634
+
635
+	DBGP ( "erasing " );
636
+	pci_write_config_dword ( pci, VS_EEPROM_WRITE, ( addr << 8 ) | 0xff );
637
+
638
+	/* Wait for erase to complete. */
639
+
640
+	DBGP ( "waiting " );
641
+	pci_read_config_byte ( pci, VS_EEPROM_READ_DATA, &verify );
642
+	while ( verify != 0xff ) {
643
+		pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
644
+		pci_read_config_byte ( pci, VS_EEPROM_READ_DATA, &verify );
645
+	}
646
+
647
+	/* Write the data one byte at a time. */
648
+
649
+	DBGP ( "writing " );
650
+	pci_write_config_byte ( pci, VS_MODE, VS_MODE_EEPROM_STREAM_WRITE );
651
+	pci_write_config_dword ( pci, VS_ADDR, addr );
652
+	for (i=0; i<len; i++, addr++)
653
+		pci_write_config_byte ( pci, VS_DATA, buf[i] );
654
+	pci_write_config_dword ( pci, VS_ADDR, 0xffffffff );
655
+	pci_write_config_byte ( pci, VS_MODE, 0 );
656
+
657
+	DBGP ( "done\n" );
658
+	return 0;
659
+}
660
+
661
+/*
662
+ * Initialize NonVolatile storage support for a device.
663
+ *
664
+ * @v priv	Device private data for the device.
665
+ * @ret rc	0 on success, else an error code.
666
+ */
667
+
668
+static int myri10ge_nv_init ( struct myri10ge_private *priv )
669
+{
670
+	int rc;
671
+	struct myri10ge_eeprom_header
672
+	{
673
+		uint8 __jump[8];
674
+		uint32 eeprom_len;
675
+		uint32 eeprom_segment_len;
676
+		uint32 mcp1_offset;
677
+		uint32 mcp2_offset;
678
+		uint32 version;
679
+	} hdr;
680
+	uint32 mcp2_len;
681
+	unsigned int nvo_fragment_pos;
682
+
683
+	DBGP ( "myri10ge_nv_init\n" );
684
+
685
+	/* Read the EEPROM header, and byteswap the fields we will use.
686
+	   This is safe even though priv->nvs is not yet initialized. */
687
+
688
+	rc = myri10ge_nvs_read ( &priv->nvs, 0, &hdr, sizeof ( hdr ) );
689
+	if ( rc ) {
690
+		DBG ( "EEPROM header unreadable\n" );
691
+		return rc;
692
+	}
693
+	hdr.eeprom_len	       = ntohl ( hdr.eeprom_len );
694
+	hdr.eeprom_segment_len = ntohl ( hdr.eeprom_segment_len );
695
+	hdr.mcp2_offset	       = ntohl ( hdr.mcp2_offset );
696
+	hdr.version	       = ntohl ( hdr.version );
697
+	DBG2 ( "eelen:%xh seglen:%xh mcp2@%xh ver%d\n", hdr.eeprom_len,
698
+	       hdr.eeprom_segment_len, hdr.mcp2_offset, hdr.version );
699
+
700
+	/* If the firmware does not support EEPROM writes, simply return. */
701
+
702
+	if ( hdr.version < 1 ) {
703
+		DBG ( "No EEPROM write support\n" );
704
+		return 0;
705
+	}
706
+
707
+	/* Read the length of MCP2. */
708
+
709
+	rc = myri10ge_nvs_read ( &priv->nvs, hdr.mcp2_offset, &mcp2_len, 4 );
710
+	mcp2_len = ntohl ( mcp2_len );
711
+	DBG2 ( "mcp2len:%xh\n", mcp2_len );
712
+
713
+	/* Determine the position of the NonVolatile Options fragment and
714
+	   simply return if it overlaps other data. */
715
+
716
+	nvo_fragment_pos = hdr.eeprom_len -  hdr.eeprom_segment_len;
717
+	if ( hdr.mcp2_offset + mcp2_len > nvo_fragment_pos ) {
718
+		DBG ( "EEPROM full\n" );
719
+		return 0;
720
+	}
721
+
722
+	/* Initilize NonVolatile Storage state. */
723
+
724
+	priv->nvs.word_len_log2 = 0;
725
+	priv->nvs.size		= hdr.eeprom_len;
726
+	priv->nvs.block_size	= hdr.eeprom_segment_len;
727
+	priv->nvs.read		= myri10ge_nvs_read;
728
+	priv->nvs.write		= myri10ge_nvs_write;
729
+
730
+	/* Build the NonVolatile storage fragment list.  We would like
731
+	   to use the whole last EEPROM block for this, but we must
732
+	   reduce the block size lest malloc fail in
733
+	   src/core/nvo.o. */
734
+
735
+	priv->nvo_fragment[0].address = nvo_fragment_pos;
736
+	priv->nvo_fragment[0].len     = 0x200;
737
+
738
+	/* Register the NonVolatile Options storage. */
739
+
740
+	nvo_init ( &priv->nvo,
741
+		   &priv->nvs,
742
+		   priv->nvo_fragment,
743
+		   & myri10ge_netdev (priv) -> refcnt );
744
+	rc = register_nvo ( &priv->nvo,
745
+			    netdev_settings ( myri10ge_netdev ( priv ) ) );
746
+	if ( rc ) {
747
+		DBG ("register_nvo failed");
748
+		priv->nvo_fragment[0].len = 0;
749
+		return rc;
750
+	}
751
+
752
+	DBG2 ( "NVO supported\n" );
753
+	return 0;
754
+}
755
+
756
+void
757
+myri10ge_nv_fini ( struct myri10ge_private *priv )
758
+{
759
+	/* Simply return if nonvolatile access is not supported. */
760
+
761
+	if ( 0 == priv->nvo_fragment[0].len )
762
+		return;
763
+
764
+	unregister_nvo ( &priv->nvo );
765
+}
766
+
486 767
 /****************************************************************
487 768
  * iPXE PCI Device Driver API functions
488 769
  ****************************************************************/
@@ -532,9 +813,20 @@ static int myri10ge_pci_probe ( struct pci_device *pci,
532 813
 
533 814
 	myri10ge_net_irq ( netdev, 0 );
534 815
 
816
+	/* Find the PCI Vendor-Specific capability. */
817
+
818
+	priv->pci_cap_vs = pci_find_capability ( pci , PCI_CAP_ID_VNDR );
819
+	if ( 0 == priv->pci_cap_vs ) {
820
+		rc = -ENOTSUP;
821
+		dbg = "no_vs";
822
+		goto abort_with_netdev_init;
823
+	}
824
+
535 825
 	/* Read the NIC HW address. */
536 826
 
537
-	rc = mac_address_from_string_specs ( pci, netdev->hw_addr );
827
+	rc = mac_address_from_string_specs ( pci,
828
+					     priv->pci_cap_vs,
829
+					     netdev->hw_addr );
538 830
 	if ( rc ) {
539 831
 		dbg = "mac_from_ss";
540 832
 		goto abort_with_netdev_init;
@@ -554,10 +846,20 @@ static int myri10ge_pci_probe ( struct pci_device *pci,
554 846
 		goto abort_with_netdev_init;
555 847
 	}
556 848
 
849
+	/* Initialize NonVolatile Storage support. */
850
+
851
+	rc = myri10ge_nv_init ( priv );
852
+	if ( rc ) {
853
+		dbg = "myri10ge_nv_init";
854
+		goto abort_with_registered_netdev;
855
+	}
856
+
557 857
 	DBGP ( "done\n" );
558 858
 
559 859
 	return 0;
560 860
 
861
+abort_with_registered_netdev:
862
+	unregister_netdev ( netdev );
561 863
 abort_with_netdev_init:
562 864
 	netdev_nullify ( netdev );
563 865
 	netdev_put ( netdev );
@@ -580,6 +882,7 @@ static void myri10ge_pci_remove ( struct pci_device *pci )
580 882
 	DBGP ( "myri10ge_pci_remove\n" );
581 883
 	netdev = pci_get_drvdata ( pci );
582 884
 
885
+	myri10ge_nv_fini ( myri10ge_priv ( netdev ) );
583 886
 	unregister_netdev ( netdev );
584 887
 	netdev_nullify ( netdev );
585 888
 	netdev_put ( netdev );

Loading…
取消
儲存