Преглед на файлове

[efi] Work around bugs in Emulex NII driver

Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Fabrice Bacchella преди 8 години
родител
ревизия
c0b61bad99
променени са 1 файла, в които са добавени 71 реда и са изтрити 15 реда
  1. 71
    15
      src/drivers/net/efi/nii.c

+ 71
- 15
src/drivers/net/efi/nii.c Целия файл

@@ -575,9 +575,10 @@ static int nii_get_init_info ( struct nii_nic *nii,
575 575
  * Initialise UNDI
576 576
  *
577 577
  * @v nii		NII NIC
578
+ * @v flags		Flags
578 579
  * @ret rc		Return status code
579 580
  */
580
-static int nii_initialise ( struct nii_nic *nii ) {
581
+static int nii_initialise_flags ( struct nii_nic *nii, unsigned int flags ) {
581 582
 	PXE_CPB_INITIALIZE cpb;
582 583
 	PXE_DB_INITIALIZE db;
583 584
 	unsigned int op;
@@ -600,8 +601,7 @@ static int nii_initialise ( struct nii_nic *nii ) {
600 601
 	memset ( &db, 0, sizeof ( db ) );
601 602
 
602 603
 	/* Issue command */
603
-	op = NII_OP ( PXE_OPCODE_INITIALIZE,
604
-		      PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE );
604
+	op = NII_OP ( PXE_OPCODE_INITIALIZE, flags );
605 605
 	if ( ( stat = nii_issue_cpb_db ( nii, op, &cpb, sizeof ( cpb ),
606 606
 					 &db, sizeof ( db ) ) ) < 0 ) {
607 607
 		rc = -EIO_STAT ( stat );
@@ -618,6 +618,36 @@ static int nii_initialise ( struct nii_nic *nii ) {
618 618
 	return rc;
619 619
 }
620 620
 
621
+/**
622
+ * Initialise UNDI
623
+ *
624
+ * @v nii		NII NIC
625
+ * @ret rc		Return status code
626
+ */
627
+static int nii_initialise ( struct nii_nic *nii ) {
628
+	unsigned int flags;
629
+
630
+	/* Initialise UNDI */
631
+	flags = PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE;
632
+	return nii_initialise_flags ( nii, flags );
633
+}
634
+
635
+/**
636
+ * Initialise UNDI and detect cable
637
+ *
638
+ * @v nii		NII NIC
639
+ * @ret rc		Return status code
640
+ */
641
+static int nii_initialise_and_detect ( struct nii_nic *nii ) {
642
+	unsigned int flags;
643
+
644
+	/* Initialise UNDI and detect cable.  This is required to work
645
+	 * around bugs in some Emulex NII drivers.
646
+	 */
647
+	flags = PXE_OPFLAGS_INITIALIZE_DETECT_CABLE;
648
+	return nii_initialise_flags ( nii, flags );
649
+}
650
+
621 651
 /**
622 652
  * Shut down UNDI
623 653
  *
@@ -650,6 +680,7 @@ static void nii_shutdown ( struct nii_nic *nii ) {
650 680
 static int nii_get_station_address ( struct nii_nic *nii,
651 681
 				     struct net_device *netdev ) {
652 682
 	PXE_DB_STATION_ADDRESS db;
683
+	unsigned int op;
653 684
 	int stat;
654 685
 	int rc;
655 686
 
@@ -658,8 +689,9 @@ static int nii_get_station_address ( struct nii_nic *nii,
658 689
 		goto err_initialise;
659 690
 
660 691
 	/* Issue command */
661
-	if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_STATION_ADDRESS, &db,
662
-				     sizeof ( db ) ) ) < 0 ) {
692
+	op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
693
+		      PXE_OPFLAGS_STATION_ADDRESS_READ );
694
+	if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
663 695
 		rc = -EIO_STAT ( stat );
664 696
 		DBGC ( nii, "NII %s could not get station address: %s\n",
665 697
 		       nii->dev.name, strerror ( rc ) );
@@ -689,18 +721,25 @@ static int nii_get_station_address ( struct nii_nic *nii,
689 721
  */
690 722
 static int nii_set_station_address ( struct nii_nic *nii,
691 723
 				     struct net_device *netdev ) {
724
+	uint32_t implementation = nii->undi->Implementation;
692 725
 	PXE_CPB_STATION_ADDRESS cpb;
726
+	unsigned int op;
693 727
 	int stat;
694 728
 	int rc;
695 729
 
730
+	/* Fail if setting station address is unsupported */
731
+	if ( ! ( implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE ) )
732
+		return -ENOTSUP;
733
+
696 734
 	/* Construct parameter block */
697 735
 	memset ( &cpb, 0, sizeof ( cpb ) );
698 736
 	memcpy ( cpb.StationAddr, netdev->ll_addr,
699 737
 		 netdev->ll_protocol->ll_addr_len );
700 738
 
701 739
 	/* Issue command */
702
-	if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_STATION_ADDRESS,
703
-				      &cpb, sizeof ( cpb ) ) ) < 0 ) {
740
+	op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
741
+	              PXE_OPFLAGS_STATION_ADDRESS_WRITE );
742
+	if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
704 743
 		rc = -EIO_STAT ( stat );
705 744
 		DBGC ( nii, "NII %s could not set station address: %s\n",
706 745
 		       nii->dev.name, strerror ( rc ) );
@@ -717,6 +756,7 @@ static int nii_set_station_address ( struct nii_nic *nii,
717 756
  * @ret rc		Return status code
718 757
  */
719 758
 static int nii_set_rx_filters ( struct nii_nic *nii ) {
759
+	uint32_t implementation = nii->undi->Implementation;
720 760
 	unsigned int flags;
721 761
 	unsigned int op;
722 762
 	int stat;
@@ -724,10 +764,13 @@ static int nii_set_rx_filters ( struct nii_nic *nii ) {
724 764
 
725 765
 	/* Construct receive filter set */
726 766
 	flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
727
-		  PXE_OPFLAGS_RECEIVE_FILTER_UNICAST |
728
-		  PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST |
729
-		  PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
730
-		  PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST );
767
+		  PXE_OPFLAGS_RECEIVE_FILTER_UNICAST );
768
+	if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED )
769
+		flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
770
+	if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED )
771
+		flags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
772
+	if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED )
773
+		flags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
731 774
 
732 775
 	/* Issue command */
733 776
 	op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
@@ -752,6 +795,7 @@ static int nii_transmit ( struct net_device *netdev,
752 795
 			  struct io_buffer *iobuf ) {
753 796
 	struct nii_nic *nii = netdev->priv;
754 797
 	PXE_CPB_TRANSMIT cpb;
798
+	unsigned int op;
755 799
 	int stat;
756 800
 	int rc;
757 801
 
@@ -768,8 +812,10 @@ static int nii_transmit ( struct net_device *netdev,
768 812
 	cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len;
769 813
 
770 814
 	/* Transmit packet */
771
-	if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_TRANSMIT, &cpb,
772
-				      sizeof ( cpb ) ) ) < 0 ) {
815
+	op = NII_OP ( PXE_OPCODE_TRANSMIT,
816
+		      ( PXE_OPFLAGS_TRANSMIT_WHOLE |
817
+			PXE_OPFLAGS_TRANSMIT_DONT_BLOCK ) );
818
+	if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
773 819
 		rc = -EIO_STAT ( stat );
774 820
 		DBGC ( nii, "NII %s could not transmit: %s\n",
775 821
 		       nii->dev.name, strerror ( rc ) );
@@ -924,8 +970,18 @@ static int nii_open ( struct net_device *netdev ) {
924 970
 	struct nii_nic *nii = netdev->priv;
925 971
 	int rc;
926 972
 
927
-	/* Initialise NIC */
928
-	if ( ( rc = nii_initialise ( nii ) ) != 0 )
973
+	/* Initialise NIC
974
+	 *
975
+	 * Some Emulex NII drivers have a bug which prevents packets
976
+	 * from being sent or received unless we specifically ask it
977
+	 * to detect cable presence during initialisation.  Work
978
+	 * around these buggy drivers by requesting cable detection at
979
+	 * this point, even though we don't care about link state here
980
+	 * (and would prefer to have the NIC initialise even if no
981
+	 * cable is present, to match the behaviour of all other iPXE
982
+	 * drivers).
983
+	 */
984
+	if ( ( rc = nii_initialise_and_detect ( nii ) ) != 0 )
929 985
 		goto err_initialise;
930 986
 
931 987
 	/* Attempt to set station address */

Loading…
Отказ
Запис