tc35815.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,746 行 · 第 1/4 页
C
1,746 行
int tfd_end; struct RxFD *rfd_base; struct RxFD *rfd_limit; struct RxFD *rfd_cur; struct FrFD *fbl_ptr; unsigned char fbl_curid; dma_addr_t data_buf_dma_handle[RX_BUF_PAGES]; void * data_buf[RX_BUF_PAGES]; /* packing */ spinlock_t lock;};/* Index to functions, as function prototypes. */static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);static int tc35815_open(struct net_device *dev);static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);static void tc35815_tx_timeout(struct net_device *dev);static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void tc35815_rx(struct net_device *dev);static 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_chip_reset(struct net_device *dev);static void tc35815_chip_init(struct net_device *dev);static void tc35815_phy_chip_init(struct net_device *dev);/* A list of all installed tc35815 devices. */static struct net_device *root_tc35815_dev = NULL;/* * PCI device identifiers for "new style" Linux PCI Device Drivers */static struct pci_device_id tc35815_pci_tbl[] = { { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, }};MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);inttc35815_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ int err = 0; int ret; unsigned long pci_memaddr; unsigned int pci_irq_line; printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); err = pci_enable_device(pdev); if (err) return err; pci_memaddr = pci_resource_start (pdev, 1); printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); if (!pci_memaddr) { printk(KERN_WARNING "no PCI MEM resources, aborting\n"); ret = -ENODEV; goto err_out; } pci_irq_line = pdev->irq; /* irq disabled. */ if (pci_irq_line == 0) { printk(KERN_WARNING "no PCI irq, aborting\n"); ret = -ENODEV; goto err_out; } ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); if (ret) goto err_out; pci_set_master(pdev); return 0;err_out: pci_disable_device(pdev); return ret;}static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq){ static unsigned version_printed = 0; int i, ret; struct tc35815_local *lp; struct tc35815_regs *tr; struct net_device *dev; /* Allocate a new 'dev' if needed. */ dev = alloc_etherdev(sizeof(struct tc35815_local)); if (dev == NULL) return -ENOMEM; /* * alloc_etherdev allocs and zeros dev->priv */ lp = dev->priv; if (tc35815_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); /* Fill in the 'dev' fields. */ dev->irq = irq; dev->base_addr = (unsigned long)ioremap(base_addr, sizeof(struct tc35815_regs)); if (!dev->base_addr) { ret = -ENOMEM; goto err_out; } tr = (struct tc35815_regs*)dev->base_addr; tc35815_chip_reset(dev); /* Retrieve and print the ethernet address. */ 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; } /* Initialize the device structure. */ lp->pdev = pdev; lp->next_module = root_tc35815_dev; root_tc35815_dev = dev; spin_lock_init(&lp->lock); if (dev->mem_start > 0) { lp->option = dev->mem_start; if ((lp->option & TC35815_OPT_10M) && (lp->option & TC35815_OPT_100M)) { /* if both speed speficied, auto select. */ lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M); } } //XXX fixme lp->option |= TC35815_OPT_10M; /* do auto negotiation */ tc35815_phy_chip_init(dev); dev->open = tc35815_open; dev->stop = tc35815_close; dev->tx_timeout = tc35815_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->hard_start_xmit = tc35815_send_packet; dev->get_stats = tc35815_get_stats; dev->set_multicast_list = tc35815_set_multicast_list; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); ret = register_netdev(dev); if (ret) goto err_out_iounmap; printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", dev->name, cardname, base_addr, irq); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i]); printk("\n"); printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); return 0;err_out_iounmap: iounmap((void *) dev->base_addr);err_out: free_netdev(dev); return ret;}static inttc35815_init_queues(struct net_device *dev){ struct tc35815_local *lp = dev->priv; int i; unsigned long fd_addr; if (!lp->fd_buf) { if (sizeof(struct FDesc) + sizeof(struct BDesc) * RX_BUF_PAGES + sizeof(struct FDesc) * RX_FD_NUM + sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) { printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name); return -ENOMEM; } if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0) return -ENOMEM; for (i = 0; i < RX_BUF_PAGES; i++) { if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) { while (--i >= 0) { free_page((unsigned long)lp->data_buf[i]); lp->data_buf[i] = 0; } free_page((unsigned long)lp->fd_buf); lp->fd_buf = 0; return -ENOMEM; }#ifdef __mips__ dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);#endif }#ifdef __mips__ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);#endif } else { clear_page(lp->fd_buf);#ifdef __mips__ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);#endif }#ifdef __mips__ fd_addr = (unsigned long)vtonocache(lp->fd_buf); #else fd_addr = (unsigned long)lp->fd_buf;#endif /* Free Descriptors (for Receive) */ lp->rfd_base = (struct RxFD *)fd_addr; fd_addr += sizeof(struct RxFD) * RX_FD_NUM; for (i = 0; i < RX_FD_NUM; i++) { lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); } lp->rfd_cur = lp->rfd_base; lp->rfd_limit = (struct RxFD *)(fd_addr - sizeof(struct FDesc) - sizeof(struct BDesc) * 30); /* Transmit Descriptors */ lp->tfd_base = (struct TxFD *)fd_addr; fd_addr += sizeof(struct TxFD) * TX_FD_NUM; for (i = 0; i < TX_FD_NUM; i++) { lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1])); lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); } lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0])); lp->tfd_start = 0; lp->tfd_end = 0; /* Buffer List (for Receive) */ lp->fbl_ptr = (struct FrFD *)fd_addr; lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr)); lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD); for (i = 0; i < RX_BUF_PAGES; i++) { lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i])); /* BDID is index of FrFD.bd[] */ lp->fbl_ptr->bd[i].BDCtl = cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE); } lp->fbl_curid = 0; return 0;}static voidtc35815_clear_queues(struct net_device *dev){ struct tc35815_local *lp = dev->priv; int i; for (i = 0; i < TX_FD_NUM; i++) { struct sk_buff *skb = (struct sk_buff *) le32_to_cpu(lp->tfd_base[i].fd.FDSystem); if (skb) dev_kfree_skb_any(skb); lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); } tc35815_init_queues(dev);}static voidtc35815_free_queues(struct net_device *dev){ struct tc35815_local *lp = dev->priv; int i; if (lp->tfd_base) { for (i = 0; i < TX_FD_NUM; i++) { struct sk_buff *skb = (struct sk_buff *) le32_to_cpu(lp->tfd_base[i].fd.FDSystem); if (skb) dev_kfree_skb_any(skb); lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); } } lp->rfd_base = NULL; lp->rfd_base = NULL; lp->rfd_limit = NULL; lp->rfd_cur = NULL; lp->fbl_ptr = NULL; for (i = 0; i < RX_BUF_PAGES; i++) { if (lp->data_buf[i]) free_page((unsigned long)lp->data_buf[i]); lp->data_buf[i] = 0; } if (lp->fd_buf) __free_pages(lp->fd_buf, FD_PAGE_ORDER); lp->fd_buf = NULL;}static voiddump_txfd(struct TxFD *fd){ printk("TxFD(%p): %08x %08x %08x %08x\n", fd, le32_to_cpu(fd->fd.FDNext), le32_to_cpu(fd->fd.FDSystem), le32_to_cpu(fd->fd.FDStat), le32_to_cpu(fd->fd.FDCtl)); printk("BD: "); printk(" %08x %08x", le32_to_cpu(fd->bd.BuffData), le32_to_cpu(fd->bd.BDCtl)); printk("\n");}static intdump_rxfd(struct RxFD *fd){ int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; if (bd_count > 8) bd_count = 8; printk("RxFD(%p): %08x %08x %08x %08x\n", fd, le32_to_cpu(fd->fd.FDNext), le32_to_cpu(fd->fd.FDSystem), le32_to_cpu(fd->fd.FDStat), le32_to_cpu(fd->fd.FDCtl)); if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD) return 0; printk("BD: "); for (i = 0; i < bd_count; i++) printk(" %08x %08x", le32_to_cpu(fd->bd[i].BuffData), le32_to_cpu(fd->bd[i].BDCtl)); printk("\n"); return bd_count;}static voiddump_frfd(struct FrFD *fd){ int i; printk("FrFD(%p): %08x %08x %08x %08x\n", fd, le32_to_cpu(fd->fd.FDNext), le32_to_cpu(fd->fd.FDSystem), le32_to_cpu(fd->fd.FDStat), le32_to_cpu(fd->fd.FDCtl)); printk("BD: "); for (i = 0; i < RX_BUF_PAGES; i++) printk(" %08x %08x", le32_to_cpu(fd->bd[i].BuffData), le32_to_cpu(fd->bd[i].BDCtl)); printk("\n");}static voidpanic_queues(struct net_device *dev){ struct tc35815_local *lp = dev->priv; int i; printk("TxFD base %p, start %d, end %d\n", lp->tfd_base, lp->tfd_start, lp->tfd_end); printk("RxFD base %p limit %p cur %p\n", lp->rfd_base, lp->rfd_limit, lp->rfd_cur); printk("FrFD %p\n", lp->fbl_ptr); for (i = 0; i < TX_FD_NUM; i++) dump_txfd(&lp->tfd_base[i]); for (i = 0; i < RX_FD_NUM; i++) { int bd_count = dump_rxfd(&lp->rfd_base[i]); i += (bd_count + 1) / 2; /* skip BDs */ } dump_frfd(lp->fbl_ptr); panic("%s: Illegal queue state.", dev->name);}#if 0static void print_buf(char *add, int length){ int i; int len = length; printk("print_buf(%08x)(%x)\n", (unsigned int) add,length); if (len > 100) len = 100; for (i = 0; i < len; i++) { printk(" %2.2X", (unsigned char) add[i]); if (!(i % 16)) printk("\n"); } printk("\n");}#endifstatic void print_eth(char *add){ int i; printk("print_eth(%08x)\n", (unsigned int) add); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char) add[i + 6]); printk(" =>"); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char) add[i]); printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);}/* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */static inttc35815_open(struct net_device *dev)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?