📄 8390.c
字号:
/*** File: 8390.c May 02, 2000**** Author: Giovanni Falzoni <gfalzoni@inwind.it>**** This file contains an ethernet device driver for NICs** equipped with the National Semiconductor NS 8390 chip.** It has to be associated with the board specific driver.** Rewritten from Minix 2.0.0 ethernet driver dp8390.c** to extract the NS 8390 common functions.**** $Id: 8390.c,v 1.4 2005/09/04 18:52:16 beng Exp $*/#include "drivers.h"#include <minix/com.h>#include <net/hton.h>#include <net/gen/ether.h>#include <net/gen/eth_io.h>#include "dp.h"#if (ENABLE_DP8390 == 1)#define PIO16 0 /* NOTE: pio 16 functions missing */#include "8390.h"#define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \ sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\ (dstProc),D,(vir_bytes)(dstOffs),length)#define sys_user2nic(srcProc,srcOffs,dstOffs,length) \ sys_vircopy((srcProc),D,(vir_bytes)(srcOffs),\ SELF,dep->de_memsegm,(vir_bytes)(dstOffs),length)static const char RdmaErrMsg[] = "remote dma failed to complete";/*** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);** Function: Sets the board for reading/writing.*/static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset){ if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC); outb_reg0(dep, DP_RBCR0, size & 0xFF); outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF); outb_reg0(dep, DP_RSAR0, offset & 0xFF); outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF); mode |= (CR_PS_P0 | CR_STA); outb_reg0(dep, DP_CR, mode); return;}/*** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno);** Function: Sets the board for for transmitting and fires it.*/static void ns_start_xmit(dpeth_t * dep, int size, int pageno){ outb_reg0(dep, DP_TPSR, pageno); outb_reg0(dep, DP_TBCR1, size >> 8); outb_reg0(dep, DP_TBCR0, size & 0xFF); outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */ return;}/*** Name: void mem_getblock(dpeth_t *dep, u16_t offset,** int size, void *dst)** Function: Reads a block of packet from board (shared memory).*/static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst){ sys_nic2mem(dep->de_linmem + offset, SELF, dst, size); return;}/*** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);** Function: Copies a packet from board to user area (shared memory).*/static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize){ phys_bytes offset, phys_user; iovec_dat_t *iovp = &dep->de_read_iovec; int bytes, ix = 0; /* Computes shared memory address (skipping receive header) */ offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); do { /* Reads chuncks of packet into user area */ bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ if (bytes > pktsize) bytes = pktsize; /* Reads from board to user area */ if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { /* Circular buffer wrap-around */ bytes = dep->de_stoppage * DP_PAGESIZE - offset; sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); pktsize -= bytes; phys_user += bytes; bytes = iovp->iod_iovec[ix].iov_size - bytes; if (bytes > pktsize) bytes = pktsize; offset = dep->de_startpage * DP_PAGESIZE; } sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); offset += bytes; if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ dp_next_iovec(iovp); ix = 0; } /* Till packet done */ } while ((pktsize -= bytes) > 0); return;}/*** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)** Function: Copies a packet from user area to board (shared memory).*/static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize){ phys_bytes offset, phys_user; iovec_dat_t *iovp = &dep->de_write_iovec; int bytes, ix = 0; /* Computes shared memory address */ offset = pageno * DP_PAGESIZE; do { /* Reads chuncks of packet from user area */ bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ if (bytes > pktsize) bytes = pktsize; /* Reads from user area to board (shared memory) */ sys_user2nic(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, dep->de_linmem + offset, bytes); offset += bytes; if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ dp_next_iovec(iovp); ix = 0; } /* Till packet done */ } while ((pktsize -= bytes) > 0); return;}/*** Name: void pio_getblock(dpeth_t *dep, u16_t offset,** int size, void *dst)** Function: Reads a block of packet from board (Prog. I/O).*/static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst){ /* Sets up board for reading */ ns_rw_setup(dep, CR_DM_RR, size, offset);#if PIO16 == 0 insb(dep->de_data_port, SELF, dst, size);#else if (dep->de_16bit == TRUE) { insw(dep->de_data_port, dst, size); } else { insb(dep->de_data_port, dst, size); }#endif return;}/*** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)** Function: Copies a packet from board to user area (Prog. I/O).*/static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize){ phys_bytes phys_user; iovec_dat_t *iovp = &dep->de_read_iovec; unsigned offset; int bytes, ix = 0; /* Computes memory address (skipping receive header) */ offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); /* Sets up board for reading */ ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ? (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset); do { /* Reads chuncks of packet into user area */ bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ if (bytes > pktsize) bytes = pktsize; if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { /* Circular buffer wrap-around */ bytes = dep->de_stoppage * DP_PAGESIZE - offset; insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes); pktsize -= bytes; iovp->iod_iovec[ix].iov_addr += bytes; bytes = iovp->iod_iovec[ix].iov_size - bytes; if (bytes > pktsize) bytes = pktsize; offset = dep->de_startpage * DP_PAGESIZE; ns_rw_setup(dep, CR_DM_RR, pktsize, offset); } insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes); offset += bytes; if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ dp_next_iovec(iovp); ix = 0; } /* Till packet done */ } while ((pktsize -= bytes) > 0); return;}/*** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)** Function: Copies a packet from user area to board (Prog. I/O).*/static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize){ phys_bytes phys_user; iovec_dat_t *iovp = &dep->de_write_iovec; int bytes, ix = 0; /* Sets up board for writing */ ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE); do { /* Reads chuncks of packet from user area */ bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ if (bytes > pktsize) bytes = pktsize; outsb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes); if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ dp_next_iovec(iovp); ix = 0; } /* Till packet done */ } while ((pktsize -= bytes) > 0); for (ix = 0; ix < 100; ix += 1) { if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; } if (ix == 100) { panic(dep->de_name, RdmaErrMsg, NO_NUM); } return;}/*** Name: void ns_stats(dpeth_t * dep)** Function: Updates counters reading from device*/static void ns_stats(dpeth_t * dep){ dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); return;}/*** Name: void ns_dodump(dpeth_t * dep)** Function: Displays statistics (a request from F5 key).*/static void ns_dodump(dpeth_t * dep){ ns_stats(dep); /* Forces reading fo counters from board */ return;}/*** Name: void ns_reinit(dpeth_t *dep)** Function: Updates receiver configuration.*/static void ns_reinit(dpeth_t * dep){ int dp_reg = 0; if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM; if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB; if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM; outb_reg0(dep, DP_CR, CR_PS_P0); outb_reg0(dep, DP_RCR, dp_reg); return;}/*** Name: void ns_send(dpeth_t * dep, int from_int, int size)** Function: Transfers packet to device and starts sending.*/static void ns_send(dpeth_t * dep, int from_int, int size){ int queue; if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) { if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM); dep->de_send_s = size; return; } (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size); dep->bytes_Tx += (long) size; dep->de_sendq[queue].sq_filled = TRUE; dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); if (dep->de_sendq_tail == queue) { /* there it goes.. */ ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage); } else dep->de_sendq[queue].sq_size = size; if (++queue == dep->de_sendq_nr) queue = 0; dep->de_sendq_head = queue; dep->de_flags &= NOT(DEF_SENDING); return;}/*** Name: void ns_reset(dpeth_t *dep)** Function: Resets device.*/static void ns_reset(dpeth_t * dep){ int ix; /* Stop chip */ outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA); outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1) /* Do nothing */ ; outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST); outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST); /* Acknowledge the ISR_RDC (remote dma) interrupt. */ for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1) /* Do nothing */ ; outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC)); /* Reset the transmit ring. If we were transmitting a packet, we * pretend that the packet is processed. Higher layers will * retransmit if the packet wasn't actually sent. */ dep->de_sendq_head = dep->de_sendq_tail = 0; for (ix = 0; ix < dep->de_sendq_nr; ix++) dep->de_sendq[ix].sq_filled = FALSE; ns_send(dep, TRUE, dep->de_send_s); return;}/*** Name: void ns_recv(dpeth_t *dep, int fromint, int size)** Function: Gets a packet from device*/static void ns_recv(dpeth_t *dep, int fromint, int size){ dp_rcvhdr_t header; dp_rcvhdr_t dummy;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -