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.");
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)
{
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)
{
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)
{
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;
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);
* Disable interrupt
*/
jwrite32f(jme, JME_IENC, INTR_ENABLE);
-
+
if (intrstat & (INTR_LINKCH | INTR_SWINTR)) {
/*
* Link change event is critical
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);
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;
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);
struct jme_adapter *jme;
u16 bmcr, bmsr;
u32 apmc;
-
+
/*
* set up PCI device basics
*/
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;
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;
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);
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) ?
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);
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);
#endif
pci_set_power_state(pdev, PCI_D3hot);
+ jme->mc_count = 0;
+ jme->flag_media_connected = false;
return 0;
}