📄 de2104x.c
字号:
*/ if (de->media_type == DE_MEDIA_AUI) { u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO }; de_next_media(de, next_states, ARRAY_SIZE(next_states)); } else if (de->media_type == DE_MEDIA_BNC) { u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI }; de_next_media(de, next_states, ARRAY_SIZE(next_states)); } else { u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO }; de_next_media(de, next_states, ARRAY_SIZE(next_states)); } set_media: spin_lock_irqsave(&de->lock, flags); de_stop_rxtx(de); spin_unlock_irqrestore(&de->lock, flags); de_set_media(de); de_start_rxtx(de);no_link_yet: de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; add_timer(&de->media_timer); if (netif_msg_timer(de)) printk(KERN_INFO "%s: no link, trying media %s, status %x\n", dev->name, media_name[de->media_type], status);}static void de_media_interrupt (struct de_private *de, u32 status){ if (status & LinkPass) { de_link_up(de); mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK); return; } if (!(status & LinkFail)) BUG(); if (netif_carrier_ok(de->dev)) { de_link_down(de); mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK); }}static int de_reset_mac (struct de_private *de){ u32 status, tmp; /* * Reset MAC. Copied from de4x5.c. */ tmp = dr32 (BusMode); if (tmp == 0xffffffff) return -ENODEV; mdelay (1); dw32 (BusMode, tmp | CmdReset); mdelay (1); dw32 (BusMode, tmp); mdelay (1); for (tmp = 0; tmp < 5; tmp++) { dr32 (BusMode); mdelay (1); } mdelay (1); status = dr32(MacStatus); if (status & (RxState | TxState)) return -EBUSY; if (status == 0xffffffff) return -ENODEV; return 0;}static void de_adapter_wake (struct de_private *de){ u32 pmctl; if (de->de21040) return; pci_read_config_dword(de->pdev, PCIPM, &pmctl); if (pmctl & PM_Mask) { pmctl &= ~PM_Mask; pci_write_config_dword(de->pdev, PCIPM, pmctl); /* de4x5.c delays, so we do too */ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(msec_to_jiffies(10)); }}static void de_adapter_sleep (struct de_private *de){ u32 pmctl; if (de->de21040) return; pci_read_config_dword(de->pdev, PCIPM, &pmctl); pmctl |= PM_Sleep; pci_write_config_dword(de->pdev, PCIPM, pmctl);}static int de_init_hw (struct de_private *de){ struct net_device *dev = de->dev; int rc; de_adapter_wake(de); de->macmode = dr32(MacMode) & ~MacModeClear; rc = de_reset_mac(de); if (rc) return rc; de_set_media(de); /* reset phy */ dw32(RxRingAddr, de->ring_dma); dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE)); dw32(MacMode, RxTx | de->macmode); dr32(RxMissed); /* self-clearing */ dw32(IntrMask, de_intr_mask); de_set_rx_mode(dev); return 0;}static int de_refill_rx (struct de_private *de){ unsigned i; for (i = 0; i < DE_RX_RING_SIZE; i++) { struct sk_buff *skb; skb = dev_alloc_skb(de->rx_buf_sz); if (!skb) goto err_out; skb->dev = de->dev; de->rx_skb[i].mapping = pci_map_single(de->pdev, skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE); de->rx_skb[i].skb = skb; de->rx_ring[i].opts1 = cpu_to_le32(DescOwn); if (i == (DE_RX_RING_SIZE - 1)) de->rx_ring[i].opts2 = cpu_to_le32(RingEnd | de->rx_buf_sz); else de->rx_ring[i].opts2 = cpu_to_le32(de->rx_buf_sz); de->rx_ring[i].addr1 = cpu_to_le32(de->rx_skb[i].mapping); de->rx_ring[i].addr2 = 0; } return 0;err_out: de_clean_rings(de); return -ENOMEM;}static int de_init_rings (struct de_private *de){ memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE); de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd); de->rx_tail = 0; de->tx_head = de->tx_tail = 0; return de_refill_rx (de);}static int de_alloc_rings (struct de_private *de){ de->rx_ring = pci_alloc_consistent(de->pdev, DE_RING_BYTES, &de->ring_dma); if (!de->rx_ring) return -ENOMEM; de->tx_ring = &de->rx_ring[DE_RX_RING_SIZE]; return de_init_rings(de);}static void de_clean_rings (struct de_private *de){ unsigned i; memset(de->rx_ring, 0, sizeof(struct de_desc) * DE_RX_RING_SIZE); de->rx_ring[DE_RX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd); wmb(); memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE); de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd); wmb(); for (i = 0; i < DE_RX_RING_SIZE; i++) { if (de->rx_skb[i].skb) { pci_unmap_single(de->pdev, de->rx_skb[i].mapping, de->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(de->rx_skb[i].skb); } } for (i = 0; i < DE_TX_RING_SIZE; i++) { struct sk_buff *skb = de->tx_skb[i].skb; if ((skb) && (skb != DE_DUMMY_SKB)) { if (skb != DE_SETUP_SKB) { dev_kfree_skb(skb); de->net_stats.tx_dropped++; pci_unmap_single(de->pdev, de->tx_skb[i].mapping, skb->len, PCI_DMA_TODEVICE); } else { pci_unmap_single(de->pdev, de->tx_skb[i].mapping, sizeof(de->setup_frame), PCI_DMA_TODEVICE); } } } memset(&de->rx_skb, 0, sizeof(struct ring_info) * DE_RX_RING_SIZE); memset(&de->tx_skb, 0, sizeof(struct ring_info) * DE_TX_RING_SIZE);}static void de_free_rings (struct de_private *de){ de_clean_rings(de); pci_free_consistent(de->pdev, DE_RING_BYTES, de->rx_ring, de->ring_dma); de->rx_ring = NULL; de->tx_ring = NULL;}static int de_open (struct net_device *dev){ struct de_private *de = dev->priv; int rc; unsigned long flags; if (netif_msg_ifup(de)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); rc = de_alloc_rings(de); if (rc) { printk(KERN_ERR "%s: ring allocation failure, err=%d\n", dev->name, rc); return rc; } rc = de_init_hw(de); if (rc) { printk(KERN_ERR "%s: h/w init failure, err=%d\n", dev->name, rc); goto err_out_free; } rc = request_irq(dev->irq, de_interrupt, SA_SHIRQ, dev->name, dev); if (rc) { printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n", dev->name, dev->irq, rc); goto err_out_hw; } netif_start_queue(dev); mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK); return 0;err_out_hw: spin_lock_irqsave(&de->lock, flags); de_stop_hw(de); spin_unlock_irqrestore(&de->lock, flags);err_out_free: de_free_rings(de); return rc;}static int de_close (struct net_device *dev){ struct de_private *de = dev->priv; unsigned long flags; if (netif_msg_ifdown(de)) printk(KERN_DEBUG "%s: disabling interface\n", dev->name); del_timer_sync(&de->media_timer); spin_lock_irqsave(&de->lock, flags); de_stop_hw(de); netif_stop_queue(dev); netif_carrier_off(dev); spin_unlock_irqrestore(&de->lock, flags); free_irq(dev->irq, dev); de_free_rings(de); de_adapter_sleep(de); pci_disable_device(de->pdev); return 0;}static void de_tx_timeout (struct net_device *dev){ struct de_private *de = dev->priv; printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), de->rx_tail, de->tx_head, de->tx_tail); del_timer_sync(&de->media_timer); disable_irq(dev->irq); spin_lock_irq(&de->lock); de_stop_hw(de); netif_stop_queue(dev); netif_carrier_off(dev); spin_unlock_irq(&de->lock); enable_irq(dev->irq); /* Update the error counts. */ __de_get_stats(de); synchronize_irq(); de_clean_rings(de); de_init_hw(de); netif_wake_queue(dev);}static int de_get_regs(struct de_private *de, u8 *buf){ int i; u32 *rbuf = (u32 *)buf; /* read all CSRs */ for (i = 0; i < DE_NUM_REGS; i++) rbuf[i] = dr32(i * 8); /* handle self-clearing RxMissed counter, CSR8 */ de_rx_missed(de, rbuf[8]); return 0;}static int de_ethtool_gset(struct de_private *de, struct ethtool_cmd *ecmd){ ecmd->supported = de->media_supported; ecmd->transceiver = XCVR_INTERNAL; ecmd->phy_address = 0; ecmd->advertising = de->media_advertise; switch (de->media_type) { case DE_MEDIA_AUI: ecmd->port = PORT_AUI; ecmd->speed = 5; break; case DE_MEDIA_BNC: ecmd->port = PORT_BNC; ecmd->speed = 2; break; default: ecmd->port = PORT_TP; ecmd->speed = SPEED_10; break; } if (de->macmode & FullDuplex) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; if (de->media_lock) ecmd->autoneg = AUTONEG_DISABLE; else ecmd->autoneg = AUTONEG_ENABLE; /* ignore maxtxpkt, maxrxpkt for now */ return 0;}static int de_ethtool_sset(struct de_private *de, struct ethtool_cmd *ecmd){ u32 new_media; unsigned int media_lock; if (ecmd->speed != SPEED_10 && ecmd->speed != 5 && ecmd->speed != 2) return -EINVAL; if (de->de21040 && ecmd->speed == 2) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI && ecmd->port != PORT_BNC) return -EINVAL; if (de->de21040 && ecmd->port == PORT_BNC) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; if (ecmd->advertising & ~de->media_supported) return -EINVAL; if (ecmd->autoneg == AUTONEG_ENABLE && (!(ecmd->advertising & ADVERTISED_Autoneg))) return -EINVAL; switch (ecmd->port) { case PORT_AUI: new_media = DE_MEDIA_AUI; if (!(ecmd->advertising & ADVERTISED_AUI)) return -EINVAL; break; case PORT_BNC: new_media = DE_MEDIA_BNC; if (!(ecmd->advertising & ADVERTISED_BNC)) return -EINVAL; break; default: if (ecmd->autoneg == AUTONEG_ENABLE) new_media = DE_MEDIA_TP_AUTO; else if (ecmd->duplex == DUPLEX_FULL) new_media = DE_MEDIA_TP_FD; else new_media = DE_MEDIA_TP; if (!(ecmd->advertising & ADVERTISED_TP)) return -EINVAL; if (!(ecmd->advertising & (ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half))) return -EINVAL; break; } media_lock = (ecmd->autoneg == AUTONEG_ENABLE) ? 0 : 1; if ((new_media == de->media_type) && (media_lock == de->media_lock) && (ecmd->advertising == de->media_advertise)) return 0; /* nothing to change */ de_link_down(de); de_stop_rxtx(de); de->media_type = new_media; de->media_lock = media_lock; de->media_advertise = ecmd->advertising; de_set_media(de); return 0;}static int de_ethtool_ioctl (struct de_private *de, void *useraddr){ u32 ethcmd; /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ if (get_user(ethcmd, (u32 *)useraddr)) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); strcpy (info.bus_info, de->pdev->slot_name); info.eedump_len = DE_EEPROM_SIZE; info.regdump_len = DE_REGS_SIZE; if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; return 0; } /* get settings */ case ETHTOOL_GSET: { struct ethtool_cmd ecmd = { ETHTOOL_GSET }; spin_lock_irq(&de->lock); de_ethtool_gset(de, &ecmd); spin_unlock_irq(&de->lock); if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; } /* set settings */ case ETHTOOL_SSET: { struct ethtool_cmd ecmd; int r; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; spin_lock_irq(&de->lock); r = de_ethtool_sset(de, &ecmd); spin_unlock_irq(&de->lock); return r; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { u32 status; if (de->media_type != DE_MEDIA_TP_AUTO) return -EINVAL; if (netif_carrier_ok(de->dev)) de_link_down(de); status = dr32(SIAStatus); dw32(SIAStatus, (status & ~NWayState) | NWayRestart); if (netif_msg_link(de)) printk(KERN_INFO "%s: link nway restart, status %x,%x\n", de->dev->name, status, dr32(SIAStatus)); return 0; } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = (netif_carrier_ok(de->dev)) ? 1 : 0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; edata.data = de->msg_enable; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* set message-level */ case ETHTOOL_SMSGLVL: { struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; de->msg_enable = edata.data; return 0; } /* get registers */ case ETHTOOL_GREGS: { struct ethtool_regs regs; u8 regbuf[DE_REGS_SIZE]; int r; if (copy_from_user(®s, useraddr, sizeof(regs))) return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -