]> bbs.cooldavid.org Git - jme.git/commitdiff
AudoSpeedDown autodown
authorGuo-Fu Tseng <cooldavid@cooldavid.org>
Sat, 28 May 2011 13:57:52 +0000 (21:57 +0800)
committerGuo-Fu Tseng <cooldavid@cooldavid.org>
Sat, 28 May 2011 13:57:52 +0000 (21:57 +0800)
jme.c
jme.h

diff --git a/jme.c b/jme.c
index aeedfe209c19f0b4176fea330dd703daa718defe..b79913e815802b0c70c068991482864226531022 100644 (file)
--- 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 1f65208758c90a12150f53aabf56f20301324e73..1fabbce4d33f5b816d12aac305a91ec200f74e16 100644 (file)
--- 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
  */