--- /usr/src/linux-2.6.16/drivers/net/8139too.c 2006-03-20 14:53:29.000000000 +0900 +++ ./8139too.c 2007-08-08 10:02:59.000000000 +0900 @@ -164,6 +164,9 @@ /* bitmapped message enable number */ static int debug = -1; +/* Serial part of MAC address */ +static int mac_addr = 0x00000000; + /* * Receive ring size * Warning: 64K ring has hardware issues and may lock up. @@ -611,11 +614,14 @@ module_param_array(media, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); module_param(debug, int, 0); +module_param(mac_addr, int, 0); MODULE_PARM_DESC (debug, "8139too bitmapped message enable number"); MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses"); MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"); MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)"); +MODULE_PARM_DESC (mac_addr, "8139too: Serial part of MAC address (exclude Vendor ID)"); +static int write_eeprom (void __iomem *ioaddr, int location, int addr_len, int value); static int read_eeprom (void __iomem *ioaddr, int location, int addr_len); static int rtl8139_open (struct net_device *dev); static int mdio_read (struct net_device *dev, int phy_id, int location); @@ -970,6 +976,18 @@ ioaddr = tp->mmio_addr; assert (ioaddr != NULL); + for(i = 0; i < 0x32; i+=1) + { + addr_len = read_eeprom (ioaddr, i, 6); + printk("%d: %02x %02x\n", i, addr_len & 0xff, (addr_len >> 8) & 0xff); + } + write_eeprom (ioaddr, 0, 6, 0); + for(i = 0; i < 0x32; i+=1) + { + addr_len = read_eeprom (ioaddr, i, 6); + printk("%d: %02x %02x\n", i, addr_len & 0xff, (addr_len >> 8) & 0xff); + } + addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = @@ -1093,7 +1111,11 @@ /* Put the chip into low-power mode. */ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - + + mdio_write(dev, tp->phys[0], 0, ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */ + ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + + return 0; err_out: @@ -1135,10 +1157,15 @@ /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5) -#define EE_READ_CMD (6) +#define EE_READ_CMD (6) #define EE_ERASE_CMD (7) -static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len) +#define EE_WENDI_CMD (4) +#define EE_EN_ADR (0x30) +#define EE_DI_ADR (0) + + +int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len) { int i; unsigned retval = 0; @@ -1176,6 +1203,131 @@ return retval; } +// Serial EEPROM (93c46) Writer. +// Added by H.Suzuki 2007/08/07 +static int __devinit write_eeprom (void __iomem *ioaddr, int location, int addr_len, int value) +{ + int i, j; + unsigned retval = 0; + int write_cmd = 0; + static int data[] = { + 0x8129, // Header. Always 0x8129 + // 0xffff, // Dummy. Insti + 0x10ec, 0x8139, // Reserved. (May be PCI Subsystem Vendor and Device ID + 0x10ec, // PCI Subsystem Vendor ID + 0x8139, // PCI Subsystem Device ID + 0x4020, // MAXLAT : MNGNT (see DataSheet.) + 0xe512, // CONFIG3 : MSRBMCR (see DataSheet.) + 0x4f00, 0x0149, 0x1100, // Ethernet ID (MAC) + 0x8d13, // CONFIG1 : CONFIG0 (see DataSheet.) + 0xf7c2, // PMC (Power Management Capabilities(see DataSheet.)) + 0x8801, // CONFIG4 : PMCSR (see DataSheet.) + 0x03b9, 0x60f4, // PHY1_PARM_U (see DataSheet.) + 0x071a, // CONFIG5 : PHY2_PARM_U (see DataSheet.) + 0xdfa3, 0x9836, // TW_PARM_U (see DataSheet.) + 0xdfa3, 0x9836, // TW_PARM_T (see DataSheet.) + 0x03b9, 0x60f4, // PHY1_PARM_T (see DataSheet.) + 0x1a1a, 0x1a1a, 0x0000, // PHY2_PARM_T : Reserved : Reserved : ... + 0x08cf // CheckSum ( Not Used ? ) + }; + if(debug < 0) + return retval; + + if(mac_addr) + { + data[8] |= (mac_addr >> 8) & 0x0000ff00; + data[9] = (mac_addr >> 8) & 0x000000ff; + data[9] |= (mac_addr & 0x000000ff) << 8; + } + + RTL_W8 (Cfg9346, EE_ENB & ~EE_CS); + RTL_W8 (Cfg9346, EE_ENB); + eeprom_delay (); + + /* Shift the write enable command bits out. */ + write_cmd = addr_len == 8 ? EE_EN_ADR << 2 : EE_EN_ADR | (EE_WENDI_CMD << addr_len); + for (i = 4 + addr_len; i >= 0; i--) { + int dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + printk("%1d", dataval ? 1 : 0); + RTL_W8 (Cfg9346, EE_ENB | dataval); + eeprom_delay (); + RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK); + eeprom_delay (); + } + RTL_W8 (Cfg9346, EE_ENB & ~EE_CS); + eeprom_delay (); + printk("\n"); + + /* Shift the write command bits out. */ + for( j = 0; j < 26; j++) + { + RTL_W8 (Cfg9346, EE_ENB); + eeprom_delay (); + write_cmd = j | (EE_WRITE_CMD << addr_len); + for (i = 4 + addr_len; i >= 0; i--) + { + int dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + printk("%1d", dataval ? 1 : 0); + RTL_W8 (Cfg9346, EE_ENB | dataval); + eeprom_delay (); + RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK); + eeprom_delay (); + } + RTL_W8 (Cfg9346, EE_ENB); + eeprom_delay (); + printk("\n"); + + for (i = 16; i > 0; i--) + { + int dataval = data[j] & (1 << (i - 1)) ? EE_WRITE_1 : EE_WRITE_0; + printk("%1d", dataval ? 1 : 0); + RTL_W8 (Cfg9346, EE_ENB | dataval); + eeprom_delay (); + RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK); + eeprom_delay (); + } + RTL_W8 (Cfg9346, EE_ENB); + eeprom_delay (); + printk("\n"); + + /* Terminate the EEPROM access. */ + RTL_W8 (Cfg9346, EE_ENB & ~EE_CS); + eeprom_delay (); + + // Wait for write complete. + RTL_W8 (Cfg9346, EE_ENB); + eeprom_delay (); + while( 1 ) + { + if(RTL_R8 (Cfg9346) & EE_DATA_READ) + break; + eeprom_delay (); + } + + RTL_W8 (Cfg9346, EE_ENB & ~EE_CS); + eeprom_delay (); + } + + RTL_W8 (Cfg9346, EE_ENB); + eeprom_delay (); + /* Shift the write disable command bits out. */ + write_cmd = EE_DI_ADR | (EE_WENDI_CMD << addr_len); + for (i = 4 + addr_len; i >= 0; i--) { + int dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + printk("%1d", dataval ? 1 : 0); + RTL_W8 (Cfg9346, EE_ENB | dataval); + eeprom_delay (); + RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK); + eeprom_delay (); + } + RTL_W8 (Cfg9346, EE_ENB); + printk("\n"); + RTL_W8 (Cfg9346, ~EE_CS); + + return retval; +} + /* MII serial management: mostly bogus for now. */ /* Read and write the MII management registers using software-generated serial MDIO protocol.