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);
}
wmb();
for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
udelay(20);
- val = jread32(jme, JME_SMI);
- if ((val & SMI_OP_REQ) == 0)
+ if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0)
break;
}
MII_ADVERTISE, ADVERTISE_ALL |
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- jme_mdio_write(jme->dev,
- jme->mii_if.phy_id,
- MII_CTRL1000,
- ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if(jme->pdev->device == JME_GE_DEVICE)
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000,
+ ADVERTISE_1000FULL | ADVERTISE_1000HALF);
val = jme_mdio_read(jme->dev,
jme->mii_if.phy_id,
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;
}
phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17);
bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR);
- if(bmsr & BMCR_ANCOMP)
+ if(bmsr & BMSR_ANCOMP)
phylink |= PHY_LINK_AUTONEG_COMPLETE;
return phylink;
dev_kfree_skb(txbi->skb);
txbi->skb = NULL;
}
- txbi->mapping = 0;
- txbi->len = 0;
- txbi->nr_desc = 0;
+ txbi->mapping = 0;
+ txbi->len = 0;
+ txbi->nr_desc = 0;
+ txbi->start_xmit = 0;
}
dma_free_coherent(&(jme->pdev->dev),
*/
jwrite32f(jme, JME_IENC, INTR_ENABLE);
- /*
- * Write 1 clear interrupt status
- */
- jwrite32f(jme, JME_IEVE, intrstat);
-
if(intrstat & (INTR_LINKCH | INTR_SWINTR)) {
+ /*
+ * Link change event is critical
+ * all other events are ignored
+ */
+ jwrite32(jme, JME_IEVE, intrstat);
tasklet_schedule(&jme->linkch_task);
goto out_reenable;
}
- if(intrstat & INTR_TMINTR)
+ if(intrstat & INTR_TMINTR) {
+ jwrite32(jme, JME_IEVE, INTR_TMINTR);
tasklet_schedule(&jme->pcc_task);
+ }
- if(intrstat & (INTR_PCCTXTO | INTR_PCCTX))
+ if(intrstat & (INTR_PCCTXTO | INTR_PCCTX)) {
+ jwrite32(jme, JME_IEVE, INTR_PCCTXTO | INTR_PCCTX | INTR_TX0);
tasklet_schedule(&jme->txclean_task);
+ }
+
+ if((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) {
+ jwrite32(jme, JME_IEVE, (intrstat & (INTR_PCCRX0TO |
+ INTR_PCCRX0 |
+ INTR_RX0EMP)) |
+ INTR_RX0);
+ }
if(jme->flags & JME_FLAG_POLL) {
if(intrstat & INTR_RX0EMP)
atomic_inc(&jme->rx_empty);
tasklet_schedule(&jme->rxempty_task);
}
-
- if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0))
+ else if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0))
tasklet_schedule(&jme->rxclean_task);
}
jwrite32(jme, JME_GHC, GHC_SPEED_100M);
}
+#define JME_WAIT_LINK_TIME 2000 /* 2000ms */
+static void
+jme_wait_link(struct jme_adapter *jme)
+{
+ __u32 phylink, to = JME_WAIT_LINK_TIME;
+
+ mdelay(1000);
+ phylink = jme_linkstat_from_phy(jme);
+ while(!(phylink & PHY_LINK_UP) && (to -= 10) > 0) {
+ mdelay(10);
+ phylink = jme_linkstat_from_phy(jme);
+ }
+}
+
static void
jme_phy_off(struct jme_adapter *jme)
{
txbi->skb = skb;
txbi->len = skb->len;
if(!(txbi->start_xmit = jiffies))
- txbi->start_xmit = 1;
+ txbi->start_xmit = (0UL-1);
return 0;
}
(jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
txbi->skb)) {
netif_stop_queue(jme->dev);
+ queue_dbg(jme->dev->name, "TX Queue Stopped @(%lu).\n", jiffies);
}
}
jme_map_tx_skb(jme, skb, idx);
jme_fill_first_tx_desc(jme, skb, idx);
- tx_dbg(jme->dev->name, "Xmit: %d+%d\n", idx, skb_shinfo(skb)->nr_frags + 2);
+ tx_dbg(jme->dev->name, "Xmit: %d+%d @(%lu)\n",
+ idx, skb_shinfo(skb)->nr_frags + 2, jiffies);
jwrite32(jme, JME_TXCS, jme->reg_txcs |
TXCS_SELECT_QUEUE0 |
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 the 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 the 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
(unsigned long) jme);
jme->dpi.cur = PCC_P1;
- jme->reg_ghc = GHC_DPX | GHC_SPEED_1000M;
+ if(pdev->device == JME_GE_DEVICE)
+ jme->reg_ghc = GHC_DPX | GHC_SPEED_1000M;
+ else
+ jme->reg_ghc = GHC_DPX | GHC_SPEED_100M;
jme->reg_rxcs = RXCS_DEFAULT;
jme->reg_rxmcs = RXMCS_DEFAULT;
jme->reg_txpfc = 0;
- jme->reg_pmcs = PMCS_LFEN | PMCS_LREN | PMCS_MFEN;
+ jme->reg_pmcs = PMCS_MFEN;
jme->flags = JME_FLAG_TXCSUM | JME_FLAG_TSO;
/*
else {
jme->mii_if.phy_id = 1;
}
- jme->mii_if.supports_gmii = 1;
+ if(pdev->device == JME_GE_DEVICE)
+ jme->mii_if.supports_gmii = true;
+ else
+ jme->mii_if.supports_gmii = false;
jme->mii_if.mdio_read = jme_mdio_read;
jme->mii_if.mdio_write = jme_mdio_write;
netif_device_detach(netdev);
netif_stop_queue(netdev);
jme_stop_irq(jme);
- jme_free_irq(jme);
+ //jme_free_irq(jme);
while(--timeout > 0 &&
(
jme_disable_shadow(jme);
if(netif_carrier_ok(netdev)) {
+ if(jme->flags & JME_FLAG_POLL)
+ jme_polling_mode(jme);
+
jme_stop_pcc_timer(jme);
jme_reset_mac_processor(jme);
jme_free_rx_resources(jme);
jme_free_tx_resources(jme);
netif_carrier_off(netdev);
jme->phylink = 0;
-
- if(jme->flags & JME_FLAG_POLL)
- jme_polling_mode(jme);
}
pci_save_state(pdev);
if(jme->reg_pmcs) {
jme_set_100m_half(jme);
+
+ if(jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
+ jme_wait_link(jme);
+
jwrite32(jme, JME_PMCS, jme->reg_pmcs);
+ pci_enable_wake(pdev, PCI_D1, true);
pci_enable_wake(pdev, PCI_D3hot, true);
pci_enable_wake(pdev, PCI_D3cold, true);
}
else {
jme_phy_off(jme);
+ pci_enable_wake(pdev, PCI_D1, false);
pci_enable_wake(pdev, PCI_D3hot, false);
pci_enable_wake(pdev, PCI_D3cold, false);
}
jme_reset_mac_processor(jme);
jme_enable_shadow(jme);
- jme_request_irq(jme);
+ //jme_request_irq(jme);
jme_start_irq(jme);
netif_device_attach(netdev);
}
static struct pci_device_id jme_pci_tbl[] = {
- { PCI_VDEVICE(JMICRON, 0x250) },
+ { PCI_VDEVICE(JMICRON, JME_GE_DEVICE) },
+ { PCI_VDEVICE(JMICRON, JME_FE_DEVICE) },
{ }
};