Browse Source

[realtek] Use ID word to detect EEPROM presence

Some onboard RTL8169 NICs seem to leave the EEPROM pins disconnected.
The existing is_valid_ether_addr() test will not necessarily catch
this, since it expects a missing EEPROM to show up as a MAC address of
00:00:00:00:00:00 or ff:ff:ff:ff:ff:ff.  When the EEPROM pins are
floating the MAC address may read as e.g. 00:00:00:00:0f:00, which
will not be detected as invalid.

Check the ID word in the first two bytes of the EEPROM (which should
have the value 0x8129 for all RTL8139 and RTL8169 chips), and use this
to determine whether or not an EEPROM is present.

Reported-by: Carl Karsten <carl@nextdayvideo.com>
Tested-by: Carl Karsten <carl@nextdayvideo.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
d90fc3156c
2 changed files with 42 additions and 16 deletions
  1. 36
    16
      src/drivers/net/realtek.c
  2. 6
    0
      src/drivers/net/realtek.h

+ 36
- 16
src/drivers/net/realtek.c View File

@@ -144,9 +144,12 @@ static struct bit_basher_operations realtek_basher_ops = {
144 144
  * Initialise EEPROM
145 145
  *
146 146
  * @v netdev		Network device
147
+ * @ret rc		Return status code
147 148
  */
148
-static void realtek_init_eeprom ( struct net_device *netdev ) {
149
+static int realtek_init_eeprom ( struct net_device *netdev ) {
149 150
 	struct realtek_nic *rtl = netdev->priv;
151
+	uint16_t id;
152
+	int rc;
150 153
 
151 154
 	/* Initialise SPI bit-bashing interface */
152 155
 	rtl->spibit.basher.op = &realtek_basher_ops;
@@ -163,6 +166,22 @@ static void realtek_init_eeprom ( struct net_device *netdev ) {
163 166
 	}
164 167
 	rtl->eeprom.bus = &rtl->spibit.bus;
165 168
 
169
+	/* Check for EEPROM presence.  Some onboard NICs will have no
170
+	 * EEPROM connected, with the BIOS being responsible for
171
+	 * programming the initial register values.
172
+	 */
173
+	if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_ID,
174
+			       &id, sizeof ( id ) ) ) != 0 ) {
175
+		DBGC ( rtl, "REALTEK %p could not read EEPROM ID: %s\n",
176
+		       rtl, strerror ( rc ) );
177
+		return rc;
178
+	}
179
+	if ( id != cpu_to_le16 ( RTL_EEPROM_ID_MAGIC ) ) {
180
+		DBGC ( rtl, "REALTEK %p EEPROM ID incorrect (%#04x); assuming "
181
+		       "no EEPROM\n", rtl, le16_to_cpu ( id ) );
182
+		return -ENODEV;
183
+	}
184
+
166 185
 	/* Initialise space for non-volatile options, if available
167 186
 	 *
168 187
 	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
@@ -176,6 +195,8 @@ static void realtek_init_eeprom ( struct net_device *netdev ) {
176 195
 		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD,
177 196
 			   RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt );
178 197
 	}
198
+
199
+	return 0;
179 200
 }
180 201
 
181 202
 /******************************************************************************
@@ -1045,23 +1066,22 @@ static int realtek_probe ( struct pci_device *pci ) {
1045 1066
 	realtek_detect ( rtl );
1046 1067
 
1047 1068
 	/* Initialise EEPROM */
1048
-	realtek_init_eeprom ( netdev );
1069
+	if ( ( rc = realtek_init_eeprom ( netdev ) ) == 0 ) {
1070
+
1071
+		/* Read MAC address from EEPROM */
1072
+		if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC,
1073
+				       netdev->hw_addr, ETH_ALEN ) ) != 0 ) {
1074
+			DBGC ( rtl, "REALTEK %p could not read MAC address: "
1075
+			       "%s\n", rtl, strerror ( rc ) );
1076
+			goto err_nvs_read;
1077
+		}
1049 1078
 
1050
-	/* Read MAC address from EEPROM */
1051
-	if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC,
1052
-			       netdev->hw_addr, ETH_ALEN ) ) != 0 ) {
1053
-		DBGC ( rtl, "REALTEK %p could not read MAC address: %s\n",
1054
-		       rtl, strerror ( rc ) );
1055
-		goto err_nvs_read;
1056
-	}
1079
+	} else {
1057 1080
 
1058
-	/* The EEPROM may not be present for onboard NICs.  Fall back
1059
-	 * to reading the current ID register value, which will
1060
-	 * hopefully have been programmed by the platform firmware.
1061
-	 */
1062
-	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
1063
-		DBGC ( rtl, "REALTEK %p seems to have no EEPROM (MAC %s)\n",
1064
-		       rtl, eth_ntoa ( netdev->hw_addr ) );
1081
+		/* EEPROM not present.  Fall back to reading the
1082
+		 * current ID register value, which will hopefully
1083
+		 * have been programmed by the platform firmware.
1084
+		 */
1065 1085
 		for ( i = 0 ; i < ETH_ALEN ; i++ )
1066 1086
 			netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i );
1067 1087
 	}

+ 6
- 0
src/drivers/net/realtek.h View File

@@ -166,6 +166,12 @@ enum realtek_legacy_status {
166 166
 #define RTL_9346CR_EEDI		0x02	/**< Data in */
167 167
 #define RTL_9346CR_EEDO		0x01	/**< Data out */
168 168
 
169
+/** Word offset of ID code word within EEPROM */
170
+#define RTL_EEPROM_ID ( 0x00 / 2 )
171
+
172
+/** EEPROM code word magic value */
173
+#define RTL_EEPROM_ID_MAGIC 0x8129
174
+
169 175
 /** Word offset of MAC address within EEPROM */
170 176
 #define RTL_EEPROM_MAC ( 0x0e / 2 )
171 177
 

Loading…
Cancel
Save