📄 ax88796b.c
字号:
ax_init (dev, 0);
PRINTK (INIT_MSG, PFX " probe end ..........\n");
return 0;
err_out:
iounmap (address);
kfree (dev->priv);
dev->priv = NULL;
return ret;
}
#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 = ax_probe (dev);
if (err)
goto out;
return dev;
out:
free_netdev (dev);
return ERR_PTR (err);
}
#endif
/*
* ----------------------------------------------------------------------------
* Function Name: ax_reset
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_reset (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned long reset_start_time = jiffies;
readb (ax_base + EN0_RESET);
ax_local->dmaing = 0;
/* This check _should_not_ be necessary, omit eventually. */
while ((readb (ax_base+EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2*HZ/100) {
PRINTK (ERROR_MSG, "%s: ax_reset() did not complete.\n", dev->name);
break;
}
writeb (ENISR_RESET, ax_base + EN0_ISR); /* Ack intr. */
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_get_hdr
* Purpose: Grab the 796b specific header
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_get_hdr (struct net_device *dev, struct ax_pkt_hdr *hdr, int ring_page)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
u16 *buf = (u16 *)hdr;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ax_local->dmaing)
{
PRINTK (ERROR_MSG, "%s: DMAing conflict in ne_get_8390_hdr "
"[DMAstat:%d][irqlock:%d].\n",
dev->name, ax_local->dmaing, ax_local->irqlock);
return;
}
ax_local->dmaing |= 0x01;
writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base+ E8390_CMD);
writeb (sizeof (struct ax_pkt_hdr), ax_base + EN0_RCNTLO);
writeb (0, ax_base + EN0_RCNTHI);
writeb (0, ax_base + EN0_RSARLO); /* On page boundary */
writeb (ring_page, ax_base + EN0_RSARHI);
writeb (E8390_RREAD+E8390_START, ax_base + E8390_CMD);
while (( readb (ax_base+EN0_SR) & ENSR_DMA_READY) == 0);
*buf = READ_FIFO (ax_base + EN0_DATAPORT);
*(++buf) = READ_FIFO (ax_base + EN0_DATAPORT);
writeb (ENISR_RDC, ax_base + EN0_ISR); /* Ack intr. */
ax_local->dmaing = 0;
le16_to_cpus (&hdr->count);
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_block_input
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
u16 *buf = (u16 *)skb->data;
u16 i;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ax_local->dmaing)
{
PRINTK (ERROR_MSG, "%s: DMAing conflict in ne_block_input "
"[DMAstat:%d][irqlock:%d].\n",
dev->name, ax_local->dmaing, ax_local->irqlock);
return;
}
ax_local->dmaing |= 0x01;
writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base+ E8390_CMD);
writeb (count & 0xff, ax_base + EN0_RCNTLO);
writeb (count >> 8, ax_base + EN0_RCNTHI);
writeb (ring_offset & 0xff, ax_base + EN0_RSARLO);
writeb (ring_offset >> 8, ax_base + EN0_RSARHI);
writeb (E8390_RREAD+E8390_START, ax_base + E8390_CMD);
while (( readb (ax_base+EN0_SR) & ENSR_DMA_READY) == 0);
#if (CONFIG_AX88796B_USE_MEMCPY == 1)
{
/* make the burst length be divided for 32-bit */
i = ((count - 2) + 3) & 0x7FC;
/* Read first 2 bytes */
*buf = READ_FIFO (ax_base + EN0_DATAPORT);
/* The address of ++buf should be agigned on 32-bit boundary */
memcpy (++buf, ax_base+EN0_DATA_ADDR, i);
}
#else
{
for (i = 0; i < count; i += 2) {
*buf++ = READ_FIFO (ax_base + EN0_DATAPORT);
}
}
#endif
writeb (ENISR_RDC, ax_base + EN0_ISR); /* Ack intr. */
ax_local->dmaing = 0;
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_block_output
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_block_output (struct net_device *dev, int count, const unsigned char *buf, const int start_page)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned long dma_start;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ax_local->dmaing)
{
PRINTK (ERROR_MSG, "%s: DMAing conflict in ne_block_output."
"[DMAstat:%d][irqlock:%d]\n",
dev->name, ax_local->dmaing, ax_local->irqlock);
return;
}
ax_local->dmaing |= 0x01;
/* We should already be in page 0, but to be safe... */
writeb (E8390_PAGE0+E8390_START+E8390_NODMA, ax_base + E8390_CMD);
writeb (ENISR_RDC, ax_base + EN0_ISR);
/* Now the normal output. */
writeb (count & 0xff, ax_base + EN0_RCNTLO);
writeb (count >> 8, ax_base + EN0_RCNTHI);
writeb (0x00, ax_base + EN0_RSARLO);
writeb (start_page, ax_base + EN0_RSARHI);
writeb (E8390_RWRITE+E8390_START, ax_base + E8390_CMD);
#if (CONFIG_AX88796B_USE_MEMCPY == 1)
memcpy ((ax_base+EN0_DATA_ADDR), buf, ((count+ 3) & 0x7FC));
#else
{
u16 i;
for (i = 0; i < count; i += 2) {
WRITE_FIFO (ax_base + EN0_DATAPORT, *((u16 *)(buf + i)));
}
}
#endif
dma_start = jiffies;
while ((readb(ax_base + EN0_ISR) & 0x40) == 0) {
if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
PRINTK (ERROR_MSG, "%s: timeout waiting for Tx RDC.\n", dev->name);
ax_reset (dev);
ax_init (dev,1);
break;
}
}
writeb (ENISR_RDC, ax_base + EN0_ISR); /* Ack intr. */
ax_local->dmaing = 0;
return;
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_open
* Purpose: Open/initialize 796b
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static int ax_open (struct net_device *dev)
{
unsigned long flags;
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *membase = ax_local->membase;
int ret=0;
PRINTK (DEBUG_MSG, PFX " ax88796B ei_open beginning ..........\n");
PRINTK (DEBUG_MSG, PFX " membase %p\n\r", membase);
ret = request_irq (dev->irq, &ax_interrupt, 0, dev->name, dev);
if (ret) {
PRINTK (ERROR_MSG, "%s: unable to get IRQ %d (errno=%d).\n",dev->name, dev->irq, ret);
return -ENXIO;
}
PRINTK (DEBUG_MSG, PFX " Request IRQ success !!\n\r");
/* This can't happen unless somebody forgot to call ethdev_init(). */
if (ax_local == NULL)
{
PRINTK (ERROR_MSG, "%s: ei_open passed a non-existent device!\n", dev->name);
return -ENXIO;
}
dev->tx_timeout = NULL;
dev->watchdog_timeo = 0;
spin_lock_irqsave (&ax_local->page_lock, flags);
ax_reset (dev);
ax_init (dev, 1);
netif_start_queue (dev);
spin_unlock_irqrestore (&ax_local->page_lock, flags);
ax_local->irqlock = 0;
init_timer (&ax_local->watchdog);
ax_local->watchdog.function = &ax_watchdog;
ax_local->watchdog.expires = jiffies + AX88796_WATCHDOG_PERIOD;
ax_local->watchdog.data = (unsigned long) dev;
add_timer (&ax_local->watchdog);
PRINTK (DEBUG_MSG, PFX " ax88796B ei_open end ..........\n");
return 0;
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_close
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static int ax_close (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
unsigned long flags;
PRINTK (DEBUG_MSG, PFX " ax88796B ei_close beginning ..........\n");
del_timer (&ax_local->watchdog);
spin_lock_irqsave (&ax_local->page_lock, flags);
ax_init (dev, 0);
free_irq (dev->irq, dev);
spin_unlock_irqrestore (&ax_local->page_lock, flags);
netif_stop_queue (dev);
PRINTK (DEBUG_MSG, PFX " ax88796B ei_close end ..........\n");
return 0;
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_start_xmit
* Purpose: begin packet transmission
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static int ax_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
int send_length;
unsigned long flags;
u8 ctepr=0, free_pages=0, need_pages;
/* check for link status */
if (!(readb (ax_base + EN0_SR) & ENSR_LINK)) {
dev_kfree_skb (skb);
return 0;
}
send_length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
spin_lock_irqsave (&ax_local->page_lock, flags);
writeb (0x00, ax_base + EN0_IMR);
spin_unlock_irqrestore (&ax_local->page_lock, flags);
spin_lock (&ax_local->page_lock);
ax_local->irqlock = 1;
need_pages = (send_length -1)/256 +1;
ctepr = readb (ax_base + EN0_CTEPR) & 0x7f;
if (ctepr == 0) {
if (ax_local->tx_curr_page == ax_local->tx_start_page && ax_local->tx_prev_ctepr == 0)
free_pages = TX_PAGES;
else
free_pages = ax_local->tx_stop_page - ax_local->tx_curr_page;
}
else if (ctepr < ax_local->tx_curr_page - 1) {
free_pages = ax_local->tx_stop_page - ax_local->tx_curr_page +
ctepr - ax_local->tx_start_page + 1;
}
else if (ctepr > ax_local->tx_curr_page - 1) {
free_pages = ctepr + 1 - ax_local->tx_curr_page;
}
else if (ctepr == ax_local->tx_curr_page - 1) {
if (ax_local->tx_full)
free_pages = 0;
else
free_pages = TX_PAGES;
}
if (free_pages < need_pages) {
PRINTK (DEBUG_MSG, "free_pages < need_pages\n\r");
netif_stop_queue (dev);
ax_local->tx_full = 1;
ax_local->irqlock = 0;
spin_unlock (&ax_local->page_lock);
spin_lock_irqsave (&ax_local->page_lock, flags);
writeb (ENISR_ALL, ax_base + EN0_IMR);
spin_unlock_irqrestore (&ax_local->page_lock, flags);
return 1;
}
ax_block_output (dev, send_length, skb->data, ax_local->tx_curr_page);
ax_trigger_send (dev, send_length, ax_local->tx_curr_page);
if (free_pages == need_pages) {
netif_stop_queue (dev);
ax_local->tx_full = 1;
}
ax_local->tx_prev_ctepr = ctepr;
ax_local->tx_curr_page = ax_local->tx_curr_page + need_pages < ax_local->tx_stop_page ?
ax_local->tx_curr_page + need_pages :
need_pages - (ax_local->tx_stop_page - ax_local->tx_curr_page) + ax_local->tx_start_page;
dev_kfree_skb (skb);
dev->trans_start = jiffies;
ax_local->stat.tx_bytes += send_length;
ax_local->irqlock = 0;
spin_unlock (&ax_local->page_lock);
spin_lock_irqsave (&ax_local->page_lock, flags);
writeb (ENISR_ALL, ax_base + EN0_IMR);
spin_unlock_irqrestore (&ax_local->page_lock, flags);
return 0;
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_tx_intr
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
static void ax_tx_intr (struct net_device *dev)
{
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
int status = readb (ax_base + EN0_TSR);
ax_local->tx_full = 0;
if (netif_queue_stopped (dev))
netif_wake_queue (dev);
/* Minimize Tx latency: update the statistics after we restart TXing. */
if (status & ENTSR_COL)
ax_local->stat.collisions++;
if (status & ENTSR_PTX)
ax_local->stat.tx_packets++;
else
{
ax_local->stat.tx_errors++;
if (status & ENTSR_ABT)
{
ax_local->stat.tx_aborted_errors++;
ax_local->stat.collisions += 16;
}
if (status & ENTSR_CRS)
ax_local->stat.tx_carrier_errors++;
if (status & ENTSR_FU)
ax_local->stat.tx_fifo_errors++;
if (status & ENTSR_CDH)
ax_local->stat.tx_heartbeat_errors++;
if (status & ENTSR_OWC)
ax_local->stat.tx_window_errors++;
}
}
/*
* ----------------------------------------------------------------------------
* Function Name: ax_interrupt
* Purpose:
* Params:
* Returns:
* Note:
* ----------------------------------------------------------------------------
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void ax_interrupt (int irq, void *dev_id, struct pt_regs * regs)
#else
static irqreturn_t ax_interrupt (int irq, void *dev_id, struct pt_regs * regs)
#endif
{
struct net_device *dev = dev_id;
int interrupts;
struct ax_device *ax_local = (struct ax_device *) dev->priv;
void *ax_base = ax_local->membase;
unsigned long flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -