📄 ax88180.c
字号:
* 0xFC00~0xFCFF MAC registers area * 0xFD00~0xFFFF Unused * * Return 0 on success. ***************************************************************************** */int __init ax88180_probe(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned long phy_membase = mem;/* //allan9 add for debugging unsigned long tmp_data; unsigned long rx_packet_len; unsigned int packet_len; unsigned long rxcurt_ptr, rxbound_ptr; int i;*/ PRINTK(DRIVER_MSG, "%s", version); PRINTK(INIT_MSG, "ax88180: ax88180_probe beginning ..........\n"); SET_MODULE_OWNER(global_dev); /* Allocate memory space for AX88180_PRIVATE structure */ global_dev->priv = kmalloc(sizeof(struct _AX88180_PRIVATE), GFP_KERNEL); if (global_dev->priv == NULL) { PRINTK(ERROR_MSG, "ax88180: Fail to allocate a private data structure!\n"); PRINTK(INIT_MSG, "ax88180: ax88180_probe fail end ..........\n"); unregister_netdev(global_dev); return -ENOMEM; } /* Initialize zero values in the AX88180_PRIVATE structure */ memset(global_dev->priv, 0, sizeof(struct _AX88180_PRIVATE)); pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; if (check_mem_region(phy_membase , AX88180_MEMORY_SIZE) != 0) { PRINTK(ERROR_MSG, "ax88180: Memory Region specified (0x%08lX to 0x%08lX) is not available!\n", phy_membase, (phy_membase + AX88180_MEMORY_SIZE - 1UL) ); kfree(global_dev->priv); global_dev->priv = NULL; unregister_netdev(global_dev); return -ENOMEM;; } request_mem_region(phy_membase, AX88180_MEMORY_SIZE, "ASIX_AX88180"); pax88180_local->Phy_MemBase = phy_membase; Log_MemBase = (unsigned long)ioremap(pax88180_local->Phy_MemBase, AX88180_MEMORY_SIZE);// PRINTK(DEBUG_MSG, "ax88180: global_dev =0x%p, pax88180_local=0x%p, Log_MemBase=0x%08lx\n", // global_dev, pax88180_local, Log_MemBase); PRINTK(DRIVER_MSG, "ax88180: Allocate AX88180 at Phy_MemBase=0x%08lx. (name=%s, IRQ=0x%x)\n", pax88180_local->Phy_MemBase, global_dev->name, (unsigned int)irq);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#ifdef CONFIG_BOARD_S3C2440_SMDK /* Configure SAMSUNG S3C2440A controller for AX88780 operation */ BANKCON1 = BANKCON1_6CLKS_PAGE; PRINTK(DEBUG_MSG, "ax88780: CLKDIVN=0x%04x, CAMDIVN=0x%04x, BANKCON1=0x%04x\n", CLKDIVN, CAMDIVN, BANKCON1); PRINTK(DEBUG_MSG, "ax88780: UBRDIV0=0x%04x, UBRDIV1=0x%04x, UBRDIV2=0x%04x\n", UBRDIV0, UBRDIV1, UBRDIV2); PRINTK(DEBUG_MSG, "ax88780: BWSCON=0x%08x, MISCCR=0x%06x\n", BWSCON, MISCCR); set_external_irq(irq, EXT_LOWLEVEL, GPIO_PULLUP_DIS); EINTMASK &= ~EINT11_MASK; EXTINT1 |= FLTEN11;#endif#else#ifdef CONFIG_ARCH_S3C2410 /* Configure SAMSUNG S3C2440A controller for AX88780 operation */ __raw_writel(S3C2410_BANKCON_Tacc6, S3C2410_BANKCON1);#endif#endif /* Initialize the Ethernet Device structure */ ether_setup(global_dev); global_dev->base_addr = mem; global_dev->irq = irq; pax88180_local->MediaMode = media; pax88180_local->JumboFlag = jumbo; pax88180_local->PhyAddr = MARVELL_88E1111_PHYADDR; pax88180_local->rx_buf = NULL; /* Declare ax88180 routines here */ global_dev->open = ax88180_open; global_dev->stop = ax88180_stop; global_dev->hard_start_xmit = ax88180_start_xmit; global_dev->tx_timeout = ax88180_tx_timeout; global_dev->watchdog_timeo = 200*HZ; global_dev->get_stats = ax88180_get_stats; global_dev->set_multicast_list = ax88180_set_multicast_list;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) global_dev->do_ioctl = ax88180_ioctl;#endif //allan9 add for debugging DISPLAY_ALLMACREG; DISPLAY_ALLPHYREG;/* //allan9 add for debugging READ_MACREG(RXCURT, rxcurt_ptr); READ_MACREG(RXBOUND, rxbound_ptr); START_READ_RXBUFF; READ_RXBUF(rx_packet_len); if ( (rx_packet_len > 0) && (rx_packet_len <= MAX_RX_SIZE) ){ packet_len = (unsigned int)rx_packet_len; PRINTK(DEBUG_MSG, "ax88180: Rx packet length = 0x%08lx\n", rx_packet_len); for (i = 0; i < (packet_len - 4); i += 4) { READ_RXBUF(tmp_data); PRINTK(DEBUG_MSG, "ax88180: Rx data #%d = 0x%08lx\n", i, tmp_data); } } else { PRINTK(DEBUG_MSG, "ax88180: Invalid Rx packet length!! (len=0x%08lx)\n", rx_packet_len); } STOP_READ_RXBUFF; //allan9 end*/ PRINTK(INIT_MSG, "ax88180: ax88180_probe end ..........\n"); return 0;}#ifndef MODULE/* * ---------------------------------------------------------------------------- * Function Name: ax_kprobe * Purpose: * Params: * Returns: * Note: * ---------------------------------------------------------------------------- */struct net_device * __init ax_kprobe(int unit){ struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) return ERR_PTR(-ENOMEM); sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); err = ax88180_probe(dev); if (err) goto out; return dev;out: free_netdev(dev); return ERR_PTR(err);}#endif/* ***************************************************************************** * ax88180_open() * * 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. * * AKPM: do we need to do any locking here? * ***************************************************************************** */static int ax88180_open(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned long tmp_regval; int rtn = -ENODEV; PRINTK(INIT_MSG, "ax88180: ax88180_open beginning ..........\n"); pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* Indicate this module is in use */ MOD_INC_USE_COUNT;#endif if (pax88180_local->rx_buf == NULL) { /* Try to allocate memory space for RX buffer */ pax88180_local->rx_buf = kmalloc(MAX_RX_SIZE, GFP_KERNEL); if (pax88180_local->rx_buf == NULL) { PRINTK(ERROR_MSG, "ax88180: Fail to allocate a RX buffer space!\n"); PRINTK(INIT_MSG, "ax88180: ax88180_open fail end ..........\n");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_DEC_USE_COUNT;#endif return -ENOMEM; } } /* Initialize zero values in the RX buffer */ memset(pax88180_local->rx_buf, 0, MAX_RX_SIZE); /* Initial AX88180 registers here */ rtn = ax88180_initialization(global_dev); if (rtn) { /* Release allocated resource here */ PRINTK(ERROR_MSG, "ax88180: Fail to initialize AX88180 controller!!\n"); PRINTK(INIT_MSG, "ax88180: ax88180_open fail end ..........\n");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_DEC_USE_COUNT;#endif return rtn; } /* Initial variables here */ INIT_TXRX_VARIABLES; /* Declare Interrupt routine to the allocated IRQ */ rtn = request_irq(global_dev->irq, &ax88180_interrupt, 0, global_dev->name, global_dev); if (rtn) { /* Release allocated resource here */ PRINTK(ERROR_MSG, "ax88180: Fail to request IRQ (0x%x)\n", global_dev->irq); PRINTK(INIT_MSG, "ax88180: ax88180_open fail end ..........\n");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_DEC_USE_COUNT;#endif return rtn; } /* Enable AX88180 interrupt */ ENABLE_INTERRUPT; /* Start AX88180 TX/RX functions */ WRITE_MACREG(CMD, RXEN | TXEN | WAKEMOD); /* Check if there is any invalid interrupt status. If yes, clear it. */ READ_MACREG(ISR, tmp_regval); PRINTK(INIT_MSG, "ax88180: The interrupt status = 0x%08lx\n", tmp_regval); if (tmp_regval) WRITE_MACREG(ISR, tmp_regval); /* Display all AX88180 MAC and PHY registers onto console screen */ DISPLAY_ALLMACREG; DISPLAY_ALLPHYREG; /* Inform upper protocol to start sending packets */ netif_start_queue(global_dev); /* Driver initialization successful */ PRINTK(DRIVER_MSG, "ax88180: name=%s, Phy_MemBase=0x%08lx, IRQ=0x%x, media=%d, jumbo=%u\n", global_dev->name, pax88180_local->Phy_MemBase, global_dev->irq, media, jumbo); PRINTK(DRIVER_MSG, "ax88180: The AX88180 driver is loaded successfully.\n"); PRINTK(INIT_MSG, "ax88180: ax88180_open end ..........\n"); return 0;}/* ***************************************************************************** * ax88180_stop() * * The inverse routine to ax88180_open(). * ***************************************************************************** */static int ax88180_stop(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned long flags; PRINTK(INIT_MSG, "ax88180: ax88180_stop beginning ..........\n"); pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv;/* PRINTK(DEBUG_MSG, "ax88180: global_dev =0x%p, pax88180_local=0x%p, dev_name=%s\n", global_dev, pax88180_local, global_dev->name); PRINTK(DEBUG_MSG, "ax88180: Phy_MemBase=0x%08lx, Log_MemBase=0x%08lx\n", pax88180_local->Phy_MemBase, Log_MemBase);*/ spin_lock_irqsave(&pax88180_local->lock, flags); kfree(pax88180_local->rx_buf); /* Inform upper layer to stop sending packets to device driver */ if (netif_device_present(global_dev)) { netif_stop_queue(global_dev); } /* Release interrupt */ free_irq(global_dev->irq, global_dev); spin_unlock_irqrestore(&pax88180_local->lock, flags);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* Indicate this module is NOT used now */ MOD_DEC_USE_COUNT;#endif /* Driver initialization successful */ PRINTK(DRIVER_MSG, "ax88180: The AX88180 driver is unloaded successfully.\n"); PRINTK(INIT_MSG, "ax88180: ax88180_stop end ..........\n"); return 0;}static int ax88180_start_xmit(struct sk_buff *skb, struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned char *txdata; unsigned long TXDES_addr; unsigned long txcmd_txdp, txbs_txdp; unsigned long txdes0_val, txdes1_val, txdes2_val, txdes3_val; unsigned long tmp_data; int i; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; txdata = skb->data; PRINTK(TX_MSG, "ax88180: ax88180_start_xmit beginning ..........\n");// spin_lock_irq(&pax88180_local->lock); /* Inform upper layer to stop sending packets to device driver */ netif_stop_queue(global_dev); pax88180_local->FirstTxDesc = pax88180_local->NextTxDesc; txbs_txdp = 1 << pax88180_local->FirstTxDesc; //allan9 add to make sure TX machine is OK i = 0; READ_MACREG(TXBS, tmp_data); READ_MACREG(TXBS, tmp_data); PRINTK(TX_MSG, "ax88180: Checking available TXDP (TXBS=0x%08lx)......\n", tmp_data); while (tmp_data & txbs_txdp) { pax88180_local->NextTxDesc++; pax88180_local->NextTxDesc &= TXDP_MASK; pax88180_local->FirstTxDesc = pax88180_local->NextTxDesc; txbs_txdp = 1 << pax88180_local->FirstTxDesc; READ_MACREG(TXBS, tmp_data); i++; if (i > 1000) { RESET_MAC; pax88180_local->NextTxDesc = TXDP0; pax88180_local->FirstTxDesc = pax88180_local->NextTxDesc; txbs_txdp = 1 << pax88180_local->FirstTxDesc; READ_MACREG(TXBS, tmp_data); i = 0; PRINTK(ERROR_MSG, "ax88180: No available TXDP!!\n"); } } PRINTK(TX_MSG, "ax88180: TXDP%d is available, i=%d\n", (int)pax88180_local->FirstTxDesc, i); //allan9 end txcmd_txdp = pax88180_local->FirstTxDesc << 13; TXDES_addr = TXDES0 + (pax88180_local->FirstTxDesc << 2); WRITE_MACREG(TXCMD, txcmd_txdp | skb->len | TX_START_WRITE); //allan9 add for debugging PRINTK(DEBUG_MSG, "ax88180: TX packets (len=0x%x, TXDP%d=0x%08lx)\n", skb->len, (int)pax88180_local->FirstTxDesc, TXDES_addr); PRINTK(DEBUG_MSG, "[");// for (i = 0; i < skb->len; i++) { for (i = 0; i < 64; i++) { PRINTK(DEBUG_MSG, "0x%02x ", *(txdata + i)); if ( (i & 0xF) == 0xF ) PRINTK(DEBUG_MSG, "\n"); } PRINTK(DEBUG_MSG, "]\n"); //alln 2006.05.25 modify to support burst mode/* for (i = 0; i < skb->len; i += 4) { tmp_data = (unsigned long)*(txdata + i) + (unsigned long)(*(txdata + i + 1) << 8) + (unsigned long)(*(txdata + i + 2) << 16) + (unsigned long)(*(txdata + i + 3) << 24); WRITE_TXBUF(tmp_data); }*/ memcpy ((void *)(Log_MemBase + TXBUFFER_START), txdata, (skb->len + (4 - skb->len%4)) ); WRITE_MACREG(TXCMD, txcmd_txdp | skb->len); WRITE_MACREG(TXBS, txbs_txdp); WRITE_MACREG(TXDES_addr, TXDPx_ENABLE | skb->len); //allan9 add for debugging READ_MACREG(TXCMD, txcmd_txdp); READ_MACREG(TXBS, txbs_txdp); READ_MACREG(TXDES0, txdes0_val); READ_MACREG(TXDES1, txdes1_val); READ_MACREG(TXDES2, txdes2_val); READ_MACREG(TXDES3, txdes3_val); PRINTK(TX_MSG, "ax88180: TXCMD=0x%08lx, TXBS=0x%08lx\n", txcmd_txdp, txbs_txdp); PRINTK(TX_MSG, "ax88180: TXDES0=0x%08lx, TXDES1=0x%08lx, TXDES2=0x%08lx, TXDES3=0x%08lx\n", txdes0_val, txdes1_val, txdes2_val, txdes3_val); pax88180_local->stats.tx_packets++; pax88180_local->stats.tx_bytes += skb->len; dev_kfree_skb(skb); global_dev->trans_start = jiffies; if (pax88180_local->JumboFlag == ENABLE_JUMBO) pax88180_local->NextTxDesc += 2; else pax88180_local->NextTxDesc++; pax88180_local->NextTxDesc &= TXDP_MASK; /* Inform upper layer to send next queued packets now */// netif_wake_queue(global_dev); //allan9 move to ax88180_tx_handler routine // spin_unlock_irq(&pax88180_local->lock); PRINTK(TX_MSG, "ax88180: ax88180_start_xmit end ..........\n\n"); return 0;}/* ***************************************************************************** * ax88180_tx_timeout() ***************************************************************************** */static void ax88180_tx_timeout(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; PRINTK(TX_MSG, "ax88180: ax88180_tx_timeout beginning ..........\n"); RESET_MAC; INIT_TXRX_VARIABLES; /* Inform upper layer to send next queued packets now */ global_dev->trans_start = jiffies; netif_wake_queue(global_dev); PRINTK(TX_MSG, "ax88180: ax88180_tx_timeout end ..........\n"); return;}/* ***************************************************************************** * ax88180_get_stats() * * Get the current statistics. This may be called with the card open or closed. * ***************************************************************************** */static struct net_device_stats * ax88180_get_stats(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned long tmp_regval; unsigned long flags; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; PRINTK(OTHERS_MSG, "ax88180: ax88180_get_stats beginning..........\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -