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
  * Initialise EEPROM
144
  * Initialise EEPROM
145
  *
145
  *
146
  * @v netdev		Network device
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
 	struct realtek_nic *rtl = netdev->priv;
150
 	struct realtek_nic *rtl = netdev->priv;
151
+	uint16_t id;
152
+	int rc;
150
 
153
 
151
 	/* Initialise SPI bit-bashing interface */
154
 	/* Initialise SPI bit-bashing interface */
152
 	rtl->spibit.basher.op = &realtek_basher_ops;
155
 	rtl->spibit.basher.op = &realtek_basher_ops;
163
 	}
166
 	}
164
 	rtl->eeprom.bus = &rtl->spibit.bus;
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
 	/* Initialise space for non-volatile options, if available
185
 	/* Initialise space for non-volatile options, if available
167
 	 *
186
 	 *
168
 	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
187
 	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
176
 		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD,
195
 		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD,
177
 			   RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt );
196
 			   RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt );
178
 	}
197
 	}
198
+
199
+	return 0;
179
 }
200
 }
180
 
201
 
181
 /******************************************************************************
202
 /******************************************************************************
1045
 	realtek_detect ( rtl );
1066
 	realtek_detect ( rtl );
1046
 
1067
 
1047
 	/* Initialise EEPROM */
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
 		for ( i = 0 ; i < ETH_ALEN ; i++ )
1085
 		for ( i = 0 ; i < ETH_ALEN ; i++ )
1066
 			netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i );
1086
 			netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i );
1067
 	}
1087
 	}

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

166
 #define RTL_9346CR_EEDI		0x02	/**< Data in */
166
 #define RTL_9346CR_EEDI		0x02	/**< Data in */
167
 #define RTL_9346CR_EEDO		0x01	/**< Data out */
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
 /** Word offset of MAC address within EEPROM */
175
 /** Word offset of MAC address within EEPROM */
170
 #define RTL_EEPROM_MAC ( 0x0e / 2 )
176
 #define RTL_EEPROM_MAC ( 0x0e / 2 )
171
 
177
 

Loading…
Cancel
Save