From: Guo-Fu Tseng Date: Sat, 28 May 2011 13:57:52 +0000 (+0800) Subject: AudoSpeedDown X-Git-Url: https://bbs.cooldavid.org/git/?p=jme.git;a=commitdiff_plain;h=refs%2Fheads%2Fautodown AudoSpeedDown --- diff --git a/jme.c b/jme.c index aeedfe2..b79913e 100644 --- a/jme.c +++ b/jme.c @@ -50,6 +50,7 @@ static int force_pseudohp = -1; static int no_pseudohp = -1; static int no_extplug = -1; +static int delay_time = 11; module_param(force_pseudohp, int, 0); MODULE_PARM_DESC(force_pseudohp, "Enable pseudo hot-plug feature manually by driver instead of BIOS."); @@ -58,7 +59,10 @@ MODULE_PARM_DESC(no_pseudohp, "Disable pseudo hot-plug feature."); module_param(no_extplug, int, 0); MODULE_PARM_DESC(no_extplug, "Do not use external plug signal for pseudo hot-plug."); - +module_param(delay_time, uint, 0); +MODULE_PARM_DESC(delay_time, + "Seconds to delay before switching lower speed; default = 11 seconds(3 trials)"); + static int jme_mdio_read(struct net_device *netdev, int phy, int reg) { @@ -111,36 +115,6 @@ jme_mdio_write(struct net_device *netdev, pr_err("phy(%d) write timeout : %d\n", phy, reg); } -static int -jme_phyext_read(struct jme_adapter *jme, int reg) -{ - jme_mdio_write(jme->dev, jme->mii_if.phy_id, - JME_PHY_SPEC_ADDR_REG, - JME_PHY_SPEC_REG_READ | (reg & 0x3FFF)); - return jme_mdio_read(jme->dev, jme->mii_if.phy_id, - JME_PHY_SPEC_DATA_REG); -} - -static void -jme_phyext_write(struct jme_adapter *jme, int reg, int val) -{ - jme_mdio_write(jme->dev, jme->mii_if.phy_id, - JME_PHY_SPEC_DATA_REG, val); - jme_mdio_write(jme->dev, jme->mii_if.phy_id, - JME_PHY_SPEC_ADDR_REG, - JME_PHY_SPEC_REG_WRITE | (reg & 0x3FFF)); -} - -static void -jme_phyext_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_phyext_read(jme, i); -} - static inline void jme_reset_phy_processor(struct jme_adapter *jme) { @@ -436,12 +410,14 @@ jme_linkstat_from_phy(struct jme_adapter *jme) return phylink; } +/* setting as RMII mode ??*/ static inline void jme_set_phyfifo_5level(struct jme_adapter *jme) { jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004); } +/* setting MII mode ??*/ static inline void jme_set_phyfifo_8level(struct jme_adapter *jme) { @@ -1328,6 +1304,122 @@ jme_stop_shutdown_timer(struct jme_adapter *jme) jwrite32f(jme, JME_APMC, apmc); } + +static void +jme_set_physpeed_capability(struct jme_adapter *jme,u16 speed) +{ + u32 advert, advert2; + + spin_lock_bh(&jme->phy_lock); + if (speed == SPEED_1000){ + advert2 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); + advert2 = (advert2|ADVERTISE_1000HALF|ADVERTISE_1000FULL); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, advert2); + advert = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); + advert = (advert|ADVERTISE_100HALF|ADVERTISE_100FULL); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE, advert); + }else if (speed == SPEED_100){ + advert2 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); + advert2 = advert2 & ~(ADVERTISE_1000HALF|ADVERTISE_1000FULL); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, advert2); + advert = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); + advert = (advert|ADVERTISE_100HALF|ADVERTISE_100FULL); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE, advert); + }else{ + advert2 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); + advert2 = advert2 & ~(ADVERTISE_1000HALF|ADVERTISE_1000FULL); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, advert2); + advert = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE); + advert = advert & ~(ADVERTISE_100HALF|ADVERTISE_100FULL); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE, advert); + } + spin_unlock_bh(&jme->phy_lock); + return; +} + +/* PHY reg: MII_FCSCOUNTER is read and clear, we have to continuing read until RJ45 is attached, then cache this result. */ +static int +jme_check_ANcomplete(struct jme_adapter *jme) +{ + u32 val; + + val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_FCSCOUNTER); + return ((val&(PHY_SPEC_STATUS_AN_FAIL|PHY_SPEC_STATUS_AN_COMPLETE))==PHY_SPEC_STATUS_AN_COMPLETE) ? true : false; +} + +static int +jme_media_connected(struct jme_adapter *jme) +{ + if (jme->flag_media_connected == true) + return true; + + jme->flag_media_connected = jme_check_ANcomplete(jme); + + return jme->flag_media_connected; +} + +static void +asd_polling_func(unsigned long data) +{ + struct jme_adapter *jme = (struct jme_adapter *)data; + + /* + check condition term by term. + 1. link is up() ==> reset all thing, exit the process. + 2. there is no RJ45 cable attached. ==> do nothing but polling. + 3. RJ45 cable attached. but link is down ==> downspeed if the timeing is over 3.5 second. + */ + if (jme->flag_run_asd == true){ + printk("%s: run polling \n", __FUNCTION__ ); + if (jme_media_connected(jme)){ + jme->mc_count++; + printk("%s: pos1 mc_count=%d flag_media_connected=%d \n", \ + __FUNCTION__, jme->mc_count , jme->flag_media_connected); + if (jme->mc_count == (delay_time*3-5)){ + /* RJ45 is attached but unable to link anyway, it CANT + be resolved by speed, restore the capability */ + jme_set_physpeed_capability(jme,SPEED_1000); + jme->flag_media_connected = false; + jme->mc_count = 0; + }else if (jme->mc_count == (delay_time*2-5)){ + if (jme_check_ANcomplete(jme)) + jme_set_physpeed_capability(jme,SPEED_10); + else{ + jme->flag_media_connected = false; + jme->mc_count = 0; + } + }else if (jme->mc_count == delay_time-5){ + if (jme_check_ANcomplete(jme)) + jme_set_physpeed_capability(jme,SPEED_100); + else{ + jme->flag_media_connected = false; + jme->mc_count = 0; + } + } + } + mod_timer(&jme->asd_timer, jiffies+HZ); + return ; + } + +//out: + printk("%s stop polling \n", __FUNCTION__); + jme->flag_media_connected = false; + jme->mc_count = 0; + return; +} + +static int jme_check_linkup(struct jme_adapter *jme) +{ + u32 phylink; + + if (jme->fpgaver) + phylink = jme_linkstat_from_phy(jme); + else + phylink = jread32(jme, JME_PHY_LINK); + + return (phylink & PHY_LINK_UP)? true : false; +} + static void jme_link_change_tasklet(unsigned long arg) { @@ -1341,7 +1433,32 @@ jme_link_change_tasklet(unsigned long arg) while (atomic_read(&jme->link_changing) != 1) netif_info(jme, intr, jme->dev, "Waiting link change lock\n"); } - + printk("====== change_tasklet()=%d =======\n",jme->flag_run_asd); +// if (jme->chip_main_rev < 4 ){ + if (jme_check_linkup(jme)){ + if (jme->flag_run_asd){ + /* stop asd_polling_timer(); */ + printk("===stop asd_polling_timer()==\n"); + jme->flag_run_asd = false; + del_timer_sync(&jme->asd_timer); + } + } + else{ + if (!jme->flag_run_asd){ + printk("===start asd_polling_timer()==\n"); + /* start asd_polling_timer(); */ + jme_set_physpeed_capability(jme,SPEED_1000); + jme_check_ANcomplete(jme); /* clear PHY 0x13*/ + jme->flag_media_connected = false; + jme->flag_run_asd = true; + jme->mc_count = 0; + jme->asd_timer.expires = jiffies + 4*HZ; + jme->asd_timer.function = &asd_polling_func; + jme->asd_timer.data = (unsigned long)jme; + add_timer(&jme->asd_timer); + } + } +// } if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu) goto out; @@ -1355,7 +1472,7 @@ jme_link_change_tasklet(unsigned long arg) tasklet_disable(&jme->rxclean_task); tasklet_disable(&jme->rxempty_task); - if (netif_carrier_ok(netdev)) { + if (netif_carrier_ok(netdev)) { jme_disable_rx_engine(jme); jme_disable_tx_engine(jme); jme_reset_mac_processor(jme); @@ -1569,7 +1686,7 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat) * Disable interrupt */ jwrite32f(jme, JME_IENC, INTR_ENABLE); - + if (intrstat & (INTR_LINKCH | INTR_SWINTR)) { /* * Link change event is critical @@ -1772,83 +1889,17 @@ jme_new_phy_off(struct jme_adapter *jme) pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg); } -static inline void -jme_recal_phy(struct jme_adapter *jme) -{ - u32 miictl1000, comm2; - - miictl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); - miictl1000 &= ~JME_PHY_GCTRL_TESTMASK; - miictl1000 |= JME_PHY_GCTRL_TESTMODE1; - jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, miictl1000); - - comm2 = jme_phyext_read(jme, JME_PHYEXT_COMM2); - comm2 &= ~(0x0001u); - comm2 |= 0x0011u; - jme_phyext_write(jme, JME_PHYEXT_COMM2, comm2); - - mdelay(20); - - comm2 = jme_phyext_read(jme, JME_PHYEXT_COMM2); - comm2 &= ~(0x0013u); - jme_phyext_write(jme, JME_PHYEXT_COMM2, comm2); - - miictl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); - miictl1000 &= ~JME_PHY_GCTRL_TESTMASK; - jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, miictl1000); -} - -static inline void -jme_set_phyparm(struct jme_adapter *jme, u32 val) -{ - u32 comm0, comm1; - - comm0 = jme_phyext_read(jme, JME_PHYEXT_COMM0); - comm1 = jme_phyext_read(jme, JME_PHYEXT_COMM1); - comm0 &= ~(0xE000u); - comm0 |= ((val << 13) & 0xE000u); - comm1 &= ~(0x0001u); - comm1 |= ((val >> 3) & 0x0001u); - jme_phyext_write(jme, JME_PHYEXT_COMM0, comm0); - jme_phyext_write(jme, JME_PHYEXT_COMM1, comm1); -} - -static inline void -jme_refill_phyparm(struct jme_adapter *jme) -{ - if (jme->chip_main_rev >= 6 || - (jme->chip_main_rev == 5 && - (jme->chip_sub_rev == 0 || - jme->chip_sub_rev == 1 || - jme->chip_sub_rev == 3))) { - jme_set_phyparm(jme, 0x8); - } else if (jme->chip_main_rev == 3 && - (jme->chip_sub_rev == 1 || - jme->chip_sub_rev == 2)) { - jme_set_phyparm(jme, 0x7); - } else if (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260 && - jme->chip_main_rev == 2) { - if (jme->chip_sub_rev == 0) - jme_set_phyparm(jme, 0x3); - else if (jme->chip_sub_rev == 2) - jme_set_phyparm(jme, 0x2); - } -} - static inline void jme_phy_on(struct jme_adapter *jme) { u32 bmcr; - if (new_phy_power_ctrl(jme->chip_main_rev)) - jme_new_phy_on(jme); - 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); - jme_recal_phy(jme); - jme_refill_phyparm(jme); + if (new_phy_power_ctrl(jme->chip_main_rev)) + jme_new_phy_on(jme); } static inline void @@ -1883,7 +1934,7 @@ jme_open(struct net_device *netdev) goto err_out; jme_start_irq(jme); - + jme_phy_on(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) jme_set_settings(netdev, &jme->old_ecmd); @@ -2549,9 +2600,6 @@ jme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) p32 += 0x100 >> 2; mdio_memcpy(jme, p32, JME_PHY_REG_NR); - - p32 += 0x100 >> 2; - jme_phyext_memcpy(jme, p32, JME_PHY_SPEC_REG_NR); } static int @@ -2785,9 +2833,10 @@ jme_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) struct jme_adapter *jme = netdev_priv(netdev); struct mii_ioctl_data *mii_data = if_mii(rq); unsigned int duplex_chg; - + u16 val ; + if (cmd == SIOCSMIIREG) { - u16 val = mii_data->val_in; + val = mii_data->val_in; if (!(val & (BMCR_RESET|BMCR_ANENABLE)) && (val & BMCR_SPEED1000)) return -EINVAL; @@ -2796,7 +2845,7 @@ jme_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 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); @@ -3132,7 +3181,7 @@ jme_init_one(struct pci_dev *pdev, struct jme_adapter *jme; u16 bmcr, bmsr; u32 apmc; - + /* * set up PCI device basics */ @@ -3222,6 +3271,8 @@ jme_init_one(struct pci_dev *pdev, jme->msg_enable = JME_DEF_MSG_ENABLE; jme->regs = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + + if (!(jme->regs)) { pr_err("Mapping PCI resource region error\n"); rc = -ENOMEM; @@ -3265,7 +3316,8 @@ jme_init_one(struct pci_dev *pdev, tasklet_disable_nosync(&jme->linkch_task); tasklet_disable_nosync(&jme->txclean_task); tasklet_disable_nosync(&jme->rxclean_task); - tasklet_disable_nosync(&jme->rxempty_task); + tasklet_disable_nosync(&jme->rxempty_task); + jme->dpi.cur = PCC_P1; jme->reg_ghc = 0; @@ -3328,7 +3380,6 @@ jme_init_one(struct pci_dev *pdev, 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_phyfifo_5level(jme); pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->pcirev); @@ -3346,18 +3397,22 @@ jme_init_one(struct pci_dev *pdev, goto err_out_unmap; } jme_load_macaddr(netdev); - + /* * Tell stack that we are not ready to work until open() */ netif_carrier_off(netdev); - rc = register_netdev(netdev); if (rc) { pr_err("Cannot register net device\n"); goto err_out_unmap; } - + + init_timer(&(jme->asd_timer)); + jme->mc_count = 0; + jme->flag_run_asd = false; + jme->flag_media_connected = false; + 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) ? @@ -3395,6 +3450,7 @@ jme_remove_one(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct jme_adapter *jme = netdev_priv(netdev); + del_timer_sync(&jme->asd_timer); /* Kill if running */ unregister_netdev(netdev); iounmap(jme->regs); pci_set_drvdata(pdev, NULL); @@ -3431,6 +3487,8 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) netif_stop_queue(netdev); jme_stop_irq(jme); +// del_timer_sync(&jme->asd_timer); /* Kill if running */ + tasklet_disable(&jme->txclean_task); tasklet_disable(&jme->rxclean_task); tasklet_disable(&jme->rxempty_task); @@ -3462,6 +3520,8 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) #endif pci_set_power_state(pdev, PCI_D3hot); + jme->mc_count = 0; + jme->flag_media_connected = false; return 0; } diff --git a/jme.h b/jme.h index 1f65208..1fabbce 100644 --- a/jme.h +++ b/jme.h @@ -582,6 +582,13 @@ struct jme_adapter { int (*jme_vlan_rx)(struct sk_buff *skb, struct vlan_group *grp, unsigned short vlan_tag); + + u8 flag_run_asd; /* Is Auto Speed Down polling function running*/ + u32 mc_count; /* second counter as RJ45 is attached */ + u8 flag_media_connected; /* Because PHY 0x13 is read and clear, we need to record it */ + struct timer_list asd_timer; + + DECLARE_NAPI_STRUCT DECLARE_NET_DEVICE_STATS }; @@ -605,7 +612,7 @@ enum jme_flags_bits { }; #define TX_TIMEOUT (5 * HZ) -#define JME_REG_LEN 0x600 +#define JME_REG_LEN 0x500 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9216 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) @@ -956,7 +963,6 @@ static inline u32 smi_phy_addr(int x) #define JME_PHY_TIMEOUT 100 /* 100 msec */ #define JME_PHY_REG_NR 32 -#define JME_PHY_SPEC_REG_NR 128 /* * Global Host Control @@ -1032,6 +1038,13 @@ enum jme_phy_pwr_bit_masks { * 1: xtl_out = phy_giga.PD_OSC */ }; +/* + * False carrier Counter + */ + enum jme_phy_an_status { + PHY_SPEC_STATUS_AN_COMPLETE = 0x00000800, + PHY_SPEC_STATUS_AN_FAIL = 0x00008000, +}; /* * Giga PHY Status Registers @@ -1379,37 +1392,8 @@ enum jme_phy_reg17_vals { PREG17_SPEED_1000M = 0x8000, }; -enum jme_phy_gctrl_masks { - JME_PHY_GCTRL_TESTMASK = 0xA000, -}; - -enum jme_phy_gctrl_vals { - JME_PHY_GCTRL_TESTOFF = 0x0000, - JME_PHY_GCTRL_TESTMODE1 = 0x2000, - JME_PHY_GCTRL_TESTMODE2 = 0x4000, - JME_PHY_GCTRL_TESTMODE3 = 0x6000, - JME_PHY_GCTRL_TESTMODE4 = 0x8000, -}; - #define BMSR_ANCOMP 0x0020 -/* - * For extended PHY register interface - */ -enum jme_phy_spec_regs { - JME_PHY_SPEC_ADDR_REG = 0x1E, - JME_PHY_SPEC_DATA_REG = 0x1F, -}; -enum jme_phy_spec_addr_bits { - JME_PHY_SPEC_REG_READ = 0x4000u, - JME_PHY_SPEC_REG_WRITE = 0x8000u, -}; -enum jme_extphy_regs { - JME_PHYEXT_COMM0 = 0x30, - JME_PHYEXT_COMM1 = 0x31, - JME_PHYEXT_COMM2 = 0x32, -}; - /* * Workaround */