📄 z85230.c
字号:
* DMA interrupts */ /* * Set up the DMA configuration */ flags=claim_dma_lock(); disable_dma(c->rxdma); clear_dma_ff(c->rxdma); set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0])); set_dma_count(c->rxdma, c->mtu); enable_dma(c->rxdma); disable_dma(c->txdma); clear_dma_ff(c->txdma); set_dma_mode(c->txdma, DMA_MODE_WRITE); disable_dma(c->txdma); release_dma_lock(flags); /* * Select the DMA interrupt handlers */ c->rxdma_on = 1; c->txdma_on = 1; c->tx_dma_used = 1; c->irqs = &z8530_dma_sync; z8530_rtsdtr(c,1); write_zsreg(c, R3, c->regs[R3]|RxENABLE); return 0;}EXPORT_SYMBOL(z8530_sync_dma_open);int z8530_sync_dma_close(struct device *dev, struct z8530_channel *c){ u8 chk; unsigned long flags; c->irqs = &z8530_nop; c->max = 0; c->sync = 0; /* * Disable the PC DMA channels */ flags=claim_dma_lock(); disable_dma(c->rxdma); clear_dma_ff(c->rxdma); c->rxdma_on = 0; disable_dma(c->txdma); clear_dma_ff(c->txdma); release_dma_lock(flags); c->txdma_on = 0; c->tx_dma_used = 0; /* * Disable DMA control mode */ c->regs[R1]&= ~WT_RDY_ENAB; write_zsreg(c, R1, c->regs[R1]); c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); c->regs[R1]|= INT_ALL_Rx; write_zsreg(c, R1, c->regs[R1]); c->regs[R14]&= ~DTRREQ; write_zsreg(c, R14, c->regs[R14]); if(c->rx_buf[0]) { kfree(c->rx_buf[0]); c->rx_buf[0]=NULL; } if(c->rx_buf[1]) { kfree(c->rx_buf[1]); c->rx_buf[1]=NULL; } if(c->tx_dma_buf[0]) { kfree(c->tx_dma_buf[0]); c->tx_dma_buf[0]=NULL; } if(c->tx_dma_buf[1]) { kfree(c->tx_dma_buf[1]); c->tx_dma_buf[1]=NULL; } chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); return 0;}EXPORT_SYMBOL(z8530_sync_dma_close);int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c){ printk("Opening sync interface for TX-DMA\n"); c->sync = 1; c->mtu = dev->mtu+64; c->count = 0; c->skb = NULL; c->skb2 = NULL; /* * Load the PIO receive ring */ z8530_rx_done(c); z8530_rx_done(c); /* * Load the DMA interfaces up */ c->rxdma_on = 0; c->txdma_on = 0; c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); if(c->tx_dma_buf[0]==NULL) { kfree(c->rx_buf[0]); kfree(c->rx_buf[1]); c->rx_buf[0]=NULL; return -ENOBUFS; } c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); if(c->tx_dma_buf[1]==NULL) { kfree(c->tx_dma_buf[0]); kfree(c->rx_buf[0]); kfree(c->rx_buf[1]); c->rx_buf[0]=NULL; c->rx_buf[1]=NULL; c->tx_dma_buf[0]=NULL; return -ENOBUFS; } c->tx_dma_used=0; c->dma_num=0; c->dma_ready=1; c->dma_tx = 1; /* * Enable DMA control mode */ /* * TX DMA via DIR/REQ */ c->regs[R14]|= DTRREQ; write_zsreg(c, R14, c->regs[R14]); /* * Set up the DMA configuration */ disable_dma(c->txdma); clear_dma_ff(c->txdma); set_dma_mode(c->txdma, DMA_MODE_WRITE); disable_dma(c->txdma); /* * Select the DMA interrupt handlers */ c->rxdma_on = 0; c->txdma_on = 1; c->tx_dma_used = 1; c->irqs = &z8530_txdma_sync; printk("Loading RX\n"); z8530_rtsdtr(c,1); printk("Rx interrupts ON\n"); write_zsreg(c, R3, c->regs[R3]|RxENABLE); return 0;}EXPORT_SYMBOL(z8530_sync_txdma_open); int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c){ u8 chk; c->irqs = &z8530_nop; c->max = 0; c->sync = 0; /* * Disable the PC DMA channels */ disable_dma(c->txdma); clear_dma_ff(c->txdma); c->txdma_on = 0; c->tx_dma_used = 0; /* * Disable DMA control mode */ c->regs[R1]&= ~WT_RDY_ENAB; write_zsreg(c, R1, c->regs[R1]); c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); c->regs[R1]|= INT_ALL_Rx; write_zsreg(c, R1, c->regs[R1]); c->regs[R14]&= ~DTRREQ; write_zsreg(c, R14, c->regs[R14]); if(c->tx_dma_buf[0]) { kfree(c->tx_dma_buf[0]); c->tx_dma_buf[0]=NULL; } if(c->tx_dma_buf[1]) { kfree(c->tx_dma_buf[1]); c->tx_dma_buf[1]=NULL; } chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); return 0;}EXPORT_SYMBOL(z8530_sync_txdma_close);/* * Describe a Z8530 in a standard format. We must pass the I/O as * the port offset isnt predictable. The main reason for this function * is to try and get a common format of report. */static char *z8530_type_name[]={ "Z8530", "Z85C30", "Z85230"};void z8530_describe(struct z8530_dev *dev, char *mapping, int io){ printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n", dev->name, z8530_type_name[dev->type], mapping, Z8530_PORT_OF(io), dev->irq);}EXPORT_SYMBOL(z8530_describe);/* * Configure up a Z8530 */ int z8530_init(struct z8530_dev *dev){ /* NOP the interrupt handlers first - we might get a floating IRQ transition when we reset the chip */ dev->chanA.irqs=&z8530_nop; dev->chanB.irqs=&z8530_nop; /* Reset the chip */ write_zsreg(&dev->chanA, R9, 0xC0); udelay(200); /* Now check its valid */ write_zsreg(&dev->chanA, R12, 0xAA); if(read_zsreg(&dev->chanA, R12)!=0xAA) return -ENODEV; write_zsreg(&dev->chanA, R12, 0x55); if(read_zsreg(&dev->chanA, R12)!=0x55) return -ENODEV; dev->type=Z8530; /* * See the application note. */ write_zsreg(&dev->chanA, R15, 0x01); /* * If we can set the low bit of R15 then * the chip is enhanced. */ if(read_zsreg(&dev->chanA, R15)==0x01) { /* This C30 versus 230 detect is from Klaus Kudielka's dmascc */ /* Put a char in the fifo */ write_zsreg(&dev->chanA, R8, 0); if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP) dev->type = Z85230; /* Has a FIFO */ else dev->type = Z85C30; /* Z85C30, 1 byte FIFO */ } /* * The code assumes R7' and friends are * off. Use write_zsext() for these and keep * this bit clear. */ write_zsreg(&dev->chanA, R15, 0); /* * At this point it looks like the chip is behaving */ memcpy(dev->chanA.regs, reg_init, 16); memcpy(dev->chanB.regs, reg_init ,16); return 0;}EXPORT_SYMBOL(z8530_init);int z8530_shutdown(struct z8530_dev *dev){ /* Reset the chip */ dev->chanA.irqs=&z8530_nop; dev->chanB.irqs=&z8530_nop; write_zsreg(&dev->chanA, R9, 0xC0); udelay(100); return 0;}EXPORT_SYMBOL(z8530_shutdown);/* * Load a Z8530 channel up from the system data * We use +16 to indicate the 'prime' registers */int z8530_channel_load(struct z8530_channel *c, u8 *rtable){ while(*rtable!=255) { int reg=*rtable++; if(reg>0x0F) write_zsreg(c, R15, c->regs[15]|1); write_zsreg(c, reg&0x0F, *rtable); if(reg>0x0F) write_zsreg(c, R15, c->regs[15]&~1); c->regs[reg]=*rtable++; } c->rx_function=z8530_null_rx; c->skb=NULL; c->tx_skb=NULL; c->tx_next_skb=NULL; c->mtu=1500; c->max=0; c->count=0; c->status=0; /* Fixme - check DCD now */ c->sync=1; write_zsreg(c, R3, c->regs[R3]|RxENABLE); return 0;}EXPORT_SYMBOL(z8530_channel_load);/* * Higher level shovelling - transmit chains */static void z8530_tx_begin(struct z8530_channel *c){ unsigned long flags; if(c->tx_skb) return; c->tx_skb=c->tx_next_skb; c->tx_next_skb=NULL; c->tx_ptr=c->tx_next_ptr; mark_bh(NET_BH); if(c->tx_skb==NULL) { /* Idle on */ if(c->dma_tx) { flags=claim_dma_lock(); disable_dma(c->txdma); /* * Check if we crapped out. */ if(get_dma_residue(c->txdma)) { c->stats.tx_dropped++; c->stats.tx_fifo_errors++; } release_dma_lock(flags); } c->txcount=0; } else { c->txcount=c->tx_skb->len; if(c->dma_tx) { /* * FIXME. DMA is broken for the original 8530, * on the older parts we need to set a flag and * wait for a further TX interrupt to fire this * stage off */ flags=claim_dma_lock(); disable_dma(c->txdma); /* * These two are needed by the 8530/85C30 * and must be issued when idling. */ if(c->dev->type!=Z85230) { write_zsctrl(c, RES_Tx_CRC); write_zsctrl(c, RES_EOM_L); } write_zsreg(c, R10, c->regs[10]&~ABUNDER); clear_dma_ff(c->txdma); set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); set_dma_count(c->txdma, c->txcount); enable_dma(c->txdma); release_dma_lock(flags); write_zsctrl(c, RES_EOM_L); write_zsreg(c, R5, c->regs[R5]|TxENAB); } else { save_flags(flags); cli(); /* ABUNDER off */ write_zsreg(c, R10, c->regs[10]); write_zsctrl(c, RES_Tx_CRC);//??? write_zsctrl(c, RES_EOM_L); while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP)) { write_zsreg(c, R8, *c->tx_ptr++); c->txcount--; } restore_flags(flags); } }} static void z8530_tx_done(struct z8530_channel *c){ unsigned long flags; struct sk_buff *skb; spin_lock_irqsave(&z8530_buffer_lock, flags); c->netdevice->tbusy=0; /* Actually this can happen.*/ if(c->tx_skb==NULL) { spin_unlock_irqrestore(&z8530_buffer_lock, flags); return; } skb=c->tx_skb; c->tx_skb=NULL; z8530_tx_begin(c); spin_unlock_irqrestore(&z8530_buffer_lock, flags); c->stats.tx_packets++; c->stats.tx_bytes+=skb->len; dev_kfree_skb(skb);}/* * Higher level shovelling - receive chains */ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb){ kfree_skb(skb);}EXPORT_SYMBOL(z8530_null_rx);static void z8530_rx_done(struct z8530_channel *c){ struct sk_buff *skb; int ct; /* * Is our receive engine in DMA mode */ if(c->rxdma_on) { /* * Save the ready state and the buffer currently * being used as the DMA target */ int ready=c->dma_ready; unsigned char *rxb=c->rx_buf[c->dma_num]; unsigned long flags; /* * Complete this DMA. Neccessary to find the length */ flags=claim_dma_lock(); disable_dma(c->rxdma); clear_dma_ff(c->rxdma); c->rxdma_on=0; ct=c->mtu-get_dma_residue(c->rxdma); if(ct<0) ct=2; /* Shit happens.. */ c->dma_ready=0; /* * Normal case: the other slot is free, start the next DMA * into it immediately. */ if(ready) { c->dma_num^=1; set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num])); set_dma_count(c->rxdma, c->mtu); c->rxdma_on = 1; enable_dma(c->rxdma); /* Stop any frames that we missed the head of from passing */ write_zsreg(c, R0, RES_Rx_CRC); } else /* Can't occur as we dont reenable the DMA irq until after the flip is done */ printk("DMA flip overrun!\n"); release_dma_lock(flags); /* * Shove the old buffer into an sk_buff. We can't DMA * directly into one on a PC - it might be above the 16Mb * boundary. Optimisation - we could check to see if we * can avoid the copy. Optimisation 2 - make the memcpy * a copychecksum. */ skb=dev_alloc_skb(ct); if(skb==NULL) { c->stats.rx_dropped++; printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name); } else { skb_put(skb, ct); memcpy(skb->data, rxb, ct); c->stats.rx_packets++; c->stats.rx_bytes+=ct; } c->dma_ready=1; } else { RT_LOCK; skb=c->skb; /* * The game we play for non DMA is similar. We want to * get the controller set up for the next packet as fast * as possible. We potentially only have one byte + the * fifo length for this. Thus we want to flip to the new * buffer and then mess around copying and allocating * things. For the current case it doesn't matter but * if you build a system where the sync irq isnt blocked * by the kernel IRQ disable then you need only block the * sync IRQ for the RT_LOCK area. * */ ct=c->count; c->skb = c->skb2; c->count = 0; c->max = c->mtu; if(c->skb) { c->dptr = c->skb->data; c->max = c->mtu; } else { c->count= 0; c->max = 0; } RT_UNLOCK; c->skb2 = dev_alloc_skb(c->mtu); if(c->skb2==NULL) printk(KERN_WARNING "%s: memory squeeze.\n", c->netdevice->name); else { skb_put(c->skb2,c->mtu); } c->stats.rx_packets++; c->stats.rx_bytes+=ct; } /* * If we received a frame we must now process it. */ if(skb) { skb_trim(skb, ct); c->rx_function(c,skb); } else { c->stats.rx_dropped++; printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name); }}/* * Cannot DMA over a 64K boundary on a PC */ extern inline int spans_boundary(struct sk_buff *skb){ unsigned long a=(unsigned long)skb->data; a^=(a+skb->len); if(a&0x00010000) /* If the 64K bit is different.. */ { printk("spanner\n"); return 1; } return 0;}/* * Queue a packet for transmission. Because we have rather * hard to hit interrupt latencies for the Z85230 per packet * even in DMA mode we do the flip to DMA buffer if needed here * not in the IRQ. */int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb){ unsigned long flags; if(c->tx_next_skb) { skb->dev->tbusy=1; return 1; } /* PC SPECIFIC - DMA limits */ /* * If we will DMA the transmit and its gone over the ISA bus * limit, then copy to the flip buffer */ if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb))) { /* * Send the flip buffer, and flip the flippy bit. * We don't care which is used when just so long as * we never use the same buffer twice in a row. Since * only one buffer can be going out at a time the other * has to be safe. */ c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used]; c->tx_dma_used^=1; /* Flip temp buffer */ memcpy(c->tx_next_ptr, skb->data, skb->len); } else c->tx_next_ptr=skb->data; RT_LOCK; c->tx_next_skb=skb; RT_UNLOCK; spin_lock_irqsave(&z8530_buffer_lock, flags); z8530_tx_begin(c); spin_unlock_irqrestore(&z8530_buffer_lock, flags); return 0;}EXPORT_SYMBOL(z8530_queue_xmit);struct net_device_stats *z8530_get_stats(struct z8530_channel *c){ return &c->stats;}EXPORT_SYMBOL(z8530_get_stats);#ifdef MODULE/* * Module support */ int init_module(void){ printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"); return 0;}void cleanup_module(void){}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -