jme_mdio_read(struct net_device *netdev, int phy, int reg)
{
struct jme_adapter *jme = netdev_priv(netdev);
- int i, val;
+ int i, val, again = (reg == MII_BMSR)?1:0;
+read_again:
jwrite32(jme, JME_SMI, SMI_OP_REQ |
smi_phy_addr(phy) |
smi_reg_addr(reg));
return 0;
}
+ if(again--)
+ goto read_again;
+
return ((val & SMI_DATA_MASK) >> SMI_DATA_SHIFT);
}
jwrite32(jme, JME_SMBCSR, val);
mdelay(12);
- for (i = JME_SMB_TIMEOUT; i > 0; --i)
+ for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i)
{
mdelay(1);
if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0)
}
if(i == 0) {
- jeprintk(jme->dev->name, "eeprom reload timeout\n");
+ jeprintk("jme", "eeprom reload timeout\n");
return -EIO;
}
}
- else
- return -EIO;
return 0;
}
spin_lock(&jme->macaddr_lock);
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- val = addr->sa_data[3] << 24 |
- addr->sa_data[2] << 16 |
- addr->sa_data[1] << 8 |
- addr->sa_data[0];
+ val = (addr->sa_data[3] & 0xff) << 24 |
+ (addr->sa_data[2] & 0xff) << 16 |
+ (addr->sa_data[1] & 0xff) << 8 |
+ (addr->sa_data[0] & 0xff);
jwrite32(jme, JME_RXUMA_LO, val);
- val = addr->sa_data[5] << 8 |
- addr->sa_data[4];
+ val = (addr->sa_data[5] & 0xff) << 8 |
+ (addr->sa_data[4] & 0xff);
jwrite32(jme, JME_RXUMA_HI, val);
spin_unlock(&jme->macaddr_lock);
static int
jme_get_regs_len(struct net_device *netdev)
{
- return 0x400;
+ return JME_REG_LEN;
}
static void
for(i = 0 ; i < len ; i += 4)
p[i >> 2] = jread32(jme, reg + i);
+}
+static void
+mdio_memcpy(struct jme_adapter *jme, __u32 *p, int reg_nr)
+{
+ int i;
+ __u16 *p16 = (__u16*)p;
+
+ for(i = 0 ; i < reg_nr ; ++i)
+ p16[i] = jme_mdio_read(jme->dev, jme->mii_if.phy_id, i);
}
static void
struct jme_adapter *jme = netdev_priv(netdev);
__u32 *p32 = (__u32*)p;
- memset(p, 0, 0x400);
+ memset(p, 0xFF, JME_REG_LEN);
regs->version = 1;
mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN);
p32 += 0x100 >> 2;
mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN);
+ p32 += 0x100 >> 2;
+ mdio_memcpy(jme, p32, JME_PHY_REG_NR);
}
static int
return 0;
}
+static __u8
+jme_smb_read(struct jme_adapter *jme, unsigned int addr)
+{
+ __u32 val;
+ int to;
+
+ val = jread32(jme, JME_SMBCSR);
+ to = JME_SMB_BUSY_TIMEOUT;
+ while((val & SMBCSR_BUSY) && --to) {
+ msleep(1);
+ val = jread32(jme, JME_SMBCSR);
+ }
+ if(!to) {
+ jeprintk(jme->dev->name, "SMB Bus Busy.\n");
+ return 0xFF;
+ }
+
+ jwrite32(jme, JME_SMBINTF,
+ ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) |
+ SMBINTF_HWRWN_READ |
+ SMBINTF_HWCMD);
+
+ val = jread32(jme, JME_SMBINTF);
+ to = JME_SMB_BUSY_TIMEOUT;
+ while((val & SMBINTF_HWCMD) && --to) {
+ msleep(1);
+ val = jread32(jme, JME_SMBINTF);
+ }
+ if(!to) {
+ jeprintk(jme->dev->name, "SMB Bus Busy.\n");
+ return 0xFF;
+ }
+
+ return (val & SMBINTF_HWDATR) >> SMBINTF_HWDATR_SHIFT;
+}
+
+static void
+jme_smb_write(struct jme_adapter *jme, unsigned int addr, __u8 data)
+{
+ __u32 val;
+ int to;
+
+ val = jread32(jme, JME_SMBCSR);
+ to = JME_SMB_BUSY_TIMEOUT;
+ while((val & SMBCSR_BUSY) && --to) {
+ msleep(1);
+ val = jread32(jme, JME_SMBCSR);
+ }
+ if(!to) {
+ jeprintk(jme->dev->name, "SMB Bus Busy.\n");
+ return;
+ }
+
+ jwrite32(jme, JME_SMBINTF,
+ ((data << SMBINTF_HWDATW_SHIFT) & SMBINTF_HWDATW) |
+ ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) |
+ SMBINTF_HWRWN_WRITE |
+ SMBINTF_HWCMD);
+
+ val = jread32(jme, JME_SMBINTF);
+ to = JME_SMB_BUSY_TIMEOUT;
+ while((val & SMBINTF_HWCMD) && --to) {
+ msleep(1);
+ val = jread32(jme, JME_SMBINTF);
+ }
+ if(!to) {
+ jeprintk(jme->dev->name, "SMB Bus Busy.\n");
+ return;
+ }
+
+ mdelay(2);
+}
+
+static int
+jme_get_eeprom_len(struct net_device *netdev)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+ __u32 val;
+ val = jread32(jme, JME_SMBCSR);
+ return (val & SMBCSR_EEPROMD)?JME_SMB_LEN:0;
+}
+
+static int
+jme_get_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+ int i, offset = eeprom->offset, len = eeprom->len;
+
+ /*
+ * ethtool will check boundary for us
+ */
+ eeprom->magic = JME_EEPROM_MAGIC;
+ for(i = 0 ; i < len ; ++i)
+ data[i] = jme_smb_read(jme, i + offset);
+
+ return 0;
+}
+
+static int
+jme_set_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+ int i, offset = eeprom->offset, len = eeprom->len;
+
+ if (eeprom->magic != JME_EEPROM_MAGIC)
+ return -EINVAL;
+
+ /*
+ * ethtool will check boundary for us
+ */
+ for(i = 0 ; i < len ; ++i)
+ jme_smb_write(jme, i + offset, data[i]);
+
+ return 0;
+}
+
static const struct ethtool_ops jme_ethtool_ops = {
.get_drvinfo = jme_get_drvinfo,
.get_regs_len = jme_get_regs_len,
.set_tso = jme_set_tso,
.set_sg = ethtool_op_set_sg,
.nway_reset = jme_nway_reset,
+ .get_eeprom_len = jme_get_eeprom_len,
+ .get_eeprom = jme_get_eeprom,
+ .set_eeprom = jme_set_eeprom,
};
static int
#include <linux/version.h>
#define DRV_NAME "jme"
-#define DRV_VERSION "0.9b"
+#define DRV_VERSION "0.9c"
#define PFX DRV_NAME ": "
#ifdef DEBUG
};
#define WAIT_TASKLET_TIMEOUT 500 /* 500 ms */
#define TX_TIMEOUT (5*HZ)
+#define JME_REG_LEN 0x500
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
__always_inline static struct jme_adapter*
JME_PHY_CS = JME_PHY | 0x28, /* PHY Ctrl and Status Register */
JME_PHY_LINK = JME_PHY | 0x30, /* PHY Link Status Register */
JME_SMBCSR = JME_PHY | 0x40, /* SMB Control and Status */
+ JME_SMBINTF = JME_PHY | 0x44, /* SMB Interface */
JME_TMCSR = JME_MISC| 0x00, /* Timer Control/Status Register */
return (((x) << SMI_PHY_ADDR_SHIFT) & SMI_PHY_ADDR_MASK);
}
#define JME_PHY_TIMEOUT 1000 /* 1000 msec */
+#define JME_PHY_REG_NR 32
/*
* Global Host Control
SMBCSR_CNACK = 0x00020000,
SMBCSR_RELOAD = 0x00010000,
SMBCSR_EEPROMD = 0x00000020,
+ SMBCSR_INITDONE = 0x00000010,
+ SMBCSR_BUSY = 0x0000000F,
};
-#define JME_SMB_TIMEOUT 10 /* 10 msec */
+enum jme_smbintf_bit_mask {
+ SMBINTF_HWDATR = 0xFF000000,
+ SMBINTF_HWDATW = 0x00FF0000,
+ SMBINTF_HWADDR = 0x0000FF00,
+ SMBINTF_HWRWN = 0x00000020,
+ SMBINTF_HWCMD = 0x00000010,
+ SMBINTF_FASTM = 0x00000008,
+ SMBINTF_GPIOSCL = 0x00000004,
+ SMBINTF_GPIOSDA = 0x00000002,
+ SMBINTF_GPIOEN = 0x00000001,
+};
+enum jme_smbintf_vals {
+ SMBINTF_HWRWN_READ = 0x00000020,
+ SMBINTF_HWRWN_WRITE = 0x00000000,
+};
+enum jme_smbintf_shifts {
+ SMBINTF_HWDATR_SHIFT = 24,
+ SMBINTF_HWDATW_SHIFT = 16,
+ SMBINTF_HWADDR_SHIFT = 8,
+};
+#define JME_EEPROM_RELOAD_TIMEOUT 2000 /* 2000 msec */
+#define JME_SMB_BUSY_TIMEOUT 20 /* 20 msec */
+#define JME_SMB_LEN 256
+#define JME_EEPROM_MAGIC 0x250
/*
* Timer Control/Status Register