📄 gt96100eth.c
字号:
// now route ethernet interrupts to GT Int0 (eth0 and eth1 will be // sharing it). // FIX! The kernel's irq code should do this intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); intMask |= 1 << gp->port_num; GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask);}static void disable_ether_irq(struct net_device *dev){ struct gt96100_private *gp = (struct gt96100_private *) dev->priv; u32 intMask; // FIX! The kernel's irq code should do this intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); intMask &= ~(1 << gp->port_num); GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0);}/* * Probe for a GT96100 ethernet controller. */int __init gt96100_probe(struct net_device *dev){ unsigned int base_addr = dev ? dev->base_addr : 0; int i;#ifndef CONFIG_MIPS_GT96100ETH return -ENODEV;#endif if (gt96100_debug > 2) printk(KERN_INFO "%s: gt96100_probe\n", dev->name); if (base_addr >= KSEG0) /* Check a single specified location. */ return gt96100_probe1(dev, base_addr, dev->irq, 0); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO;// for (i = 0; i<NUM_INTERFACES; i++) { for (i = NUM_INTERFACES - 1; i >= 0; i--) { int base_addr = gt96100_iflist[i].port;#if 0 if (check_region(base_addr, GT96100_ETH_IO_SIZE)) { printk(KERN_ERR "%s: gt96100_probe: ioaddr 0x%lx taken?\n", dev->name, base_addr); continue; }#endif if (gt96100_probe1 (dev, base_addr, gt96100_iflist[i].irq, i) == 0) return 0; } return -ENODEV;}static int __initgt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num){ static unsigned version_printed = 0; struct gt96100_private *gp = NULL; int i, retval; u32 cpuConfig; // FIX! probe for GT96100 by reading a suitable register if (gt96100_debug > 2) printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n", ioaddr, irq); request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH"); cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); if (cpuConfig & (1 << 12)) { printk(KERN_ERR "gt96100_probe1: must be in Big Endian mode!\n"); retval = -ENODEV; goto free_region; } if (gt96100_debug > 2) printk(KERN_INFO "gt96100_probe1: chip in Big Endian mode - cool\n"); /* Allocate a new 'dev' if needed. */ if (dev == NULL) dev = init_etherdev(0, sizeof(struct gt96100_private)); if (gt96100_debug && version_printed++ == 0) printk(version); if (irq < 0) { printk(KERN_ERR "gt96100_probe1: irq unknown - probing not supported\n"); retval = -ENODEV; goto free_region; } printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n", dev->name, ioaddr, irq); /* private struct aligned and zeroed by init_etherdev */ /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; dev->irq = irq; memcpy(dev->dev_addr, gt96100_station_addr[port_num], sizeof(dev->dev_addr)); printk(KERN_INFO "%s: HW Address ", dev->name); for (i = 0; i < sizeof(dev->dev_addr); i++) { printk("%2.2x", dev->dev_addr[i]); printk(i < 5 ? ":" : "\n"); } /* Initialize our private structure. */ if (dev->priv == NULL) { gp = (struct gt96100_private *) kmalloc(sizeof(*gp), GFP_KERNEL); if (gp == NULL) { retval = -ENOMEM; goto free_region; } dev->priv = gp; } gp = dev->priv; memset(gp, 0, sizeof(*gp)); // clear it gp->port_num = port_num; gp->io_size = GT96100_ETH_IO_SIZE; gp->port_offset = port_num * GT96100_ETH_IO_SIZE; gp->phy_addr = port_num + 1; if (gt96100_debug > 2) printk(KERN_INFO "%s: gt96100_probe1, port %d\n", dev->name, gp->port_num); // Allocate Rx and Tx descriptor rings if (gp->rx_ring == NULL) { // All descriptors in ring must be 16-byte aligned gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE + sizeof(gt96100_td_t) * TX_RING_SIZE, &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; goto free_region; } gp->tx_ring = (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE); gp->tx_ring_dma = gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; } if (gt96100_debug > 2) printk(KERN_INFO "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n", dev->name, gp->rx_ring, gp->tx_ring); // Allocate Rx Hash Table if (gp->hash_table == NULL) { gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE, &gp->hash_table_dma); if (gp->hash_table == NULL) { dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + sizeof(gt96100_td_t) * TX_RING_SIZE, gp->rx_ring); retval = -ENOMEM; goto free_region; } } if (gt96100_debug > 2) printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n", dev->name, gp->hash_table); spin_lock_init(&gp->lock); dev->open = gt96100_open; dev->hard_start_xmit = gt96100_tx; dev->stop = gt96100_close; dev->get_stats = gt96100_get_stats; //dev->do_ioctl = gt96100_ioctl; dev->set_multicast_list = gt96100_set_rx_mode; dev->tx_timeout = gt96100_tx_timeout; dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); return 0; free_region: release_region(ioaddr, gp->io_size); unregister_netdev(dev); if (dev->priv != NULL) kfree(dev->priv); kfree(dev); printk(KERN_ERR "%s: gt96100_probe1 failed. Returns %d\n", dev->name, retval); return retval;}static int gt96100_init(struct net_device *dev){ struct gt96100_private *gp = (struct gt96100_private *) dev->priv; unsigned long flags; u32 phyAD, ciu; int i; if (gt96100_debug > 2) printk("%s: gt96100_init: dev=%p\n", dev->name, dev); // Stop and disable Port hard_stop(dev); spin_lock_irqsave(&gp->lock, flags); // First things first, set-up hash table memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it gp->hash_mode = 0; // Add a single entry to hash table - our ethernet address gt96100_add_hash_entry(dev, dev->dev_addr); // Set-up DMA ptr to hash table GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); if (gt96100_debug > 2) printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); // Setup Tx descriptor ring for (i = 0; i < TX_RING_SIZE; i++) { gp->tx_ring[i].cmdstat = 0; // CPU owns gp->tx_ring[i].byte_cnt = 0; gp->tx_ring[i].buff_ptr = 0; gp->tx_ring[i].next = cpu_to_dma32(gp->tx_ring_dma + sizeof(gt96100_td_t) * (i + 1)); } /* Wrap the ring. */ gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma); // setup only the lowest priority TxCDP reg GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma); GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0); if (gt96100_debug > 2) printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0)); // Setup Rx descriptor ring for (i = 0; i < RX_RING_SIZE; i++) { dma_addr_t rx_buff_dma; gp->rx_ring[i].next = cpu_to_dma32(gp->rx_ring_dma + sizeof(gt96100_rd_t) * (i + 1)); if (gp->rx_buff[i] == NULL) gp->rx_buff[i] = dmaalloc(PKT_BUF_SZ, &rx_buff_dma); else rx_buff_dma = virt_to_phys(gp->rx_buff[i]); if (gp->rx_buff[i] == NULL) break; gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma); gp->rx_ring[i].buff_cnt_sz = cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit); // Give ownership to device, enable interrupt gp->rx_ring[i].cmdstat = cpu_to_dma32((u32) (rxOwn | rxEI)); } if (i != RX_RING_SIZE) { int j; for (j = 0; j < RX_RING_SIZE; j++) { if (gp->rx_buff[j]) { dmafree(PKT_BUF_SZ, gp->rx_buff[j]); gp->rx_buff[j] = NULL; } } printk(KERN_ERR "%s: Rx ring allocation failed.\n", dev->name); spin_unlock_irqrestore(&gp->lock, flags); return -ENOMEM; } /* Wrap the ring. */ gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma); // Set our MII PHY device address phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); phyAD &= ~(0x1f << (gp->port_num * 5)); phyAD |= gp->phy_addr << (gp->port_num * 5); GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); if (gt96100_debug > 2) printk("%s: gt96100_init: PhyAD=%x\n", dev->name, GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); // Clear all the RxFDP and RXCDP regs... for (i = 0; i < 4; i++) { GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4, 0); GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4, 0); } // and setup only the lowest priority RxFDP and RxCDP regs GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, gp->rx_ring_dma); GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, gp->rx_ring_dma); if (gt96100_debug > 2) printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0), GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); // init Rx/Tx indeces and pkt counters gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0; gp->tx_count = 0; // setup DMA // FIX! this should be done by Kernel setup code ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); ciu |= (0x0c << (gp->port_num * 2)); // set Ether DMA req priority to high // FIX! setting the following bit causes the EV96100 board to hang!!! //ciu |= (1 << (24+gp->port_num)); // pull Ethernet port out of Reset??? // FIX! endian mode??? ciu &= ~(1 << 31); // set desc endianess to Big GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu); if (gt96100_debug > 2) printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name, ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); // We want the Rx/Tx DMA to write/read data to/from memory in // Big Endian mode. Also set DMA Burst Size to 8 64Bit words. // FIX! endian mode??? GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG, //sdcrBLMR | sdcrBLMT | (0xf << sdcrRCBit) | sdcrRIFB | (3 << sdcrBSZBit)); if (gt96100_debug > 2) printk("%s: gt96100_init: SDMA Config=%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG)); // start Rx DMA GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); if (gt96100_debug > 2) printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); // enable interrupts enable_ether_irq(dev); /* * Disable all Type-of-Service queueing. All Rx packets will be * treated normally and will be sent to the lowest priority * queue. * * Disable flow-control for now. FIX! support flow control? */ // clear all the MIB ctr regs // Enable reg clear on read. FIX! desc of this bit is inconsistent // in the GT-96100A datasheet. GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, pcxrFCTL | pcxrFCTLen | pcxrFLP); read_mib_counters(gp); GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode); if (gt96100_debug > 2) printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); // enable this port (set hash size to 1/2K) GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); if (gt96100_debug > 2) printk("%s: gt96100_init: Port Config=%x\n", dev->name, GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); // we should now be receiving frames if (gt96100_debug > 2) dump_MII(dev); spin_unlock_irqrestore(&gp->lock, flags); return 0;}static int gt96100_open(struct net_device *dev){ int retval; MOD_INC_USE_COUNT; if (gt96100_debug > 2) printk("%s: gt96100_open: dev=%p\n", dev->name, dev); if ((retval = request_irq(dev->irq, >96100_interrupt, SA_SHIRQ, dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); MOD_DEC_USE_COUNT; return retval; } // Initialize and startup the GT-96100 ethernet port if ((retval = gt96100_init(dev))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -