📄 tc35815.c
字号:
/* Tx control lock. This protects the transmit buffer ring * state along with the "tx full" state of the driver. This * means all netif_queue flow control actions are protected * by this lock as well. */ spinlock_t lock; int phy_addr; int fullduplex; unsigned short saved_lpa; struct timer_list timer; enum tc35815_timer_state timer_state; /* State of auto-neg timer. */ unsigned int timer_ticks; /* Number of clicks at each state */ /* * Transmitting: Batch Mode. * 1 BD in 1 TxFD. * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER) * 1 circular FD for Free Buffer List. * RX_BUF_NUM BD in Free Buffer FD. * One Free Buffer BD has PAGE_SIZE data buffer. * Or Non-Packing Mode. * 1 circular FD for Free Buffer List. * RX_BUF_NUM BD in Free Buffer FD. * One Free Buffer BD has ETH_FRAME_LEN data buffer. */ void * fd_buf; /* for TxFD, RxFD, FrFD */ dma_addr_t fd_buf_dma; struct TxFD *tfd_base; unsigned int tfd_start; unsigned int tfd_end; struct RxFD *rfd_base; struct RxFD *rfd_limit; struct RxFD *rfd_cur; struct FrFD *fbl_ptr;#ifdef TC35815_USE_PACKEDBUFFER unsigned char fbl_curid; void * data_buf[RX_BUF_NUM]; /* packing */ dma_addr_t data_buf_dma[RX_BUF_NUM]; struct { struct sk_buff *skb; dma_addr_t skb_dma; } tx_skbs[TX_FD_NUM];#else unsigned int fbl_count; struct { struct sk_buff *skb; dma_addr_t skb_dma; } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];#endif struct mii_if_info mii; unsigned short mii_id[2]; u32 msg_enable; board_t boardtype;};static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt){ return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);}#ifdef DEBUGstatic inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus){ return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));}#endif#ifdef TC35815_USE_PACKEDBUFFERstatic inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus){ int i; for (i = 0; i < RX_BUF_NUM; i++) { if (bus >= lp->data_buf_dma[i] && bus < lp->data_buf_dma[i] + PAGE_SIZE) return (void *)((u8 *)lp->data_buf[i] + (bus - lp->data_buf_dma[i])); } return NULL;}#define TC35815_DMA_SYNC_ONDEMANDstatic void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle){#ifdef TC35815_DMA_SYNC_ONDEMAND void *buf; /* pci_map + pci_dma_sync will be more effective than * pci_alloc_consistent on some archs. */ if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL) return NULL; *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(*dma_handle)) { free_page((unsigned long)buf); return NULL; } return buf;#else return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);#endif}static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle){#ifdef TC35815_DMA_SYNC_ONDEMAND pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE); free_page((unsigned long)buf);#else pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);#endif}#else /* TC35815_USE_PACKEDBUFFER */static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, struct pci_dev *hwdev, dma_addr_t *dma_handle){ struct sk_buff *skb; skb = dev_alloc_skb(RX_BUF_SIZE); if (!skb) return NULL; *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(*dma_handle)) { dev_kfree_skb_any(skb); return NULL; } skb_reserve(skb, 2); /* make IP header 4byte aligned */ return skb;}static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle){ pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb);}#endif /* TC35815_USE_PACKEDBUFFER *//* Index to functions, as function prototypes. */static int tc35815_open(struct net_device *dev);static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);static irqreturn_t tc35815_interrupt(int irq, void *dev_id);#ifdef TC35815_NAPIstatic int tc35815_rx(struct net_device *dev, int limit);static int tc35815_poll(struct napi_struct *napi, int budget);#elsestatic void tc35815_rx(struct net_device *dev);#endifstatic void tc35815_txdone(struct net_device *dev);static int tc35815_close(struct net_device *dev);static struct net_device_stats *tc35815_get_stats(struct net_device *dev);static void tc35815_set_multicast_list(struct net_device *dev);static void tc35815_tx_timeout(struct net_device *dev);static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);#ifdef CONFIG_NET_POLL_CONTROLLERstatic void tc35815_poll_controller(struct net_device *dev);#endifstatic const struct ethtool_ops tc35815_ethtool_ops;/* Example routines you must write ;->. */static void tc35815_chip_reset(struct net_device *dev);static void tc35815_chip_init(struct net_device *dev);static void tc35815_find_phy(struct net_device *dev);static void tc35815_phy_chip_init(struct net_device *dev);#ifdef DEBUGstatic void panic_queues(struct net_device *dev);#endifstatic void tc35815_timer(unsigned long data);static void tc35815_start_auto_negotiation(struct net_device *dev, struct ethtool_cmd *ep);static int tc_mdio_read(struct net_device *dev, int phy_id, int location);static void tc_mdio_write(struct net_device *dev, int phy_id, int location, int val);#ifdef CONFIG_CPU_TX49XX/* * Find a platform_device providing a MAC address. The platform code * should provide a "tc35815-mac" device with a MAC address in its * platform_data. */static int __devinit tc35815_mac_match(struct device *dev, void *data){ struct platform_device *plat_dev = to_platform_device(dev); struct pci_dev *pci_dev = data; unsigned int id = pci_dev->irq; return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;}static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev){ struct tc35815_local *lp = dev->priv; struct device *pd = bus_find_device(&platform_bus_type, NULL, lp->pci_dev, tc35815_mac_match); if (pd) { if (pd->platform_data) memcpy(dev->dev_addr, pd->platform_data, ETH_ALEN); put_device(pd); return is_valid_ether_addr(dev->dev_addr) ? 0 : -ENODEV; } return -ENODEV;}#elsestatic int __devinit tc35815_read_plat_dev_addr(struct net_device *dev){ return -ENODEV;}#endifstatic int __devinit tc35815_init_dev_addr (struct net_device *dev){ struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; int i; while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) ; for (i = 0; i < 6; i += 2) { unsigned short data; tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) ; data = tc_readl(&tr->PROM_Data); dev->dev_addr[i] = data & 0xff; dev->dev_addr[i+1] = data >> 8; } if (!is_valid_ether_addr(dev->dev_addr)) return tc35815_read_plat_dev_addr(dev); return 0;}static int __devinit tc35815_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ void __iomem *ioaddr = NULL; struct net_device *dev; struct tc35815_local *lp; int rc; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; static int printed_version; if (!printed_version++) { printk(version); dev_printk(KERN_DEBUG, &pdev->dev, "speed:%d duplex:%d doforce:%d\n", options.speed, options.duplex, options.doforce); } if (!pdev->irq) { dev_warn(&pdev->dev, "no IRQ assigned.\n"); return -ENODEV; } /* dev zeroed in alloc_etherdev */ dev = alloc_etherdev (sizeof (*lp)); if (dev == NULL) { dev_err(&pdev->dev, "unable to alloc new ethernet\n"); return -ENOMEM; } SET_NETDEV_DEV(dev, &pdev->dev); lp = dev->priv; lp->dev = dev; /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device (pdev); if (rc) goto err_out; mmio_start = pci_resource_start (pdev, 1); mmio_end = pci_resource_end (pdev, 1); mmio_flags = pci_resource_flags (pdev, 1); mmio_len = pci_resource_len (pdev, 1); /* set this immediately, we need to know before * we talk to the chip directly */ /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; goto err_out; } /* check for weird/broken PCI region reporting */ if ((mmio_len < sizeof(struct tc35815_regs))) { dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; goto err_out; } rc = pci_request_regions (pdev, MODNAME); if (rc) goto err_out; pci_set_master (pdev); /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out_free_res; } /* Initialize the device structure. */ dev->open = tc35815_open; dev->hard_start_xmit = tc35815_send_packet; dev->stop = tc35815_close; dev->get_stats = tc35815_get_stats; dev->set_multicast_list = tc35815_set_multicast_list; dev->do_ioctl = tc35815_ioctl; dev->ethtool_ops = &tc35815_ethtool_ops; dev->tx_timeout = tc35815_tx_timeout; dev->watchdog_timeo = TC35815_TX_TIMEOUT;#ifdef TC35815_NAPI netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);#endif#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = tc35815_poll_controller;#endif dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; spin_lock_init(&lp->lock); lp->pci_dev = pdev; lp->boardtype = ent->driver_data; lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK; pci_set_drvdata(pdev, dev); /* Soft reset the chip. */ tc35815_chip_reset(dev); /* Retrieve the ethernet address. */ if (tc35815_init_dev_addr(dev)) { dev_warn(&pdev->dev, "not valid ether addr\n"); random_ether_addr(dev->dev_addr); } rc = register_netdev (dev); if (rc) goto err_out_unmap; memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); printk(KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev); lp->mii.dev = dev; lp->mii.mdio_read = tc_mdio_read; lp->mii.mdio_write = tc_mdio_write; lp->mii.phy_id_mask = 0x1f; lp->mii.reg_num_mask = 0x1f; tc35815_find_phy(dev); lp->mii.phy_id = lp->phy_addr; lp->mii.full_duplex = 0; lp->mii.force_media = 0; return 0;err_out_unmap: iounmap(ioaddr);err_out_free_res: pci_release_regions (pdev);err_out: free_netdev (dev); return rc;}static void __devexit tc35815_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata (pdev); unsigned long mmio_addr; mmio_addr = dev->base_addr; unregister_netdev (dev); if (mmio_addr) { iounmap ((void __iomem *)mmio_addr); pci_release_regions (pdev); } free_netdev (dev); pci_set_drvdata (pdev, NULL);}static inttc35815_init_queues(struct net_device *dev){ struct tc35815_local *lp = dev->priv; int i; unsigned long fd_addr; if (!lp->fd_buf) { BUG_ON(sizeof(struct FDesc) + sizeof(struct BDesc) * RX_BUF_NUM + sizeof(struct FDesc) * RX_FD_NUM + sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM); if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0) return -ENOMEM; for (i = 0; i < RX_BUF_NUM; i++) {#ifdef TC35815_USE_PACKEDBUFFER if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) { while (--i >= 0) { free_rxbuf_page(lp->pci_dev, lp->data_buf[i], lp->data_buf_dma[i]); lp->data_buf[i] = NULL; } pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, lp->fd_buf,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -