📄 adapter.c
字号:
case (MARVELL_88E1111_LINKSPEED_1000M): XTemac_SetOperatingSpeed(&lp->Emac, 1000); printk(KERN_INFO "%s: XTemac: speed set to 1000Mb/s\n", dev->name); lp->cur_speed = 1000; break; case (MARVELL_88E1111_LINKSPEED_100M): XTemac_SetOperatingSpeed(&lp->Emac, 100); printk(KERN_INFO "%s: XTemac: speed set to 100Mb/s\n", dev->name); lp->cur_speed = 100; break; case (MARVELL_88E1111_LINKSPEED_10M): XTemac_SetOperatingSpeed(&lp->Emac, 10); printk(KERN_INFO "%s: XTemac: speed set to 10Mb/s\n", dev->name); lp->cur_speed = 10; break; default: XTemac_SetOperatingSpeed(&lp->Emac, 1000); printk(KERN_INFO "%s: XTemac: speed set to 1000Mb/s\n", dev->name); lp->cur_speed = 1000; break; }#else if (XTemac_mGetPhysicalInterface(&lp->Emac) == XTE_PHY_TYPE_MII) { phylinkspeed = 100; } else { phylinkspeed = 1000; } /* * Try to renegotiate the speed until something sticks */ while (phylinkspeed > 1) { ret = renegotiate_speed(dev, phylinkspeed, FULL_DUPLEX); /* * ret == 1 - try it again * ret == 0 - it worked * ret < 0 - there was some failure negotiating the speed */ if (ret == 0) { /* it worked, get out of the loop */ break; } /* it didn't work this time, but it may work if we try again */ if ((ret == 1) && (retry_count)) { retry_count--; printk("trying again...\n"); continue; } /* reset the retry_count, becuase we're about to try a lower speed */ retry_count = 1; phylinkspeed /= 10; } if (phylinkspeed == 1) { printk(KERN_INFO "%s: XTemac: could not negotiate speed\n", dev->name); lp->cur_speed = 0; return; } XTemac_SetOperatingSpeed(&lp->Emac, phylinkspeed); printk(KERN_INFO "%s: XTemac: speed set to %dMb/s\n", dev->name, phylinkspeed); lp->cur_speed = phylinkspeed;#endif}/* * Helper function to reset the underlying hardware. This is called * when we get into such deep trouble that we don't know how to handle * otherwise. *//* * This reset function should handle five different reset request types * from other functions. The reset request types include * 1. FIFO error: FifoWrite()/FifoSend()/FifoRecv()/FifoRead() fails * 2. DMA error: SgAlloc()/SgCommit()/SgFree() fails * 3. DUPLEX error: MAC DUPLEX is not full duplex or does not match * PHY setting * 4. TX Timeout: Timeout occurs for a TX frame given to this adapter * 5. Error Status: Temac Error interrupt occurs and asks for a reset * */static voidreset(struct net_device *dev, u32 line_num){ struct net_local *lp = (struct net_local *) dev->priv; u16 TxThreshold, TxWaitBound, RxThreshold, RxWaitBound; u32 Options; static u32 reset_cnt = 0; printk(KERN_INFO "%s: XTemac: resets (#%u) from adapter code line %d\n", dev->name, ++reset_cnt, line_num); /* Shouldn't really be necessary, but shouldn't hurt. */ netif_stop_queue(dev); /* Stop device */ XTemac_Stop(&lp->Emac); /* * XTemac_Reset puts the device back to the default state. We need * to save all the settings we don't already know, reset, restore * the settings, and then restart the temac. */ Options = XTemac_GetOptions(&lp->Emac); if (XTemac_mIsSgDma(&lp->Emac)) { /* * The following two functions will return an error if we are * not doing scatter-gather DMA. We just checked that so we * can safely ignore the return values. */ (XStatus) XTemac_IntrSgCoalGet(&lp->Emac, XTE_RECV, &RxThreshold, &RxWaitBound); (XStatus) XTemac_IntrSgCoalGet(&lp->Emac, XTE_SEND, &TxThreshold, &TxWaitBound); } /* now we can reset the device */ XTemac_Reset(&lp->Emac, 0); /* Reset on TEMAC also resets PHY. Give it some time to finish negotiation * before we move on */ mdelay(2000); /* * The following four functions will return an error if the * EMAC is already started. We just stopped it by calling * XTemac_Reset() so we can safely ignore the return values. */ (XStatus) XTemac_SetMacAddress(&lp->Emac, dev->dev_addr); (XStatus) XTemac_SetOptions(&lp->Emac, Options); (XStatus) XTemac_ClearOptions(&lp->Emac, ~Options); Options = XTemac_GetOptions(&lp->Emac); printk(KERN_INFO "%s: XTemac: Options: 0x%x\n", dev->name, Options); set_mac_speed(lp); if (XTemac_mIsSgDma(&lp->Emac)) { /* SG DMA mode */ /* * The following 2 functions will return an error if * we are not doing scatter-gather DMA or if the EMAC is * already started. We just checked that we are indeed * doing scatter-gather and we just stopped the EMAC so * we can safely ignore the return values. */ (XStatus) XTemac_IntrSgCoalSet(&lp->Emac, XTE_RECV, RxThreshold, RxWaitBound); (XStatus) XTemac_IntrSgCoalSet(&lp->Emac, XTE_SEND, TxThreshold, TxWaitBound); /* Enable both SEND and RECV interrupts */ XTemac_IntrSgEnable(&lp->Emac, XTE_SEND | XTE_RECV); } else { /* FIFO interrupt mode */ XTemac_IntrFifoEnable(&lp->Emac, XTE_RECV | XTE_SEND); } if (lp->deferred_skb) { dev_kfree_skb_any(lp->deferred_skb); lp->deferred_skb = NULL; lp->stats.tx_errors++; } /* * XTemac_Start returns an error when: if configured for * scatter-gather DMA and a descriptor list has not yet been created * for the send or receive channel, or if no receive buffer descriptors * have been initialized. Those are not happening. so ignore the returned * result checking. */ (XStatus) XTemac_Start(&lp->Emac); /* We're all ready to go. Start the queue in case it was stopped. */ netif_wake_queue(dev);}/* * The PHY registers read here should be standard registers in all PHY chips */static intget_phy_status(struct net_device *dev, DUPLEX * duplex, int *linkup){ struct net_local *lp = (struct net_local *) dev->priv; u16 reg; XStatus xs; xs = XTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMCR, ®); if (xs != XST_SUCCESS) { printk(KERN_ERR "%s: XTemac: could not read PHY control register; error %d\n", dev->name, xs); return -1; } *duplex = FULL_DUPLEX; xs = XTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, ®); if (xs != XST_SUCCESS) { printk(KERN_ERR "%s: XTemac: could not read PHY status register; error %d\n", dev->name, xs); return -1; } *linkup = (reg & BMSR_LSTATUS) != 0; return 0;}/* * This routine is used for two purposes. The first is to keep the * EMAC's duplex setting in sync with the PHY's. The second is to keep * the system apprised of the state of the link. Note that this driver * does not configure the PHY. Either the PHY should be configured for * auto-negotiation or it should be handled by something like mii-tool. */static voidpoll_gmii(unsigned long data){ struct net_device *dev; struct net_local *lp; DUPLEX phy_duplex; int phy_carrier; int netif_carrier; unsigned long flags; spin_lock_irqsave(&XTE_spinlock, flags); dev = (struct net_device *) data; lp = (struct net_local *) dev->priv; /* First, find out what's going on with the PHY. */ if (get_phy_status(dev, &phy_duplex, &phy_carrier)) { printk(KERN_ERR "%s: XTemac: terminating link monitoring.\n", dev->name); spin_unlock_irqrestore(&XTE_spinlock, flags); return; } netif_carrier = netif_carrier_ok(dev) != 0; if (phy_carrier != netif_carrier) { if (phy_carrier) { printk(KERN_INFO "%s: XTemac: PHY Link carrier restored.\n", dev->name); netif_carrier_on(dev); } else { printk(KERN_INFO "%s: XTemac: PHY Link carrier lost.\n", dev->name); netif_carrier_off(dev); } } /* Set up the timer so we'll get called again in 2 seconds. */ lp->phy_timer.expires = jiffies + 2 * HZ; add_timer(&lp->phy_timer); spin_unlock_irqrestore(&XTE_spinlock, flags);}/* * This routine is registered with the OS as the function to call when * the TEMAC interrupts. It in turn, calls the Xilinx OS independent * interrupt function. There are different interrupt functions for FIFO * and scatter-gather so we just set a pointer (Isr) into our private * data so we don't have to figure it out here. The Xilinx OS * independent interrupt function will in turn call any callbacks that * we have registered for various conditions. */static irqreturn_txenet_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id; struct net_local *lp = (struct net_local *) dev->priv; /* Call it. */ (*(lp->Isr)) (&lp->Emac); /* Right now, our IRQ handlers do not return a status. Let's always return * IRQ_HANDLED here for now. */ return IRQ_HANDLED;}static intxenet_open(struct net_device *dev){ struct net_local *lp; u32 Options; unsigned long flags; /* * Just to be safe, stop TX queue and the device first. If the device is * already stopped, an error will be returned. In this case, we don't * really care. */ netif_stop_queue(dev); spin_lock_irqsave(&XTE_spinlock, flags); lp = (struct net_local *) dev->priv; XTemac_Stop(&lp->Emac); /* Set the MAC address each time opened. */ if (XTemac_SetMacAddress(&lp->Emac, dev->dev_addr) != XST_SUCCESS) { printk(KERN_ERR "%s: XTemac: could not set MAC address.\n", dev->name); spin_unlock_irqrestore(&XTE_spinlock, flags); return -EIO; } /* * If the device is not configured for polled mode, connect to the * interrupt controller and enable interrupts. Currently, there * isn't any code to set polled mode, so this check is probably * superfluous. */ Options = XTemac_GetOptions(&lp->Emac); Options &= ~XTE_SGEND_INT_OPTION; Options &= ~XTE_REPORT_RXERR_OPTION; Options |= XTE_FLOW_CONTROL_OPTION; Options |= XTE_JUMBO_OPTION;#if XTE_AUTOSTRIPPING Options |= XTE_FCS_STRIP_OPTION;#endif (XStatus) XTemac_SetOptions(&lp->Emac, Options); (XStatus) XTemac_ClearOptions(&lp->Emac, ~Options); Options = XTemac_GetOptions(&lp->Emac); printk(KERN_INFO "%s: XTemac: Options: 0x%x\n", dev->name, Options); /* Register interrupt handler */ if ((Options & XTE_POLLED_OPTION) == 0) { int retval; /* Grab the IRQ */ retval = request_irq(dev->irq, &xenet_interrupt, 0, dev->name, dev); if (retval) { printk(KERN_ERR "%s: XTemac: could not allocate interrupt %d.\n", dev->name, dev->irq); spin_unlock_irqrestore(&XTE_spinlock, flags); return retval; } } /* give the system enough time to establish a link */ mdelay(2000); set_mac_speed(lp); INIT_LIST_HEAD(&(lp->rcv)); INIT_LIST_HEAD(&(lp->xmit)); /* Enable interrupts if not in polled mode */ if ((Options & XTE_POLLED_OPTION) == 0) { if (!XTemac_mIsSgDma(&lp->Emac)) { /*fifo direct interrupt driver mode*/ XTemac_IntrFifoEnable(&lp->Emac, XTE_RECV | XTE_SEND); } else {/* SG DMA mode */ XTemac_IntrSgEnable(&lp->Emac, XTE_SEND | XTE_RECV); } } /* Start TEMAC device */ if (XTemac_Start(&lp->Emac) != XST_SUCCESS) { printk(KERN_ERR "%s: XTemac: could not start device.\n", dev->name); free_irq(dev->irq, dev); spin_unlock_irqrestore(&XTE_spinlock, flags); return -EBUSY; } spin_unlock_irqrestore(&XTE_spinlock, flags); if (XTemac_mIsSgDma(&lp->Emac)) { u16 threshold_s, timer_s, threshold_r, timer_r; (XStatus) XTemac_IntrSgCoalGet(&lp->Emac, XTE_SEND, &threshold_s, &timer_s); (XStatus) XTemac_IntrSgCoalGet(&lp->Emac, XTE_RECV, &threshold_r, &timer_r); printk(KERN_INFO "%s: XTemac: Send Threshold = %d, Receive Threshold = %d\n", dev->name, threshold_s, threshold_r); printk(KERN_INFO "%s: XTemac: Send Wait bound = %d, Receive Wait bound = %d\n", dev->name, timer_s, timer_r); } /* We're ready to go. */ netif_start_queue(dev); /* Set up the PHY monitoring timer. */ lp->phy_timer.expires = jiffies + 2 * HZ; lp->phy_timer.data = (unsigned long) dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -