]> bbs.cooldavid.org Git - jme.git/blobdiff - jme.c
AudoSpeedDown
[jme.git] / jme.c
diff --git a/jme.c b/jme.c
index 2852ba56fb33696f70a1c8771fa7e9634b85eb2b..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
@@ -1817,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);
@@ -2483,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
@@ -2719,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;
@@ -2730,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);
@@ -3066,7 +3181,7 @@ jme_init_one(struct pci_dev *pdev,
        struct jme_adapter *jme;
        u16 bmcr, bmsr;
        u32 apmc;
-
+       
        /*
         * set up PCI device basics
         */
@@ -3156,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;
@@ -3199,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;
@@ -3262,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);
@@ -3280,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) ?
@@ -3329,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);
@@ -3365,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);
@@ -3396,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;
 }