/** * ks8695_link_irq - Link change IRQ handler * @irq: The IRQ which went off (ignored) * @dev_id: The net_device for the interrupt * * The WAN interface can generate an IRQ when the link changes, * report this to the net layer and the user. */ static irqreturn_t ks8695_link_irq(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *)dev_id; struct ks8695_priv *ksp = netdev_priv(ndev); u32 ctrl; ctrl = readl(ksp->phyiface_regs + KS8695_WMC); if (ctrl & WMC_WLS) { netif_carrier_on(ndev); if (netif_msg_link(ksp)) dev_info(ksp->dev, "%s: Link is now up (10%sMbps/%s-duplex)\n", ndev->name, (ctrl & WMC_WSS) ? "0" : "", (ctrl & WMC_WDS) ? "Full" : "Half"); } else { netif_carrier_off(ndev); if (netif_msg_link(ksp)) dev_info(ksp->dev, "%s: Link is now down.\n", ndev->name); } return IRQ_HANDLED; }
static int atl1c_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct atl1c_adapter *adapter = netdev_priv(netdev); struct atl1c_hw *hw = &adapter->hw; u16 autoneg_advertised; while (test_and_set_bit(__AT_RESETTING, &adapter->flags)) msleep(1); if (ecmd->autoneg == AUTONEG_ENABLE) { autoneg_advertised = ADVERTISED_Autoneg; } else { u32 speed = ethtool_cmd_speed(ecmd); if (speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, "1000M half is invalid\n"); clear_bit(__AT_RESETTING, &adapter->flags); return -EINVAL; } autoneg_advertised = ADVERTISED_1000baseT_Full; } else if (speed == SPEED_100) { if (ecmd->duplex == DUPLEX_FULL) autoneg_advertised = ADVERTISED_100baseT_Full; else autoneg_advertised = ADVERTISED_100baseT_Half; } else { if (ecmd->duplex == DUPLEX_FULL) autoneg_advertised = ADVERTISED_10baseT_Full; else autoneg_advertised = ADVERTISED_10baseT_Half; } } if (hw->autoneg_advertised != autoneg_advertised) { hw->autoneg_advertised = autoneg_advertised; if (atl1c_restart_autoneg(hw) != 0) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, "ethtool speed/duplex setting failed\n"); clear_bit(__AT_RESETTING, &adapter->flags); return -EINVAL; } } clear_bit(__AT_RESETTING, &adapter->flags); return 0; }
/*----------------------------------------------------------------------------- * generic link-change handler - should be sufficient for most cases *-----------------------------------------------------------------------------*/ static void generic_adjust_link(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); struct phy_device *phydev = fep->phydev; int new_state = 0; if (phydev->link) { /* adjust to duplex mode */ if (phydev->duplex != fep->oldduplex) { new_state = 1; fep->oldduplex = phydev->duplex; } if (phydev->speed != fep->oldspeed) { new_state = 1; fep->oldspeed = phydev->speed; } if (!fep->oldlink) { new_state = 1; fep->oldlink = 1; } if (new_state) fep->ops->restart(dev); } else if (fep->oldlink) { new_state = 1; fep->oldlink = 0; fep->oldspeed = 0; fep->oldduplex = -1; } if (new_state && netif_msg_link(fep)) phy_print_status(phydev); }
static int netx_eth_open(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); if (request_irq (ndev->irq, netx_eth_interrupt, IRQF_SHARED, ndev->name, ndev)) return -EAGAIN; writel(ndev->dev_addr[0] | ndev->dev_addr[1]<<8 | ndev->dev_addr[2]<<16 | ndev->dev_addr[3]<<24, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); writel(ndev->dev_addr[4] | ndev->dev_addr[5]<<8, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65); writel(LOCAL_CONFIG_LINK_STATUS_IRQ_EN | LOCAL_CONFIG_CON_LO_IRQ_EN | LOCAL_CONFIG_CON_HI_IRQ_EN | LOCAL_CONFIG_IND_LO_IRQ_EN | LOCAL_CONFIG_IND_HI_IRQ_EN, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG); mii_check_media(&priv->mii, netif_msg_link(priv), 1); netif_start_queue(ndev); return 0; }
static irqreturn_t netx_eth_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct netx_eth_priv *priv = netdev_priv(ndev); int status; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); while (status) { int fill_level; writel(status, NETX_PFIFO_XPEC_ISR(priv->id)); if ((status & ISR_CON_HI) || (status & ISR_IND_HI)) printk("%s: unexpected status: 0x%08x\n", __func__, status); fill_level = readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id))); while (fill_level--) netx_eth_receive(ndev); if (status & ISR_CON_LO) netif_wake_queue(ndev); if (status & ISR_LINK_STATUS_CHANGE) mii_check_media(&priv->mii, netif_msg_link(priv), 1); status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); } spin_unlock_irqrestore(&priv->lock, flags); return IRQ_HANDLED; }
static int cp_open (struct net_device *dev) { struct cp_private *cp = netdev_priv(dev); int rc; if (netif_msg_ifup(cp)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); rc = cp_alloc_rings(cp); if (rc) return rc; cp_init_hw(cp); rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev); if (rc) goto err_out_hw; netif_carrier_off(dev); mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE); netif_start_queue(dev); return 0; err_out_hw: cp_stop_hw(cp); cp_free_rings(cp); return rc; }
static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) { if (netif_msg_link(dev)) devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d", dev->udev->bus->bus_name, dev->udev->devpath, ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); }
static inline void nc_dump_status(struct usbnet *dev, u16 status) { if (!netif_msg_link(dev)) return; devdbg(dev, "net1080 %s-%s status 0x%x:" " this (%c) PKT=%d%s%s%s;" " other PKT=%d%s%s%s; unspec 0x%x", dev->udev->bus->bus_name, dev->udev->devpath, status, // XXX the packet counts don't seem right // (1 at reset, not 0); maybe UNSPEC too (status & STATUS_PORT_A) ? 'A' : 'B', STATUS_PACKETS_THIS(status), (status & STATUS_CONN_THIS) ? " CON" : "", (status & STATUS_SUSPEND_THIS) ? " SUS" : "", (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", STATUS_PACKETS_OTHER(status), (status & STATUS_CONN_OTHER) ? " CON" : "", (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", status & STATUS_UNSPEC_MASK ); }
static void usbnet_bh (unsigned long param) { struct usbnet *dev = (struct usbnet *) param; struct sk_buff *skb; struct skb_data *entry; while ((skb = skb_dequeue (&dev->done))) { entry = (struct skb_data *) skb->cb; switch (entry->state) { case rx_done: entry->state = rx_cleanup; rx_process (dev, skb); continue; case tx_done: case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); continue; default: devdbg (dev, "bogus skb state %d", entry->state); } } // waiting for all pending urbs to complete? if (dev->wait) { if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { wake_up (dev->wait); } // or are we maybe short a few urbs? } else if (netif_running (dev->net) && netif_device_present (dev->net) && !timer_pending (&dev->delay) && !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; int qlen = RX_QLEN (dev); if (temp < qlen) { struct urb *urb; int i; // don't refill the queue all at once for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { urb = usb_alloc_urb (0, GFP_ATOMIC); if (urb != NULL) rx_submit (dev, urb, GFP_ATOMIC); } if (temp != dev->rxq.qlen && netif_msg_link (dev)) devdbg (dev, "rxqlen %d --> %d", temp, dev->rxq.qlen); if (dev->rxq.qlen < qlen) tasklet_schedule (&dev->bh); } if (dev->txq.qlen < TX_QLEN (dev)) netif_wake_queue (dev->net); } }
static irqreturn_t cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = dev_instance; struct cp_private *cp; u16 status; if (unlikely(dev == NULL)) return IRQ_NONE; cp = netdev_priv(dev); status = cpr16(IntrStatus); if (!status || (status == 0xFFFF)) return IRQ_NONE; if (netif_msg_intr(cp)) printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n", dev->name, status, cpr8(Cmd), cpr16(CpCmd)); cpw16(IntrStatus, status & ~cp_rx_intr_mask); spin_lock(&cp->lock); /* close possible race's with dev_close */ if (unlikely(!netif_running(dev))) { cpw16(IntrMask, 0); spin_unlock(&cp->lock); return IRQ_HANDLED; } if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) if (netif_rx_schedule_prep(dev)) { cpw16_f(IntrMask, cp_norx_intr_mask); __netif_rx_schedule(dev); } if (status & (TxOK | TxErr | TxEmpty | SWInt)) cp_tx(cp); if (status & LinkChg) mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE); spin_unlock(&cp->lock); if (status & PciErr) { u16 pci_status; pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status); pci_write_config_word(cp->pdev, PCI_STATUS, pci_status); printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n", dev->name, status, pci_status); /* TODO: reset hardware */ } return IRQ_HANDLED; }
static void tx_complete (struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; if (urb->status == 0) { dev->net->stats.tx_packets++; dev->net->stats.tx_bytes += entry->length; } else { dev->net->stats.tx_errors++; switch (urb->status) { case -EPIPE: usbnet_defer_kevent (dev, EVENT_TX_HALT); break; /* software-driven interface shutdown */ case -ECONNRESET: // async unlink case -ESHUTDOWN: // hardware gone break; // like rx, tx gets controller i/o faults during khubd delays // and so it uses the same throttling mechanism. case -EPROTO: case -ETIME: case -EILSEQ: #if defined(CONFIG_ERICSSON_F3307_ENABLE) usb_mark_last_busy(dev->udev); #endif if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); if (netif_msg_link (dev)) devdbg (dev, "tx throttle %d", urb->status); } netif_stop_queue (dev->net); break; default: if (netif_msg_tx_err (dev)) devdbg (dev, "tx err %d", entry->urb->status); break; } } #if defined(CONFIG_ERICSSON_F3307_ENABLE) usb_autopm_put_interface_async(dev->intf); #endif urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); }
static int net1080_reset(struct usbnet *dev) { u16 usbctl, status, ttl; u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL); int retval; if (!vp) return -ENOMEM; // nc_dump_registers(dev); if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) { dbg("can't read %s-%s status: %d", dev->udev->bus->bus_name, dev->udev->devpath, retval); goto done; } status = *vp; nc_dump_status(dev, status); if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) { dbg("can't read USBCTL, %d", retval); goto done; } usbctl = *vp; nc_dump_usbctl(dev, usbctl); nc_register_write(dev, REG_USBCTL, USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) { dbg("can't read TTL, %d", retval); goto done; } ttl = *vp; // nc_dump_ttl(dev, ttl); nc_register_write(dev, REG_TTL, MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS); if (netif_msg_link(dev)) devinfo(dev, "port %c, peer %sconnected", (status & STATUS_PORT_A) ? 'A' : 'B', (status & STATUS_CONN_OTHER) ? "" : "dis" ); retval = 0; done: kfree(vp); return retval; }
/* Start or stop link monitoring. If we want to be interrupted for a link state change, then we call this routine just once when turning on interrupt monitoring. For polling, this routine is called periodically every HX_LINK_TIMEOUT seconds and the one-shot timer is set for the next period. */ static int hxge_link_monitor(struct hxge_adapter *hxgep, int cmd) { if (netif_msg_link(hxgep)) { HXGE_DBG(hxgep, "hxge_link_monitor: cmd = %d",cmd); if (hxgep->link_monitor_state == LINK_MONITOR_DISABLED) { HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring disabled"); } else { HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring enabled"); } } hxgep->statsp->link_monitor_cnt++; switch (cmd) { case LINK_MONITOR_START: /* Assert an interrupt when link state changes. */ if (hxgep->link_mode == LINK_MODE_INTR) { if (hxge_link_intr(hxgep, cmd)) goto fail; /* Periodically poll for for state change */ } else if (hxgep->link_monitor_state == LINK_MONITOR_DISABLED) { hxgep->link_monitor_state = LINK_MONITOR_ENABLED; mod_timer (&hxgep->wd_timer, jiffies + HXGE_LINK_TIMEOUT); } HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring started"); break; case LINK_MONITOR_STOP: if (hxgep->link_mode == LINK_MODE_INTR) { if (hxge_link_intr(hxgep, cmd)) goto fail; } else if (hxgep->link_monitor_state == LINK_MONITOR_ENABLED) { hxgep->link_monitor_state = LINK_MONITOR_DISABLED; del_timer_sync(&hxgep->wd_timer); } HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring stopped"); break; default: HXGE_ERR(hxgep, "hxge_link_monitor: Unknown command"); break; } return 0; fail: HXGE_ERR(hxgep, "hxge_link_monitor: failed"); return -1; }
static void smc_phy_check_media(struct net_device *dev, int init) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { if (lp->mii.full_duplex) { lp->tcr_cur_mode |= TCR_SWFDUP; } else { lp->tcr_cur_mode &= ~TCR_SWFDUP; } SMC_SELECT_BANK(lp, 0); SMC_SET_TCR(lp, lp->tcr_cur_mode); } }
static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl) { if (!netif_msg_link(dev)) return; devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;" " this%s%s;" " other%s%s; r/o 0x%x", dev->udev->bus->bus_name, dev->udev->devpath, usbctl, (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", usbctl & ~USBCTL_WRITABLE_MASK ); }
static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) { int new_state = 0; if (pdata->phy.link) { /* Flow control support */ pdata->pause_autoneg = pdata->phy.pause_autoneg; if (pdata->tx_pause != pdata->phy.tx_pause) { new_state = 1; pdata->hw_if.config_tx_flow_control(pdata); pdata->tx_pause = pdata->phy.tx_pause; } if (pdata->rx_pause != pdata->phy.rx_pause) { new_state = 1; pdata->hw_if.config_rx_flow_control(pdata); pdata->rx_pause = pdata->phy.rx_pause; } /* Speed support */ if (pdata->phy_speed != pdata->phy.speed) { new_state = 1; pdata->phy_speed = pdata->phy.speed; } if (pdata->phy_link != pdata->phy.link) { new_state = 1; pdata->phy_link = pdata->phy.link; } } else if (pdata->phy_link) { new_state = 1; pdata->phy_link = 0; pdata->phy_speed = SPEED_UNKNOWN; } if (new_state && netif_msg_link(pdata)) xgbe_phy_print_status(pdata); }
static INT bcm_open(struct net_device *dev) { struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); if (Adapter->fw_download_done == false) { pr_notice(PFX "%s: link up failed (download in progress)\n", dev->name); return -EBUSY; } if (netif_msg_ifup(Adapter)) pr_info(PFX "%s: enabling interface\n", dev->name); if (Adapter->LinkUpStatus) { if (netif_msg_link(Adapter)) pr_info(PFX "%s: link up\n", dev->name); netif_carrier_on(Adapter->dev); netif_start_queue(Adapter->dev); } return 0; }
static void smc_10bt_check_media(struct net_device *dev, int init) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int old_carrier, new_carrier; old_carrier = netif_carrier_ok(dev) ? 1 : 0; SMC_SELECT_BANK(lp, 0); new_carrier = (SMC_GET_EPH_STATUS(lp) & ES_LINK_OK) ? 1 : 0; SMC_SELECT_BANK(lp, 2); if (init || (old_carrier != new_carrier)) { if (!new_carrier) { netif_carrier_off(dev); } else { netif_carrier_on(dev); } if (netif_msg_link(lp)) printk(KERN_INFO "%s: link %s\n", dev->name, new_carrier ? "up" : "down"); } }
/* PHY state control function */ static void sh_eth_adjust_link(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); struct phy_device *phydev = mdp->phydev; int new_state = 0; if (phydev->link != PHY_DOWN) { if (phydev->duplex != mdp->duplex) { new_state = 1; mdp->duplex = phydev->duplex; if (mdp->cd->set_duplex) mdp->cd->set_duplex(ndev); } if (phydev->speed != mdp->speed) { new_state = 1; mdp->speed = phydev->speed; if (mdp->cd->set_rate) mdp->cd->set_rate(ndev); } if (mdp->link == PHY_DOWN) { sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR); new_state = 1; mdp->link = phydev->link; } } else if (mdp->link) { new_state = 1; mdp->link = PHY_DOWN; mdp->speed = 0; mdp->duplex = -1; } if (new_state && netif_msg_link(mdp)) phy_print_status(phydev); }
static int mpodp_clean_tx_unlocked(struct mpodp_if_priv *priv, struct mpodp_txq *txq, unsigned budget) { struct net_device *netdev = priv->netdev; struct mpodp_tx *tx; unsigned int packets_completed = 0; unsigned int bytes_completed = 0; unsigned int worked = 0; union mppa_timestamp ts; uint32_t tx_done, first_tx_done, last_tx_done, tx_submitted, tx_size, tx_head; tx_submitted = atomic_read(&txq->submitted); tx_done = atomic_read(&txq->done); first_tx_done = tx_done; last_tx_done = first_tx_done; tx_size = txq->size; tx_head = atomic_read(&txq->head); if (!tx_head) { /* No carrier yet. Check if there are any buffers yet */ tx_head = readl(txq->head_addr); if (tx_head) { /* We now have buffers */ atomic_set(&txq->head, tx_head); if (netif_msg_link(priv)) netdev_info(netdev,"txq[%d] now has Tx (%u).\n", txq->id, tx_head); } return 0; } /* TX: 2nd step: update TX tail (DMA transfer completed) */ while (tx_done != tx_submitted && worked < budget) { if (!mpodp_tx_is_done(priv, txq, tx_done)) { /* DMA transfer not completed */ break; } if (netif_msg_tx_done(priv)) netdev_info(netdev, "txq[%d] tx[%d]: transfer done (head: %d submitted: %d done: %d)\n", txq->id, tx_done, atomic_read(&txq->head), tx_submitted, tx_done); /* get TX slot */ tx = &(txq->ring[tx_done]); /* free ressources */ unmap_skb(&priv->pdev->dev, tx->skb, tx); consume_skb(tx->skb); worked++; tx_done += 1; if (tx_done == tx_size) tx_done = 0; last_tx_done = tx_done; } /* write new TX tail */ atomic_set(&txq->done, tx_done); /* TX: 3rd step: free finished TX slot */ while (first_tx_done != last_tx_done) { if (netif_msg_tx_done(priv)) netdev_info(netdev, "txq[%d] tx[%d]: done (head: %d submitted: %d done: %d)\n", txq->id, first_tx_done, atomic_read(&txq->head), tx_submitted, tx_done); /* get TX slot */ tx = &(txq->ring[first_tx_done]); mppa_pcie_time_get(priv->tx_time, &ts); mppa_pcie_time_update(priv->tx_time, &tx->time, &ts); /* get stats */ packets_completed++; bytes_completed += tx->len; first_tx_done += 1; if (first_tx_done == tx_size) first_tx_done = 0; } if (!packets_completed) { goto out; } /* update stats */ netdev->stats.tx_bytes += bytes_completed; netdev->stats.tx_packets += packets_completed; netdev_tx_completed_queue(txq->txq, packets_completed, bytes_completed); netif_tx_wake_queue(txq->txq); out: return worked; }
static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; int retval = 0; unsigned long lockflags; size_t size = dev->rx_urb_size; #if defined(CONFIG_RA_HW_NAT_PCI) && (defined(CONFIG_RA_HW_NAT) || defined(CONFIG_RA_HW_NAT_MODULE)) if ((skb = alloc_skb (size + NET_IP_ALIGN + FOE_INFO_LEN, flags)) == NULL) { #else if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { #endif if (netif_msg_rx_err (dev)) devdbg (dev, "no rx skb"); usbnet_defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); return; } #if defined(CONFIG_RA_HW_NAT_PCI) && (defined(CONFIG_RA_HW_NAT) || defined(CONFIG_RA_HW_NAT_MODULE)) skb_reserve (skb, NET_IP_ALIGN + FOE_INFO_LEN); #else skb_reserve (skb, NET_IP_ALIGN); #endif entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; entry->length = 0; usb_fill_bulk_urb (urb, dev->udev, dev->in, skb->data, size, rx_complete, skb); spin_lock_irqsave (&dev->rxq.lock, lockflags); if (netif_running (dev->net) && netif_device_present (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ case -EPIPE: usbnet_defer_kevent (dev, EVENT_RX_HALT); break; case -ENOMEM: usbnet_defer_kevent (dev, EVENT_RX_MEMORY); break; case -ENODEV: if (netif_msg_ifdown (dev)) devdbg (dev, "device gone"); netif_device_detach (dev->net); break; default: if (netif_msg_rx_err (dev)) devdbg (dev, "rx submit, %d", retval); tasklet_schedule (&dev->bh); break; case 0: __usbnet_queue_skb(&dev->rxq, skb, rx_start); } } else { if (netif_msg_ifdown (dev)) devdbg (dev, "rx: stopped"); retval = -ENOLINK; } spin_unlock_irqrestore (&dev->rxq.lock, lockflags); if (retval) { dev_kfree_skb_any (skb); usb_free_urb (urb); } } /*-------------------------------------------------------------------------*/ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) { if (dev->driver_info->rx_fixup && !dev->driver_info->rx_fixup (dev, skb)) goto error; // else network stack removes extra byte if we forced a short packet if (skb->len) usbnet_skb_return (dev, skb); else { if (netif_msg_rx_err (dev)) devdbg (dev, "drop"); error: dev->stats.rx_errors++; skb_queue_tail (&dev->done, skb); } } /*-------------------------------------------------------------------------*/ static void rx_complete (struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; int urb_status = urb->status; enum skb_state state; skb_put (skb, urb->actual_length); state = rx_done; entry->urb = NULL; switch (urb_status) { // success case 0: if (skb->len < dev->net->hard_header_len) { state = rx_cleanup; dev->stats.rx_errors++; dev->stats.rx_length_errors++; if (netif_msg_rx_err (dev)) devdbg (dev, "rx length %d", skb->len); } break; // stalls need manual reset. this is rare ... except that // when going through USB 2.0 TTs, unplug appears this way. // we avoid the highspeed version of the ETIMEOUT/EILSEQ // storm, recovering as needed. case -EPIPE: dev->stats.rx_errors++; usbnet_defer_kevent (dev, EVENT_RX_HALT); // FALLTHROUGH // software-driven interface shutdown case -ECONNRESET: // async unlink case -ESHUTDOWN: // hardware gone if (netif_msg_ifdown (dev)) devdbg (dev, "rx shutdown, code %d", urb_status); goto block; // we get controller i/o faults during khubd disconnect() delays. // throttle down resubmits, to avoid log floods; just temporarily, // so we still recover when the fault isn't a khubd delay. case -EPROTO: case -ETIME: case -EILSEQ: dev->stats.rx_errors++; if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); if (netif_msg_link (dev)) devdbg (dev, "rx throttle %d", urb_status); } block: state = rx_cleanup; entry->urb = urb; urb = NULL; break; // data overrun ... flush fifo? case -EOVERFLOW: dev->stats.rx_over_errors++; // FALLTHROUGH default: state = rx_cleanup; dev->stats.rx_errors++; if (netif_msg_rx_err (dev)) devdbg (dev, "rx status %d", urb_status); break; } state = defer_bh(dev, skb, &dev->rxq, state); if (urb) { if (netif_running (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags) && state != unlink_start) { rx_submit (dev, urb, GFP_ATOMIC); return; } usb_free_urb (urb); } if (netif_msg_rx_err (dev)) devdbg (dev, "no read resubmitted"); } static void intr_complete (struct urb *urb) { struct usbnet *dev = urb->context; int status = urb->status; switch (status) { /* success */ case 0: dev->driver_info->status(dev, urb); break; /* software-driven interface shutdown */ case -ENOENT: // urb killed case -ESHUTDOWN: // hardware gone if (netif_msg_ifdown (dev)) devdbg (dev, "intr shutdown, code %d", status); return; /* NOTE: not throttling like RX/TX, since this endpoint * already polls infrequently */ default: devdbg (dev, "intr status %d", status); break; } memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); status = usb_submit_urb (urb, GFP_ATOMIC); if (status != 0 && netif_msg_timer (dev)) deverr(dev, "intr resubmit --> %d", status); } /*-------------------------------------------------------------------------*/ // unlink pending rx/tx; completion handlers do all other cleanup static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) { unsigned long flags; struct sk_buff *skb; int count = 0; spin_lock_irqsave (&q->lock, flags); while (!skb_queue_empty(q)) { struct skb_data *entry; struct urb *urb; int retval; skb_queue_walk(q, skb) { entry = (struct skb_data *) skb->cb; if (entry->state != unlink_start) goto found; } break; found: entry->state = unlink_start; urb = entry->urb; /* * Get reference count of the URB to avoid it to be * freed during usb_unlink_urb, which may trigger * use-after-free problem inside usb_unlink_urb since * usb_unlink_urb is always racing with .complete * handler(include defer_bh). */ usb_get_urb(urb); spin_unlock_irqrestore(&q->lock, flags); // during some PM-driven resume scenarios, // these (async) unlinks complete immediately retval = usb_unlink_urb (urb); if (retval != -EINPROGRESS && retval != 0) devdbg (dev, "unlink urb err, %d", retval); else count++; usb_put_urb(urb); spin_lock_irqsave(&q->lock, flags); }
static void kevent(void *data) { struct usbnet *dev = (struct usbnet *)data; #else static void kevent(struct work_struct *work) { struct usbnet *dev = container_of(work, struct usbnet, kevent); #endif int status; /* usb_clear_halt() needs a thread context */ if (test_bit(EVENT_TX_HALT, &dev->flags)) { unlink_urbs(dev, &dev->txq); status = usb_clear_halt(dev->udev, dev->out); if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) { if (netif_msg_tx_err(dev)) deverr(dev, "can't clear tx halt, status %d", status); } else { clear_bit(EVENT_TX_HALT, &dev->flags); if (status != -ESHUTDOWN) netif_wake_queue(dev->net); } } if (test_bit(EVENT_RX_HALT, &dev->flags)) { unlink_urbs(dev, &dev->rxq); status = usb_clear_halt(dev->udev, dev->in); if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) { if (netif_msg_rx_err(dev)) deverr(dev, "can't clear rx halt, status %d", status); } else { clear_bit(EVENT_RX_HALT, &dev->flags); tasklet_schedule(&dev->bh); } } /* tasklet could resubmit itself forever if memory is tight */ if (test_bit(EVENT_RX_MEMORY, &dev->flags)) { struct urb *urb = NULL; if (netif_running(dev->net)) urb = usb_alloc_urb(0, GFP_KERNEL); else clear_bit(EVENT_RX_MEMORY, &dev->flags); if (urb != NULL) { clear_bit(EVENT_RX_MEMORY, &dev->flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) urb->transfer_flags |= URB_ASYNC_UNLINK; #endif rx_submit(dev, urb, GFP_KERNEL); tasklet_schedule(&dev->bh); } } if (test_bit(EVENT_LINK_RESET, &dev->flags)) { struct driver_info *info = dev->driver_info; int retval = 0; clear_bit(EVENT_LINK_RESET, &dev->flags); if (info->link_reset) { retval = info->link_reset(dev); if (retval < 0) { devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", retval, dev->udev->bus->bus_name, dev->udev->devpath, info->description); } } } if (dev->flags) devdbg(dev, "kevent done, flags = 0x%lx", dev->flags); } /*-------------------------------------------------------------------------*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static void tx_complete(struct urb *urb, struct pt_regs *regs) #else static void tx_complete(struct urb *urb) #endif { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; if (urb->status == 0) { dev->stats.tx_packets++; dev->stats.tx_bytes += entry->length; } else { dev->stats.tx_errors++; switch (urb->status) { case -EPIPE: axusbnet_defer_kevent(dev, EVENT_TX_HALT); break; /* software-driven interface shutdown */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware gone */ break; /* like rx, tx gets controller i/o faults during khubd delays */ /* and so it uses the same throttling mechanism. */ case -EPROTO: case -ETIME: case -EILSEQ: if (!timer_pending(&dev->delay)) { mod_timer(&dev->delay, jiffies + THROTTLE_JIFFIES); if (netif_msg_link(dev)) devdbg(dev, "tx throttle %d", urb->status); } netif_stop_queue(dev->net); break; default: if (netif_msg_tx_err(dev)) devdbg(dev, "tx err %d", entry->urb->status); break; } } urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); } /*-------------------------------------------------------------------------*/ static void axusbnet_tx_timeout(struct net_device *net) { struct usbnet *dev = netdev_priv(net); unlink_urbs(dev, &dev->txq); tasklet_schedule(&dev->bh); /* FIXME: device recovery -- reset? */ } /*-------------------------------------------------------------------------*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) static int #else static netdev_tx_t #endif axusbnet_start_xmit(struct sk_buff *skb, struct net_device *net) { struct usbnet *dev = netdev_priv(net); int length; struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; int retval; /* some devices want funky USB-level framing, for */ /* win32 driver (usually) and/or hardware quirks */ if (info->tx_fixup) { skb = info->tx_fixup(dev, skb, GFP_ATOMIC); if (!skb) { if (netif_msg_tx_err(dev)) devdbg(dev, "can't tx_fixup skb"); goto drop; } } length = skb->len; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { if (netif_msg_tx_err(dev)) devdbg(dev, "no urb"); goto drop; } entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; entry->state = tx_start; entry->length = length; usb_fill_bulk_urb(urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); /* don't assume the hardware handles USB_ZERO_PACKET * NOTE: strictly conforming cdc-ether devices should expect * the ZLP here, but ignore the one-byte packet. */ if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) { urb->transfer_buffer_length++; if (skb_tailroom(skb)) { skb->data[skb->len] = 0; __skb_put(skb, 1); } } spin_lock_irqsave(&dev->txq.lock, flags); switch ((retval = usb_submit_urb(urb, GFP_ATOMIC))) { case -EPIPE: netif_stop_queue(net); axusbnet_defer_kevent(dev, EVENT_TX_HALT); break; default: if (netif_msg_tx_err(dev)) devdbg(dev, "tx: submit urb err %d", retval); break; case 0: net->trans_start = jiffies; __skb_queue_tail(&dev->txq, skb); if (dev->txq.qlen >= TX_QLEN(dev)) netif_stop_queue(net); } spin_unlock_irqrestore(&dev->txq.lock, flags); if (retval) { if (netif_msg_tx_err(dev)) devdbg(dev, "drop, code %d", retval); drop: dev->stats.tx_dropped++; if (skb) dev_kfree_skb_any(skb); usb_free_urb(urb); } else if (netif_msg_tx_queued(dev)) { devdbg(dev, "> tx, len %d, type 0x%x", length, skb->protocol); } return NETDEV_TX_OK; } /*-------------------------------------------------------------------------*/ /* tasklet (work deferred from completions, in_irq) or timer */ static void axusbnet_bh(unsigned long param) { struct usbnet *dev = (struct usbnet *) param; struct sk_buff *skb; struct skb_data *entry; while ((skb = skb_dequeue(&dev->done))) { entry = (struct skb_data *) skb->cb; switch (entry->state) { case rx_done: entry->state = rx_cleanup; rx_process(dev, skb); continue; case tx_done: case rx_cleanup: usb_free_urb(entry->urb); dev_kfree_skb(skb); continue; default: devdbg(dev, "bogus skb state %d", entry->state); } } /* waiting for all pending urbs to complete? */ if (dev->wait) { if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) wake_up(dev->wait); /* or are we maybe short a few urbs? */ } else if (netif_running(dev->net) && netif_device_present(dev->net) && !timer_pending(&dev->delay) && !test_bit(EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; int qlen = RX_QLEN(dev); if (temp < qlen) { struct urb *urb; int i; /* don't refill the queue all at once */ for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { urb = usb_alloc_urb(0, GFP_ATOMIC); if (urb != NULL) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) urb->transfer_flags |= URB_ASYNC_UNLINK; #endif rx_submit(dev, urb, GFP_ATOMIC); } } if (temp != dev->rxq.qlen && netif_msg_link(dev)) devdbg(dev, "rxqlen %d --> %d", temp, dev->rxq.qlen); if (dev->rxq.qlen < qlen) tasklet_schedule(&dev->bh); } if (dev->txq.qlen < TX_QLEN(dev)) netif_wake_queue(dev->net); } } /*------------------------------------------------------------------------- * * USB Device Driver support * *-------------------------------------------------------------------------*/ /* precondition: never called in_interrupt */ static void axusbnet_disconnect(struct usb_interface *intf) { struct usbnet *dev; struct usb_device *xdev; struct net_device *net; dev = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); if (!dev) return; xdev = interface_to_usbdev(intf); if (netif_msg_probe(dev)) devinfo(dev, "unregister '%s' usb-%s-%s, %s", intf->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); net = dev->net; unregister_netdev(net); /* we don't hold rtnl here ... */ flush_scheduled_work(); if (dev->driver_info->unbind) dev->driver_info->unbind(dev, intf); free_netdev(net); usb_put_dev(xdev); } /*-------------------------------------------------------------------------*/ /* precondition: never called in_interrupt */ static int axusbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod) { struct usbnet *dev; struct net_device *net; struct usb_host_interface *interface; struct driver_info *info; struct usb_device *xdev; int status; const char *name; name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; if (!info) { printk(KERN_ERR "blacklisted by %s\n", name); return -ENODEV; } xdev = interface_to_usbdev(udev); interface = udev->cur_altsetting; usb_get_dev(xdev); status = -ENOMEM; /* set up our own records */ net = alloc_etherdev(sizeof(*dev)); if (!net) { printk(KERN_ERR "can't kmalloc dev"); goto out; } dev = netdev_priv(net); dev->udev = xdev; dev->intf = udev; dev->driver_info = info; dev->driver_name = name; dev->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK); skb_queue_head_init(&dev->rxq); skb_queue_head_init(&dev->txq); skb_queue_head_init(&dev->done); dev->bh.func = axusbnet_bh; dev->bh.data = (unsigned long) dev; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&dev->kevent, kevent, dev); #else INIT_WORK(&dev->kevent, kevent); #endif dev->delay.function = axusbnet_bh; dev->delay.data = (unsigned long) dev; init_timer(&dev->delay); /* mutex_init(&dev->phy_mutex); */ dev->net = net; /* rx and tx sides can use different message sizes; * bind() should set rx_urb_size in that case. */ dev->hard_mtu = net->mtu + net->hard_header_len; #if 0 /* dma_supported() is deeply broken on almost all architectures */ /* possible with some EHCI controllers */ if (dma_supported(&udev->dev, DMA_BIT_MASK(64))) net->features |= NETIF_F_HIGHDMA; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) net->open = axusbnet_open, net->stop = axusbnet_stop, net->hard_start_xmit = axusbnet_start_xmit, net->tx_timeout = axusbnet_tx_timeout, net->get_stats = axusbnet_get_stats; #endif net->watchdog_timeo = TX_TIMEOUT_JIFFIES; net->ethtool_ops = &axusbnet_ethtool_ops; /* allow device-specific bind/init procedures */ /* NOTE net->name still not usable ... */ status = info->bind(dev, udev); if (status < 0) { deverr(dev, "Binding device failed: %d", status); goto out1; } /* maybe the remote can't receive an Ethernet MTU */ if (net->mtu > (dev->hard_mtu - net->hard_header_len)) net->mtu = dev->hard_mtu - net->hard_header_len; status = init_status(dev, udev); if (status < 0) goto out3; if (!dev->rx_urb_size) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); SET_NETDEV_DEV(net, &udev->dev); status = register_netdev(net); if (status) { deverr(dev, "net device registration failed: %d", status); goto out3; } if (netif_msg_probe(dev)) devinfo(dev, "register '%s' at usb-%s-%s, %s, %pM", udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, net->dev_addr); /* ok, it's ready to go. */ usb_set_intfdata(udev, dev); /* start as if the link is up */ netif_device_attach(net); return 0; out3: if (info->unbind) info->unbind(dev, udev); out1: free_netdev(net); out: usb_put_dev(xdev); return status; } /*-------------------------------------------------------------------------*/ /* * suspend the whole driver as soon as the first interface is suspended * resume only when the last interface is resumed */ static int axusbnet_suspend(struct usb_interface *intf, #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) pm_message_t message) #else u32 message) #endif { struct usbnet *dev = usb_get_intfdata(intf); if (!dev->suspend_count++) { /* * accelerate emptying of the rx and queues, to avoid * having everything error out. */ netif_device_detach(dev->net); (void) unlink_urbs(dev, &dev->rxq); (void) unlink_urbs(dev, &dev->txq); usb_kill_urb(dev->interrupt); /* * reattach so runtime management can use and * wake the device */ netif_device_attach(dev->net); } return 0; } static int axusbnet_resume(struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); int retval = 0; if (!--dev->suspend_count) tasklet_schedule(&dev->bh); retval = init_status(dev, intf); if (retval < 0) return retval; if (dev->interrupt) { retval = usb_submit_urb(dev->interrupt, GFP_KERNEL); if (retval < 0 && netif_msg_ifup(dev)) deverr(dev, "intr submit %d", retval); } return retval; }
static void rx_complete(struct urb *urb) #endif { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; int urb_status = urb->status; skb_put(skb, urb->actual_length); entry->state = rx_done; entry->urb = NULL; switch (urb_status) { /* success */ case 0: if (skb->len < dev->net->hard_header_len) { entry->state = rx_cleanup; dev->stats.rx_errors++; dev->stats.rx_length_errors++; if (netif_msg_rx_err(dev)) devdbg(dev, "rx length %d", skb->len); } break; /* stalls need manual reset. this is rare ... except that * when going through USB 2.0 TTs, unplug appears this way. * we avoid the highspeed version of the ETIMEDOUT/EILSEQ * storm, recovering as needed. */ case -EPIPE: dev->stats.rx_errors++; axusbnet_defer_kevent(dev, EVENT_RX_HALT); /* FALLTHROUGH */ /* software-driven interface shutdown */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware gone */ if (netif_msg_ifdown(dev)) devdbg(dev, "rx shutdown, code %d", urb_status); goto block; /* we get controller i/o faults during khubd disconnect() delays. * throttle down resubmits, to avoid log floods; just temporarily, * so we still recover when the fault isn't a khubd delay. */ case -EPROTO: case -ETIME: case -EILSEQ: dev->stats.rx_errors++; if (!timer_pending(&dev->delay)) { mod_timer(&dev->delay, jiffies + THROTTLE_JIFFIES); if (netif_msg_link(dev)) devdbg(dev, "rx throttle %d", urb_status); } block: entry->state = rx_cleanup; entry->urb = urb; urb = NULL; break; /* data overrun ... flush fifo? */ case -EOVERFLOW: dev->stats.rx_over_errors++; /* FALLTHROUGH */ default: entry->state = rx_cleanup; dev->stats.rx_errors++; if (netif_msg_rx_err(dev)) devdbg(dev, "rx status %d", urb_status); break; } defer_bh(dev, skb, &dev->rxq); if (urb) { if (netif_running(dev->net) && !test_bit(EVENT_RX_HALT, &dev->flags)) { rx_submit(dev, urb, GFP_ATOMIC); return; } usb_free_urb(urb); } if (netif_msg_rx_err(dev)) devdbg(dev, "no read resubmitted"); }
static void ag71xx_phy_link_update(struct ag71xx *ag) { u32 cfg2; u32 ifctl; u32 pll; u32 fifo5; u32 mii_speed; if (!ag->link) { netif_carrier_off(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link down\n", ag->dev->name); return; } cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0; ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); ifctl &= ~(MAC_IFCTL_SPEED); fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); fifo5 &= ~FIFO_CFG5_BYTE_PER_CLK; switch (ag->speed) { case SPEED_1000: mii_speed = MII_CTRL_SPEED_1000; cfg2 |= MAC_CFG2_IF_1000; pll = PLL_VAL_1000; fifo5 |= FIFO_CFG5_BYTE_PER_CLK; break; case SPEED_100: mii_speed = MII_CTRL_SPEED_100; cfg2 |= MAC_CFG2_IF_10_100; ifctl |= MAC_IFCTL_SPEED; pll = PLL_VAL_100; break; case SPEED_10: mii_speed = MII_CTRL_SPEED_10; cfg2 |= MAC_CFG2_IF_10_100; pll = PLL_VAL_10; break; default: BUG(); return; } ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff); ag71xx_set_pll(ag, pll); ag71xx_mii_ctrl_set_speed(ag, mii_speed); ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); netif_carrier_on(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n", ag->dev->name, ag71xx_speed_str(ag), (DUPLEX_FULL == ag->duplex) ? "Full" : "Half"); DBG("%s: fifo1=%#x, fifo2=%#x, fifo3=%#x, fifo4=%#x, fifo5=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5)); DBG("%s: mac_cfg2=%#x, ifctl=%#x, mii_ctrl=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_MAC_CFG2), ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL), ag71xx_mii_ctrl_rr(ag)); }
/** * stmmac_adjust_link * @dev: net device structure * Description: it adjusts the link parameters. */ static void stmmac_adjust_link(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phydev = priv->phydev; unsigned long flags; int new_state = 0; unsigned int fc = priv->flow_ctrl, pause_time = priv->pause; if (phydev == NULL) return; DBG(probe, DEBUG, "stmmac_adjust_link: called. address %d link %d\n", phydev->addr, phydev->link); spin_lock_irqsave(&priv->lock, flags); if (phydev->link) { u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG); /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ if (phydev->duplex != priv->oldduplex) { new_state = 1; if (!(phydev->duplex)) ctrl &= ~priv->hw->link.duplex; else ctrl |= priv->hw->link.duplex; priv->oldduplex = phydev->duplex; } /* Flow Control operation */ if (phydev->pause) priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex, fc, pause_time); if (phydev->speed != priv->speed) { new_state = 1; switch (phydev->speed) { case 1000: if (likely(priv->plat->has_gmac)) ctrl &= ~priv->hw->link.port; stmmac_hw_fix_mac_speed(priv); break; case 100: case 10: if (priv->plat->has_gmac) { ctrl |= priv->hw->link.port; if (phydev->speed == SPEED_100) { ctrl |= priv->hw->link.speed; } else { ctrl &= ~(priv->hw->link.speed); } } else { ctrl &= ~priv->hw->link.port; } stmmac_hw_fix_mac_speed(priv); break; default: if (netif_msg_link(priv)) pr_warning("%s: Speed (%d) is not 10" " or 100!\n", dev->name, phydev->speed); break; } priv->speed = phydev->speed; } writel(ctrl, priv->ioaddr + MAC_CTRL_REG); if (!priv->oldlink) { new_state = 1; priv->oldlink = 1; } } else if (priv->oldlink) { new_state = 1; priv->oldlink = 0; priv->speed = 0; priv->oldduplex = -1; } if (new_state && netif_msg_link(priv)) phy_print_status(phydev); spin_unlock_irqrestore(&priv->lock, flags); DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n"); }
static void tx_complete (struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; #ifdef TX_URB_MONITOR unsigned char b_usb_if_num = 0; int iRet = get_usb_interface(urb, &b_usb_if_num); #endif //#ifdef TX_URB_MONITOR if (urb->status == 0) { if (!(dev->driver_info->flags & FLAG_MULTI_PACKET)) dev->net->stats.tx_packets++; dev->net->stats.tx_bytes += entry->length; } else { dev->net->stats.tx_errors++; switch (urb->status) { case -EPIPE: usbnet_defer_kevent (dev, EVENT_TX_HALT); break; /* software-driven interface shutdown */ case -ECONNRESET: // async unlink case -ESHUTDOWN: // hardware gone break; // like rx, tx gets controller i/o faults during khubd delays // and so it uses the same throttling mechanism. case -EPROTO: case -ETIME: case -EILSEQ: if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); if (netif_msg_link (dev)) #if (LINUX_VERSION_CODE != KERNEL_VERSION( 3,0,6 )) devdbg (dev, "tx throttle %d", urb->status); #else netif_dbg(dev, link, dev->net, "tx throttle %d\n", urb->status); #endif } netif_stop_queue (dev->net); break; default: if (netif_msg_tx_err (dev)) #if (LINUX_VERSION_CODE != KERNEL_VERSION( 3,0,6 )) devdbg (dev, "tx err %d", entry->urb->status); #else netif_dbg(dev, tx_err, dev->net, "tx err %d\n", entry->urb->status); #endif break; } } usb_autopm_put_interface_async(dev->intf); urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); #ifdef TX_URB_MONITOR if ((URB_monitor) && (0==iRet)) { URB_monitor(false, b_usb_if_num); } #endif //#ifdef TX_URB_MONITOR }
void ag71xx_link_adjust(struct ag71xx *ag) { struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); u32 cfg2; u32 ifctl; u32 fifo5; u32 mii_speed; if (!ag->link) { netif_carrier_off(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link down\n", ag->dev->name); return; } cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0; ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); ifctl &= ~(MAC_IFCTL_SPEED); fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); fifo5 &= ~FIFO_CFG5_BM; switch (ag->speed) { case SPEED_1000: mii_speed = MII_CTRL_SPEED_1000; cfg2 |= MAC_CFG2_IF_1000; fifo5 |= FIFO_CFG5_BM; break; case SPEED_100: mii_speed = MII_CTRL_SPEED_100; cfg2 |= MAC_CFG2_IF_10_100; ifctl |= MAC_IFCTL_SPEED; break; case SPEED_10: mii_speed = MII_CTRL_SPEED_10; cfg2 |= MAC_CFG2_IF_10_100; break; default: BUG(); return; } if (pdata->is_ar91xx) ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff); else if (pdata->is_ar724x) ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3); else ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff); if (pdata->set_pll) pdata->set_pll(ag->speed); ag71xx_mii_ctrl_set_speed(ag, mii_speed); ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); netif_carrier_on(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n", ag->dev->name, ag71xx_speed_str(ag), (DUPLEX_FULL == ag->duplex) ? "Full" : "Half"); DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2)); DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5)); DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_MAC_CFG2), ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL), ag71xx_mii_ctrl_rr(ag)); }
static void tc_handle_link_change(struct net_device *dev) { struct tc35815_local *lp = netdev_priv(dev); struct phy_device *phydev = dev->phydev; unsigned long flags; int status_change = 0; spin_lock_irqsave(&lp->lock, flags); if (phydev->link && (lp->speed != phydev->speed || lp->duplex != phydev->duplex)) { struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; u32 reg; reg = tc_readl(&tr->MAC_Ctl); reg |= MAC_HaltReq; tc_writel(reg, &tr->MAC_Ctl); if (phydev->duplex == DUPLEX_FULL) reg |= MAC_FullDup; else reg &= ~MAC_FullDup; tc_writel(reg, &tr->MAC_Ctl); reg &= ~MAC_HaltReq; tc_writel(reg, &tr->MAC_Ctl); /* * TX4939 PCFG.SPEEDn bit will be changed on * NETDEV_CHANGE event. */ /* * WORKAROUND: enable LostCrS only if half duplex * operation. * (TX4939 does not have EnLCarr) */ if (phydev->duplex == DUPLEX_HALF && lp->chiptype != TC35815_TX4939) tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl); lp->speed = phydev->speed; lp->duplex = phydev->duplex; status_change = 1; } if (phydev->link != lp->link) { if (phydev->link) { /* delayed promiscuous enabling */ if (dev->flags & IFF_PROMISC) tc35815_set_multicast_list(dev); } else { lp->speed = 0; lp->duplex = -1; } lp->link = phydev->link; status_change = 1; } spin_unlock_irqrestore(&lp->lock, flags); if (status_change && netif_msg_link(lp)) { phy_print_status(phydev); pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n", dev->name, phy_read(phydev, MII_BMCR), phy_read(phydev, MII_BMSR), phy_read(phydev, MII_LPA)); } }