Chinaunix首页 | 论坛 | 博客
  • 博客访问: 981217
  • 博文数量: 109
  • 博客积分: 554
  • 博客等级: 中士
  • 技术积分: 2577
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 12:49
文章分类

全部博文(109)

文章存档

2019年(5)

2016年(7)

2015年(9)

2014年(1)

2013年(71)

2012年(16)

分类: 嵌入式

2013-06-27 11:36:41

错误现象:

系统启动后,ping网口,插拔网线后,就不能ping通,必须ifconfig重新启动网口才能ping

原因分析:

插上网线后,产生phy中断, 从中断到检查link stat自动协商比较慢,但是我们的代码中没有延时,所以导致检查失败;

解决方法:

产生PHY中断后,延时一段时间,再检查link stat

 

dm9000 采用工作队列的方式,delay一段时间后再查看寄存器。

 

dm9000_probe(struct platform_dev *pdev)

{

        

         INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);

        

}

 

static irqreturn_t dm9000_interrupt(int irq, void *devid)

{

        

         if (db->type != TYPE_DM9000E) {

                   if (int_status & ISR_LNKCHNG) {

                            /* fire a link-change request */

                            schedule_delayed_work(&db->phy_poll, 1);

                   }

         }

}

 

static void

dm9000_poll_work(struct work_struct *w)

{

         struct delayed_work *dw = to_delayed_work(w);

         board_info_t *db = container_of(dw, board_info_t, phy_poll);

         struct net_device *ndev = db->ndev;

 

         if (db->flags & DM9000_PLATF_SIMPLE_PHY &&

             !(db->flags & DM9000_PLATF_EXT_PHY)) {

                   unsigned nsr = dm9000_read_locked(db, DM9000_NSR);

                   unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;

                   unsigned new_carrier;

 

                   new_carrier = (nsr & NSR_LINKST) ? 1 : 0;

 

                   if (old_carrier != new_carrier) {

                            if (netif_msg_link(db))

                                     dm9000_show_carrier(db, new_carrier, nsr);

 

                            if (!new_carrier)

                                     netif_carrier_off(ndev);

                            else

                                     netif_carrier_on(ndev);

                   }

         } else

                   mii_check_media(&db->mii, netif_msg_link(db), 0);

        

         if (netif_running(ndev))

                   dm9000_schedule_poll(db);

}

 

static void dm9000_schedule_poll(board_info_t *db)

{

         if (db->type == TYPE_DM9000E)

                   schedule_delayed_work(&db->phy_poll, HZ * 2);

}

 

参考dm9000的代码,但是这里我们不采用延时的工作队列的办法而采用中断线程的方法,在其他文章已经介绍过request_threaded_irq的使用方法

 

static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)

{

         struct net_device *dev = (struct net_device *) dev_id;

         struct at91_private *lp = netdev_priv(dev);

         unsigned int phy;

 

         /*

          * This hander is triggered on both edges, but the PHY chips expect

          * level-triggering.  We therefore have to check if the PHY actually has

          * an IRQ pending.

          */

         enable_mdi();

         if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID) || (lp->phy_type == MII_DM9161C_ID)) {

                   read_phy(lp->phy_address, MII_DSINTR_REG, &phy);  /* ack interrupt in Davicom PHY */

 

                   if (!(phy & (1 << 0)))

                            goto done;

        else

            printk(KERN_DEBUG "In interrupt function : %s, REG21=%x\n", __FUNCTION__, phy);

         }

         else if (lp->phy_type == MII_LXT971A_ID) {

                   read_phy(lp->phy_address, MII_ISINTS_REG, &phy);    /* ack interrupt in Intel PHY */

                   if (!(phy & (1 << 2)))

                            goto done;

         }

         else if (lp->phy_type == MII_BCM5221_ID) {

                   read_phy(lp->phy_address, MII_BCMINTR_REG, &phy);       /* ack interrupt in Broadcom PHY */

                   if (!(phy & (1 << 0)))

                            goto done;

         }

         else if ((lp->phy_type == MII_KS8721_ID) || (lp->phy_type == MII_KSZ8041_ID)) {

                   read_phy(lp->phy_address, MII_TPISTATUS, &phy);                /* ack interrupt in Micrel PHY */

                   if (!(phy & ((1 << 2) | 1)))

                            goto done;

         }

         else if (lp->phy_type == MII_T78Q21x3_ID) {                    /* ack interrupt in Teridian PHY */

                   read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);

                   if (!(phy & ((1 << 2) | 1)))

                            goto done;

         }

         else if (lp->phy_type == MII_DP83848_ID) {

                   read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy);      /* ack interrupt in DP83848 PHY */

                   if (!(phy & (1 << 7)))

                            goto done;

         }

         else if (lp->phy_type == MII_STE100P_ID) {                       /* ack interrupt in STE100P PHY */

                   read_phy(lp->phy_address, MII_STE100P_XCSIIS_REG, &phy);

                   if (!(phy & 0x007F))

                            goto done;

         }

    /* update_linkspeed move to irq thread_fn */

//      update_linkspeed(dev, 0);

 

done:

         disable_mdi();

 

         return IRQ_WAKE_THREAD;

}

 

 

static irqreturn_t at91ether_phy_work(int irq, void *dev_id)

{

    struct net_device *dev = (struct net_device *) dev_id;

         struct at91_private *lp = netdev_priv(dev);

         unsigned int phy;

    msleep(2000);

    enable_mdi();

    update_linkspeed(dev, 0);

    disable_mdi();

    return IRQ_HANDLED;

}

 

申请中断:

       

         status = request_threaded_irq(irq_number, at91ether_phy_interrupt, at91ether_phy_work,0, dev->name, dev);

         if (status) {

                   printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);

                   return;

         }

        

阅读(8540) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~