@@ -80,9 +80,9 @@ static const int multicast_filter_limit = 32;
#define RTL8169_TX_TIMEOUT (6*HZ)
#define RTL8169_PHY_TIMEOUT (10*HZ)
-#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
-#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
+#define RTL_EEPROM_SIG 0x8129
#define RTL_EEPROM_SIG_ADDR 0x0000
+#define RTL_EEPROM_MAC_ADDR 0x0007
/* write/read MMIO register */
#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
@@ -292,6 +292,11 @@ enum rtl_register_content {
/* Cfg9346Bits */
Cfg9346_Lock = 0x00,
Cfg9346_Unlock = 0xc0,
+ Cfg9346_Program = 0x88, /* Programming mode */
+ Cfg9346_EECS = 0x08, /* Chip select */
+ Cfg9346_EESK = 0x04, /* Serial data clock */
+ Cfg9346_EEDI = 0x02, /* Data input */
+ Cfg9346_EEDO = 0x01, /* Data output */
/* rx_mode_bits */
AcceptErr = 0x20,
@@ -304,6 +309,7 @@ enum rtl_register_content {
/* RxConfigBits */
RxCfgFIFOShift = 13,
RxCfgDMAShift = 8,
+ RxCfg9356SEL = 6, /* EEPROM type: 0 = 9346, 1 = 9356 */
/* TxConfigBits */
TxInterFrameGapShift = 24,
@@ -1962,6 +1968,88 @@ static const struct net_device_ops rtl8169_netdev_ops = {
};
+/* delay between EEPROM clock transitions - force out buffered PCI writes. */
+#define RTL_EEPROM_DELAY() (void)RTL_R8(Cfg9346)
+#define RTL_EEPROM_READ_CMD 6
+
+/* read 16bit word stored in EEPROM. EEPROM is addressed by words. */
+static u16 rtl_eeprom_read(void __iomem *ioaddr, int addr)
+{
+ int read_cmd, addr_len, i;
+ u16 result = 0;
+
+ /* check for EEPROM address size (in bits) */
+ addr_len = (RTL_R32(RxConfig) & (1 << RxCfg9356SEL)) ? 8 : 6;
+ read_cmd = addr | (RTL_EEPROM_READ_CMD << addr_len);
+
+ /* enter programming mode */
+ RTL_W8(Cfg9346, Cfg9346_Program & ~Cfg9346_EECS);
+ RTL_W8(Cfg9346, Cfg9346_Program);
+ RTL_EEPROM_DELAY();
+
+ /* shift out read command and requested address */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ int val = (read_cmd & (1 << i)) ? Cfg9346_EEDI : 0;
+ RTL_W8(Cfg9346, Cfg9346_Program | val);
+ RTL_EEPROM_DELAY();
+ RTL_W8(Cfg9346, Cfg9346_Program | val | Cfg9346_EESK);
+ RTL_EEPROM_DELAY();
+ }
+ RTL_W8(Cfg9346, Cfg9346_Program);
+ RTL_EEPROM_DELAY();
+
+ /* read back 16bit value */
+ for (i = 16; i > 0; i--) {
+ RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EESK);
+ RTL_EEPROM_DELAY();
+
+ result <<= 1;
+ result |= (RTL_R8 (Cfg9346) & Cfg9346_EEDO) ? 1 : 0;
+
+ RTL_W8(Cfg9346, Cfg9346_Program);
+ RTL_EEPROM_DELAY();
+ }
+
+ /* leave programming mode - lock configuration */
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+ RTL_EEPROM_DELAY();
+
+ return result;
+}
+
+static void rtl_init_mac_address(struct rtl8169_private *tp,
+ void __iomem *ioaddr)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ int i;
+ u16 x;
+ u8 mac[8];
+
+ /* read EEPROM signature */
+ x = rtl_eeprom_read(ioaddr, RTL_EEPROM_SIG_ADDR);
+ if (x != RTL_EEPROM_SIG) {
+ dev_info(&pdev->dev, "Missing EEPROM signature: %04x\n", x);
+ return;
+ }
+
+ /* read MAC address */
+ for (i = 0; i < 3; i++) {
+ x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + i);
+ mac[i*2] = x & 0xff;
+ mac[i*2+1] = x >> 8;
+ }
+
+ if (netif_msg_probe(tp)) {
+ DECLARE_MAC_BUF(buf);
+
+ dev_info(&pdev->dev, "MAC address found in EEPROM: %s\n",
+ print_mac(buf, mac));
+ }
+
+ if (is_valid_ether_addr(mac))
+ rtl_rar_set(tp, mac);
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -2141,6 +2229,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->mmio_addr = ioaddr;
+ rtl_init_mac_address(tp, ioaddr);
+
/* Get MAC address */
for (i = 0; i < MAC_ADDR_LEN; i++)
dev->dev_addr[i] = RTL_R8(MAC0 + i);