📄 fealnx.c
字号:
static int printed_version; if (!printed_version++) printk (version);#endif card_idx++; sprintf(boardname, "fealnx%d", card_idx); option = card_idx < MAX_UNITS ? options[card_idx] : 0; i = pci_enable_device(pdev); if (i) return i; pci_set_master(pdev); #ifdef USE_IO_OPS ioaddr = pci_resource_len(pdev, 0);#else ioaddr = pci_resource_len(pdev, 1);#endif if (ioaddr < MIN_REGION_SIZE) { printk(KERN_ERR "%s: region size %ld too small, aborting\n", boardname, ioaddr); return -ENODEV; } i = pci_request_regions(pdev, boardname); if (i) return i; irq = pdev->irq;#ifdef USE_IO_OPS ioaddr = pci_resource_start(pdev, 0);#else ioaddr = (long) ioremap(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); if (!ioaddr) { err = -ENOMEM; goto err_out_res; }#endif dev = alloc_etherdev(sizeof(struct netdev_private)); if (!dev) { err = -ENOMEM; goto err_out_unmap; } SET_MODULE_OWNER(dev); /* read ethernet id */ for (i = 0; i < 6; ++i) dev->dev_addr[i] = readb(ioaddr + PAR0 + i); /* Reset the chip to erase previous misconfiguration. */ writel(0x00000001, ioaddr + BCR); dev->base_addr = ioaddr; dev->irq = irq; /* Make certain the descriptor lists are aligned. */ np = dev->priv; spin_lock_init(&np->lock); np->pci_dev = pdev; np->flags = skel_netdrv_tbl[chip_id].flags; pci_set_drvdata(pdev, dev); np->mii.dev = dev; np->mii.mdio_read = mdio_read; np->mii.mdio_write = mdio_write; ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); if (!ring_space) { err = -ENOMEM; goto err_out_free_dev; } np->rx_ring = (struct fealnx_desc *)ring_space; np->rx_ring_dma = ring_dma; ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); if (!ring_space) { err = -ENOMEM; goto err_out_free_rx; } np->tx_ring = (struct fealnx_desc *)ring_space; np->tx_ring_dma = ring_dma; /* find the connected MII xcvrs */ if (np->flags == HAS_MII_XCVR) { int phy, phy_idx = 0; for (phy = 1; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; printk(KERN_INFO "%s: MII PHY found at address %d, status " "0x%4.4x.\n", dev->name, phy, mii_status); /* get phy type */ { unsigned int data; data = mdio_read(dev, np->phys[0], 2); if (data == SeeqPHYID0) np->PHYType = SeeqPHY; else if (data == AhdocPHYID0) np->PHYType = AhdocPHY; else if (data == MarvellPHYID0) np->PHYType = MarvellPHY; else if (data == MysonPHYID0) np->PHYType = Myson981; else if (data == LevelOnePHYID0) np->PHYType = LevelOnePHY; else np->PHYType = OtherPHY; } } } np->mii_cnt = phy_idx; if (phy_idx == 0) { printk(KERN_WARNING "%s: MII PHY not found -- this device may " "not operate correctly.\n", dev->name); } } else { np->phys[0] = 32;/* 89/6/23 add, (begin) */ /* get phy type */ if (readl(dev->base_addr + PHYIDENTIFIER) == MysonPHYID) np->PHYType = MysonPHY; else np->PHYType = OtherPHY; } np->mii.phy_id = np->phys[0]; if (dev->mem_start) option = dev->mem_start; /* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200) np->mii.full_duplex = 1; np->default_port = option & 15; } if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->mii.full_duplex = full_duplex[card_idx]; if (np->mii.full_duplex) { printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);/* 89/6/13 add, (begin) */// if (np->PHYType==MarvellPHY) if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) { unsigned int data; data = mdio_read(dev, np->phys[0], 9); data = (data & 0xfcff) | 0x0200; mdio_write(dev, np->phys[0], 9, data); }/* 89/6/13 add, (end) */ if (np->flags == HAS_MII_XCVR) mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); else writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR); np->mii.duplex_lock = 1; } /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; err = register_netdev(dev); if (err) goto err_out_free_tx; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); return 0;err_out_free_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);err_out_free_rx: pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);err_out_free_dev: kfree(dev);err_out_unmap:#ifndef USE_IO_OPS iounmap((void *)ioaddr);err_out_res:#endif pci_release_regions(pdev); return err;}static void __devexit fealnx_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { struct netdev_private *np = dev->priv; pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); unregister_netdev(dev);#ifndef USE_IO_OPS iounmap((void *)dev->base_addr);#endif kfree(dev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } else printk(KERN_ERR "fealnx: remove for unknown device\n");}unsigned int m80x_read_tick(void)/* function: Reads the Timer tick count register which decrements by 2 from *//* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the *//* count represents 838 nsec's. *//* input : none. *//* output : none. */{ unsigned char tmp; int value; writeb((char) 0x06, 0x43); // Command 8254 to latch T0's count // now read the count. tmp = (unsigned char) readb(0x40); value = ((int) tmp) << 8; tmp = (unsigned char) readb(0x40); value |= (((int) tmp) & 0xff); return (value);}void m80x_delay(unsigned int interval)/* function: to wait for a specified time. *//* input : interval ... the specified time. *//* output : none. */{ unsigned int interval1, interval2, i = 0; interval1 = m80x_read_tick(); // get initial value do { interval2 = m80x_read_tick(); if (interval1 < interval2) interval1 = interval2; ++i; } while (((interval1 - interval2) < (ushort) interval) && (i < 65535));}static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad){ ulong miir; int i; unsigned int mask, data; /* enable MII output */ miir = (ulong) readl(miiport); miir &= 0xfffffff0; miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; /* send 32 1's preamble */ for (i = 0; i < 32; i++) { /* low MDC; MDO is already high (miir) */ miir &= ~MASK_MIIR_MII_MDC; writel(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; writel(miir, miiport); } /* calculate ST+OP+PHYAD+REGAD+TA */ data = opcode | (phyad << 7) | (regad << 2); /* sent out */ mask = 0x8000; while (mask) { /* low MDC, prepare MDO */ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); if (mask & data) miir |= MASK_MIIR_MII_MDO; writel(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; writel(miir, miiport); m80x_delay(30); /* next */ mask >>= 1; if (mask == 0x2 && opcode == OP_READ) miir &= ~MASK_MIIR_MII_WRITE; } return miir;}static int mdio_read(struct net_device *dev, int phyad, int regad){ long miiport = dev->base_addr + MANAGEMENT; ulong miir; unsigned int mask, data; miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); /* read data */ mask = 0x8000; data = 0; while (mask) { /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; writel(miir, miiport); /* read MDI */ miir = readl(miiport); if (miir & MASK_MIIR_MII_MDI) data |= mask; /* high MDC, and wait */ miir |= MASK_MIIR_MII_MDC; writel(miir, miiport); m80x_delay((int) 30); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; writel(miir, miiport); return data & 0xffff;}static void mdio_write(struct net_device *dev, int phyad, int regad, int data){ long miiport = dev->base_addr + MANAGEMENT; ulong miir; unsigned int mask; miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); /* write data */ mask = 0x8000; while (mask) { /* low MDC, prepare MDO */ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); if (mask & data) miir |= MASK_MIIR_MII_MDO; writel(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; writel(miir, miiport); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; writel(miir, miiport); return;}static int netdev_open(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; writel(0x00000001, ioaddr + BCR); /* Reset */ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) return -EAGAIN; init_ring(dev); writel(np->rx_ring_dma, ioaddr + RXLBA); writel(np->tx_ring_dma, ioaddr + TXLBA); /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. 486: Set 8 longword burst. 586: no burst limit. Burst length 5:3 0 0 0 1 0 0 1 4 0 1 0 8 0 1 1 16 1 0 0 32 1 0 1 64 1 1 0 128 1 1 1 256 Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. FIXME (Ueimor): optimistic for alpha + posted writes ? */#if defined(__powerpc__) || defined(__sparc__)// 89/9/1 modify, // np->bcrvalue=0x04 | 0x0x38; /* big-endian, 256 burst length */ np->bcrvalue = 0x04 | 0x10; /* big-endian, tx 8 burst length */ np->crvalue = 0xe00; /* rx 128 burst length */#elif defined(__alpha__) || defined(__x86_64__)// 89/9/1 modify, // np->bcrvalue=0x38; /* little-endian, 256 burst length */ np->bcrvalue = 0x10; /* little-endian, 8 burst length */ np->crvalue = 0xe00; /* rx 128 burst length */#elif defined(__i386__)#if defined(MODULE)// 89/9/1 modify, // np->bcrvalue=0x38; /* little-endian, 256 burst length */ np->bcrvalue = 0x10; /* little-endian, 8 burst length */ np->crvalue = 0xe00; /* rx 128 burst length */#else /* When not a module we can work around broken '486 PCI boards. */#define x86 boot_cpu_data.x86// 89/9/1 modify, // np->bcrvalue=(x86 <= 4 ? 0x10 : 0x38); np->bcrvalue = 0x10; np->crvalue = (x86 <= 4 ? 0xa00 : 0xe00); if (x86 <= 4) printk(KERN_INFO "%s: This is a 386/486 PCI system, setting burst " "length to %x.\n", dev->name, (x86 <= 4 ? 0x10 : 0x38));#endif#else// 89/9/1 modify,// np->bcrvalue=0x38; np->bcrvalue = 0x10; np->cralue = 0xe00; /* rx 128 burst length */#warning Processor architecture undefined!#endif// 89/12/29 add,// 90/1/16 modify,// np->imrvalue=FBE|TUNF|CNTOVF|RBU|TI|RI; np->imrvalue = TUNF | CNTOVF | RBU | TI | RI; if (np->pci_dev->device == 0x891) { np->bcrvalue |= 0x200; /* set PROG bit */ np->crvalue |= 0x02000000; /* set enhanced bit */ np->imrvalue |= ETI; } writel(np->bcrvalue, ioaddr + BCR); if (dev->if_port == 0) dev->if_port = np->default_port; writel(0, dev->base_addr + RXPDR);// 89/9/1 modify,// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ np->mii.full_duplex = np->mii.duplex_lock; getlinkstatus(dev); if (np->linkok) getlinktype(dev); set_rx_mode(dev); netif_start_queue(dev); /* Clear and Enable interrupts by setting the interrupt mask. */ writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); writel(np->imrvalue, ioaddr + IMR); if (debug) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = RUN_AT(3 * HZ); np->timer.data = (unsigned long) dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); return 0;}static void getlinkstatus(struct net_device *dev)/* function: Routine will read MII Status Register to get link status. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -