*
* Copyright 2008 JMicron Technology Corporation
* http://www.jmicron.com/
+ * Copyright (c) 2009 - 2010 Guo-Fu Tseng <cooldavid@cooldavid.org>
*
* Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
*
static void
jme_setup_wakeup_frame(struct jme_adapter *jme,
- u32 *mask, u32 crc, int fnr)
+ const u32 *mask, u32 crc, int fnr)
{
int i;
static inline void
jme_reset_mac_processor(struct jme_adapter *jme)
{
- u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
+ static const u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
u32 crc = 0xCDCDCDCD;
u32 gpreg0;
int i;
}
static inline void
-jme_set_phyfifoa(struct jme_adapter *jme)
+jme_set_phyfifo_5level(struct jme_adapter *jme)
{
jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004);
}
static inline void
-jme_set_phyfifob(struct jme_adapter *jme)
+jme_set_phyfifo_8level(struct jme_adapter *jme)
{
jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0000);
}
if (phylink & PHY_LINK_DUPLEX) {
jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT);
+ jwrite32(jme, JME_TXTRHD, TXTRHD_FULLDUPLEX);
ghc |= GHC_DPX;
} else {
jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT |
TXMCS_BACKOFF |
TXMCS_CARRIERSENSE |
TXMCS_COLLISION);
- jwrite32(jme, JME_TXTRHD, TXTRHD_TXPEN |
- ((0x2000 << TXTRHD_TXP_SHIFT) & TXTRHD_TXP) |
- TXTRHD_TXREN |
- ((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL));
+ jwrite32(jme, JME_TXTRHD, TXTRHD_HALFDUPLEX);
}
gpreg1 = GPREG1_DEFAULT;
gpreg1 |= GPREG1_HALFMODEPATCH;
switch (phylink & PHY_LINK_SPEED_MASK) {
case PHY_LINK_SPEED_10M:
- jme_set_phyfifoa(jme);
+ jme_set_phyfifo_8level(jme);
gpreg1 |= GPREG1_RSSPATCH;
break;
case PHY_LINK_SPEED_100M:
- jme_set_phyfifob(jme);
+ jme_set_phyfifo_5level(jme);
gpreg1 |= GPREG1_RSSPATCH;
break;
case PHY_LINK_SPEED_1000M:
- jme_set_phyfifoa(jme);
+ jme_set_phyfifo_8level(jme);
break;
default:
break;
goto out;
--limit;
+ rmb();
desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT;
if (unlikely(desccnt > 1 ||
}
}
+static inline void
+jme_new_phy_on(struct jme_adapter *jme)
+{
+ u32 reg;
+
+ reg = jread32(jme, JME_PHY_PWR);
+ reg &= ~(PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW |
+ PHY_PWR_DWN2 | PHY_PWR_CLKSEL);
+ jwrite32(jme, JME_PHY_PWR, reg);
+
+ pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, ®);
+ reg &= ~PE1_GPREG0_PBG;
+ reg |= PE1_GPREG0_ENBG;
+ pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg);
+}
+
+static inline void
+jme_new_phy_off(struct jme_adapter *jme)
+{
+ u32 reg;
+
+ reg = jread32(jme, JME_PHY_PWR);
+ reg |= PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW |
+ PHY_PWR_DWN2 | PHY_PWR_CLKSEL;
+ jwrite32(jme, JME_PHY_PWR, reg);
+
+ pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, ®);
+ reg &= ~PE1_GPREG0_PBG;
+ reg |= PE1_GPREG0_PDD3COLD;
+ pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg);
+}
+
+static inline void
+jme_phy_on(struct jme_adapter *jme)
+{
+ u32 bmcr;
+
+ bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
+ bmcr &= ~BMCR_PDOWN;
+ jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+
+ if (new_phy_power_ctrl(jme->chip_main_rev))
+ jme_new_phy_on(jme);
+}
+
+static inline void
+jme_phy_off(struct jme_adapter *jme)
+{
+ u32 bmcr;
+
+ bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
+ bmcr |= BMCR_PDOWN;
+ jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+
+ if (new_phy_power_ctrl(jme->chip_main_rev))
+ jme_new_phy_off(jme);
+}
+
static int
jme_open(struct net_device *netdev)
{
jme_start_irq(jme);
+ jme_phy_on(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
jme_set_settings(netdev, &jme->old_ecmd);
else
return rc;
}
-#ifdef CONFIG_PM
static void
jme_set_100m_half(struct jme_adapter *jme)
{
u32 bmcr, tmp;
+ jme_phy_on(jme);
bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
BMCR_SPEED1000 | BMCR_FULLDPLX);
phylink = jme_linkstat_from_phy(jme);
}
}
-#endif
-static inline void
-jme_phy_off(struct jme_adapter *jme)
+static void
+jme_powersave_phy(struct jme_adapter *jme)
{
- jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN);
+ 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);
+ } else {
+ jme_phy_off(jme);
+ }
}
static int
}
if (new_mtu > 1900) {
- netdev->features &= ~(NETIF_F_HW_CSUM |
- NETIF_F_TSO
-#ifdef NETIF_F_TSO6
- | NETIF_F_TSO6
-#endif
- );
+ netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6);
} else {
if (test_bit(JME_FLAG_TXCSUM, &jme->flags))
- netdev->features |= NETIF_F_HW_CSUM;
+ netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
if (test_bit(JME_FLAG_TSO, &jme->flags))
- netdev->features |= NETIF_F_TSO
-#ifdef NETIF_F_TSO6
- | NETIF_F_TSO6
-#endif
- ;
+ netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
}
netdev->mtu = new_mtu;
if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE)
return -EINVAL;
+ /*
+ * Check If user changed duplex only while force_media.
+ * Hardware would not generate link change interrupt.
+ */
if (jme->mii_if.force_media &&
ecmd->autoneg != AUTONEG_ENABLE &&
(jme->mii_if.full_duplex != ecmd->duplex))
rc = mii_ethtool_sset(&(jme->mii_if), ecmd);
spin_unlock_bh(&jme->phy_lock);
- if (!rc && fdc)
- jme_reset_link(jme);
-
if (!rc) {
- set_bit(JME_FLAG_SSET, &jme->flags);
+ if (fdc)
+ jme_reset_link(jme);
jme->old_ecmd = *ecmd;
+ set_bit(JME_FLAG_SSET, &jme->flags);
+ }
+
+ return rc;
+}
+
+static int
+jme_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ int rc;
+ struct jme_adapter *jme = netdev_priv(netdev);
+ struct mii_ioctl_data *mii_data = if_mii(rq);
+ unsigned int duplex_chg;
+
+ if (cmd == SIOCSMIIREG) {
+ u16 val = mii_data->val_in;
+ if (!(val & (BMCR_RESET|BMCR_ANENABLE)) &&
+ (val & BMCR_SPEED1000))
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&jme->phy_lock);
+ rc = generic_mii_ioctl(&jme->mii_if, mii_data, cmd, &duplex_chg);
+ spin_unlock_bh(&jme->phy_lock);
+
+ if (!rc && (cmd == SIOCSMIIREG)) {
+ if (duplex_chg)
+ jme_reset_link(jme);
+ jme_get_settings(netdev, &jme->old_ecmd);
+ set_bit(JME_FLAG_SSET, &jme->flags);
}
return rc;
if (on) {
set_bit(JME_FLAG_TXCSUM, &jme->flags);
if (netdev->mtu <= 1900)
- netdev->features |= NETIF_F_HW_CSUM;
+ netdev->features |=
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
} else {
clear_bit(JME_FLAG_TXCSUM, &jme->flags);
- netdev->features &= ~NETIF_F_HW_CSUM;
+ netdev->features &=
+ ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
}
return 0;
if (on) {
set_bit(JME_FLAG_TSO, &jme->flags);
if (netdev->mtu <= 1900)
- netdev->features |= NETIF_F_TSO
-#ifdef NETIF_F_TSO6
- | NETIF_F_TSO6
-#endif
- ;
+ netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
} else {
clear_bit(JME_FLAG_TSO, &jme->flags);
- netdev->features &= ~(NETIF_F_TSO
-#ifdef NETIF_F_TSO6
- | NETIF_F_TSO6
-#endif
- );
+ netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
}
return 0;
jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT;
jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT;
+ jme->chip_main_rev = jme->chiprev & 0xF;
+ jme->chip_sub_rev = (jme->chiprev >> 4) & 0xF;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
.ndo_open = jme_open,
.ndo_stop = jme_close,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = jme_ioctl,
.ndo_start_xmit = jme_start_xmit,
.ndo_set_mac_address = jme_set_macaddr,
.ndo_set_multicast_list = jme_set_multi,
#else
netdev->open = jme_open;
netdev->stop = jme_close;
+ netdev->do_ioctl = jme_ioctl;
netdev->hard_start_xmit = jme_start_xmit;
netdev->set_mac_address = jme_set_macaddr;
netdev->set_multicast_list = jme_set_multi;
#endif
netdev->ethtool_ops = &jme_ethtool_ops;
netdev->watchdog_timeo = TX_TIMEOUT;
- netdev->features = NETIF_F_HW_CSUM |
+ netdev->features = NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
NETIF_F_SG |
NETIF_F_TSO |
-#ifdef NETIF_F_TSO6
NETIF_F_TSO6 |
-#endif
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX;
if (using_dac)
jme->mii_if.supports_gmii = true;
else
jme->mii_if.supports_gmii = false;
+ jme->mii_if.phy_id_mask = 0x1F;
+ jme->mii_if.reg_num_mask = 0x1F;
jme->mii_if.mdio_read = jme_mdio_read;
jme->mii_if.mdio_write = jme_mdio_write;
jme_clear_pm(jme);
- jme_set_phyfifoa(jme);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->rev);
+ jme_set_phyfifo_5level(jme);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->pcirev);
if (!jme->fpgaver)
jme_phy_init(jme);
jme_phy_off(jme);
* Tell stack that we are not ready to work until open()
*/
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- /*
- * Register netdev
- */
rc = register_netdev(netdev);
if (rc) {
pr_err("Cannot register net device\n");
goto err_out_unmap;
}
- netif_info(jme, probe, jme->dev, "%s%s ver:%x rev:%x "
+ netif_info(jme, probe, jme->dev, "%s%s chipver:%x pcirev:%x "
"macaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
(jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
"JMC250 Gigabit Ethernet" :
"JMC260 Fast Ethernet" : "Unknown",
(jme->fpgaver != 0) ? " (FPGA)" : "",
(jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
- jme->rev,
+ jme->pcirev,
netdev->dev_addr[0],
netdev->dev_addr[1],
netdev->dev_addr[2],
}
+static void
+jme_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct jme_adapter *jme = netdev_priv(netdev);
+
+ jme_powersave_phy(jme);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
+ pci_enable_wake(pdev, PCI_D3hot, true);
+#else
+ pci_pme_active(pdev, true);
+#endif
+}
+
#ifdef CONFIG_PM
static int
jme_suspend(struct pci_dev *pdev, pm_message_t state)
tasklet_hi_enable(&jme->rxempty_task);
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_D3cold, true);
- } else {
- jme_phy_off(jme);
- }
- pci_set_power_state(pdev, PCI_D3cold);
+ jme_powersave_phy(jme);
+ pci_enable_wake(pdev, PCI_D3hot, true);
+ pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
jme_clear_pm(jme);
pci_restore_state(pdev);
+ jme_phy_on(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
jme_set_settings(netdev, &jme->old_ecmd);
else
.suspend = jme_suspend,
.resume = jme_resume,
#endif /* CONFIG_PM */
+ .shutdown = jme_shutdown,
};
static int __init