fealnx.c
来自「linux 内核源代码」· C语言 代码 · 共 1,989 行 · 第 1/4 页
C
1,989 行
option = card_idx < MAX_UNITS ? options[card_idx] : 0; i = pci_enable_device(pdev); if (i) return i; pci_set_master(pdev); len = pci_resource_len(pdev, bar); if (len < MIN_REGION_SIZE) { dev_err(&pdev->dev, "region size %ld too small, aborting\n", len); return -ENODEV; } i = pci_request_regions(pdev, boardname); if (i) return i; irq = pdev->irq; ioaddr = pci_iomap(pdev, bar, len); if (!ioaddr) { err = -ENOMEM; goto err_out_res; } dev = alloc_etherdev(sizeof(struct netdev_private)); if (!dev) { err = -ENOMEM; goto err_out_unmap; } SET_NETDEV_DEV(dev, &pdev->dev); /* read ethernet id */ for (i = 0; i < 6; ++i) dev->dev_addr[i] = ioread8(ioaddr + PAR0 + i); /* Reset the chip to erase previous misconfiguration. */ iowrite32(0x00000001, ioaddr + BCR); dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; /* Make certain the descriptor lists are aligned. */ np = netdev_priv(dev); np->mem = ioaddr; 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; np->mii.phy_id_mask = 0x1f; np->mii.reg_num_mask = 0x1f; 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; dev_info(&pdev->dev, "MII PHY found at address %d, status " "0x%4.4x.\n", 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) dev_warn(&pdev->dev, "MII PHY not found -- this device may " "not operate correctly.\n"); } else { np->phys[0] = 32;/* 89/6/23 add, (begin) */ /* get phy type */ if (ioread32(ioaddr + 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) { dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");/* 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 iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR); np->mii.force_media = 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->ethtool_ops = &netdev_ethtool_ops; 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 %p, %s, IRQ %d.\n", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, print_mac(mac, dev->dev_addr), 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: free_netdev(dev);err_out_unmap: pci_iounmap(pdev, ioaddr);err_out_res: 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 = netdev_priv(dev); 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); pci_iounmap(pdev, np->mem); free_netdev(dev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } else printk(KERN_ERR "fealnx: remove for unknown device\n");}static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad){ ulong miir; int i; unsigned int mask, data; /* enable MII output */ miir = (ulong) ioread32(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; iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; iowrite32(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; iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); udelay(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){ struct netdev_private *np = netdev_priv(dev); void __iomem *miiport = np->mem + 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; iowrite32(miir, miiport); /* read MDI */ miir = ioread32(miiport); if (miir & MASK_MIIR_MII_MDI) data |= mask; /* high MDC, and wait */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); udelay(30); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; iowrite32(miir, miiport); return data & 0xffff;}static void mdio_write(struct net_device *dev, int phyad, int regad, int data){ struct netdev_private *np = netdev_priv(dev); void __iomem *miiport = np->mem + 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; iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; iowrite32(miir, miiport);}static int netdev_open(struct net_device *dev){ struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->mem; int i; iowrite32(0x00000001, ioaddr + BCR); /* Reset */ if (request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev)) return -EAGAIN; for (i = 0; i < 3; i++) iowrite16(((unsigned short*)dev->dev_addr)[i], ioaddr + PAR0 + i*2); init_ring(dev); iowrite32(np->rx_ring_dma, ioaddr + RXLBA); iowrite32(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->crvalue = 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 |= CR_W_ENH; /* set enhanced bit */ np->imrvalue |= ETI; } iowrite32(np->bcrvalue, ioaddr + BCR); if (dev->if_port == 0) dev->if_port = np->default_port; iowrite32(0, ioaddr + 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.force_media; getlinkstatus(dev); if (np->linkok) getlinktype(dev); __set_rx_mode(dev); netif_start_queue(dev); /* Clear and Enable interrupts by setting the interrupt mask. */ iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); iowrite32(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); init_timer(&np->reset_timer); np->reset_timer.data = (unsigned long) dev; np->reset_timer.function = &reset_timer; np->reset_timer_armed = 0; return 0;}static void getlinkstatus(struct net_device *dev)/* function: Routine will read MII Status Register to get link status. *//* input : dev... pointer to the adapter block. *//* output : none. */{ struct netdev_private *np = netdev_priv(dev); unsigned int i, DelayTime = 0x1000; np->linkok = 0; if (np->PHYType == MysonPHY) { for (i = 0; i < DelayTime; ++i) { if (ioread32(np->mem + BMCRSR) & LinkIsUp2) { np->linkok = 1; return; } udelay(100); } } else { for (i = 0; i < DelayTime; ++i) { if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) { np->linkok = 1; return; } udelay(100); } }}static void getlinktype(struct net_device *dev){ struct netdev_private *np = netdev_priv(dev); if (np->PHYType == MysonPHY) { /* 3-in-1 case */ if (ioread32(np->mem + TCRRCR) & CR_R_FD) np->duplexmode = 2; /* full duplex */ else np->duplexmode = 1; /* half duplex */ if (ioread32(np->mem + TCRRCR) & CR_R_PS10) np->line_speed = 1; /* 10M */ else np->line_speed = 2; /* 100M */ } else { if (np->PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */ unsigned int data; data = mdio_read(dev, np->phys[0], MIIRegister18);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?