[9] | 1 | /*
|
---|
| 2 | ** File: 8390.c May 02, 2000
|
---|
| 3 | **
|
---|
| 4 | ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
---|
| 5 | **
|
---|
| 6 | ** This file contains an ethernet device driver for NICs
|
---|
| 7 | ** equipped with the National Semiconductor NS 8390 chip.
|
---|
| 8 | ** It has to be associated with the board specific driver.
|
---|
| 9 | ** Rewritten from Minix 2.0.0 ethernet driver dp8390.c
|
---|
| 10 | ** to extract the NS 8390 common functions.
|
---|
| 11 | **
|
---|
| 12 | ** $Id: 8390.c,v 1.4 2005/09/04 18:52:16 beng Exp $
|
---|
| 13 | */
|
---|
| 14 |
|
---|
| 15 | #include "drivers.h"
|
---|
| 16 | #include <minix/com.h>
|
---|
| 17 | #include <net/hton.h>
|
---|
| 18 | #include <net/gen/ether.h>
|
---|
| 19 | #include <net/gen/eth_io.h>
|
---|
| 20 | #include "dp.h"
|
---|
| 21 |
|
---|
| 22 | #if (ENABLE_DP8390 == 1)
|
---|
| 23 |
|
---|
| 24 | #define PIO16 0 /* NOTE: pio 16 functions missing */
|
---|
| 25 |
|
---|
| 26 | #include "8390.h"
|
---|
| 27 |
|
---|
| 28 | #define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
|
---|
| 29 | sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
|
---|
| 30 | (dstProc),D,(vir_bytes)(dstOffs),length)
|
---|
| 31 | #define sys_user2nic(srcProc,srcOffs,dstOffs,length) \
|
---|
| 32 | sys_vircopy((srcProc),D,(vir_bytes)(srcOffs),\
|
---|
| 33 | SELF,dep->de_memsegm,(vir_bytes)(dstOffs),length)
|
---|
| 34 |
|
---|
| 35 | static const char RdmaErrMsg[] = "remote dma failed to complete";
|
---|
| 36 |
|
---|
| 37 | /*
|
---|
| 38 | ** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
|
---|
| 39 | ** Function: Sets the board for reading/writing.
|
---|
| 40 | */
|
---|
| 41 | static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset)
|
---|
| 42 | {
|
---|
| 43 |
|
---|
| 44 | if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
|
---|
| 45 | outb_reg0(dep, DP_RBCR0, size & 0xFF);
|
---|
| 46 | outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
|
---|
| 47 | outb_reg0(dep, DP_RSAR0, offset & 0xFF);
|
---|
| 48 | outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
|
---|
| 49 | mode |= (CR_PS_P0 | CR_STA);
|
---|
| 50 | outb_reg0(dep, DP_CR, mode);
|
---|
| 51 | return;
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | /*
|
---|
| 55 | ** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno);
|
---|
| 56 | ** Function: Sets the board for for transmitting and fires it.
|
---|
| 57 | */
|
---|
| 58 | static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
|
---|
| 59 | {
|
---|
| 60 |
|
---|
| 61 | outb_reg0(dep, DP_TPSR, pageno);
|
---|
| 62 | outb_reg0(dep, DP_TBCR1, size >> 8);
|
---|
| 63 | outb_reg0(dep, DP_TBCR0, size & 0xFF);
|
---|
| 64 | outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
|
---|
| 65 | return;
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | /*
|
---|
| 69 | ** Name: void mem_getblock(dpeth_t *dep, u16_t offset,
|
---|
| 70 | ** int size, void *dst)
|
---|
| 71 | ** Function: Reads a block of packet from board (shared memory).
|
---|
| 72 | */
|
---|
| 73 | static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
---|
| 74 | {
|
---|
| 75 |
|
---|
| 76 | sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
|
---|
| 77 | return;
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | /*
|
---|
| 81 | ** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
|
---|
| 82 | ** Function: Copies a packet from board to user area (shared memory).
|
---|
| 83 | */
|
---|
| 84 | static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
|
---|
| 85 | {
|
---|
| 86 | phys_bytes offset, phys_user;
|
---|
| 87 | iovec_dat_t *iovp = &dep->de_read_iovec;
|
---|
| 88 | int bytes, ix = 0;
|
---|
| 89 |
|
---|
| 90 | /* Computes shared memory address (skipping receive header) */
|
---|
| 91 | offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
---|
| 92 |
|
---|
| 93 | do { /* Reads chuncks of packet into user area */
|
---|
| 94 |
|
---|
| 95 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
---|
| 96 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 97 |
|
---|
| 98 | /* Reads from board to user area */
|
---|
| 99 | if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
---|
| 100 |
|
---|
| 101 | /* Circular buffer wrap-around */
|
---|
| 102 | bytes = dep->de_stoppage * DP_PAGESIZE - offset;
|
---|
| 103 | sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
|
---|
| 104 | iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
| 105 | pktsize -= bytes;
|
---|
| 106 | phys_user += bytes;
|
---|
| 107 | bytes = iovp->iod_iovec[ix].iov_size - bytes;
|
---|
| 108 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 109 | offset = dep->de_startpage * DP_PAGESIZE;
|
---|
| 110 | }
|
---|
| 111 | sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
|
---|
| 112 | iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
| 113 | offset += bytes;
|
---|
| 114 |
|
---|
| 115 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
| 116 | dp_next_iovec(iovp);
|
---|
| 117 | ix = 0;
|
---|
| 118 | }
|
---|
| 119 | /* Till packet done */
|
---|
| 120 | } while ((pktsize -= bytes) > 0);
|
---|
| 121 | return;
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | /*
|
---|
| 125 | ** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 126 | ** Function: Copies a packet from user area to board (shared memory).
|
---|
| 127 | */
|
---|
| 128 | static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 129 | {
|
---|
| 130 | phys_bytes offset, phys_user;
|
---|
| 131 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
| 132 | int bytes, ix = 0;
|
---|
| 133 |
|
---|
| 134 | /* Computes shared memory address */
|
---|
| 135 | offset = pageno * DP_PAGESIZE;
|
---|
| 136 |
|
---|
| 137 | do { /* Reads chuncks of packet from user area */
|
---|
| 138 |
|
---|
| 139 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
---|
| 140 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 141 |
|
---|
| 142 | /* Reads from user area to board (shared memory) */
|
---|
| 143 | sys_user2nic(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
|
---|
| 144 | dep->de_linmem + offset, bytes);
|
---|
| 145 | offset += bytes;
|
---|
| 146 |
|
---|
| 147 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
| 148 | dp_next_iovec(iovp);
|
---|
| 149 | ix = 0;
|
---|
| 150 | }
|
---|
| 151 | /* Till packet done */
|
---|
| 152 | } while ((pktsize -= bytes) > 0);
|
---|
| 153 | return;
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 | /*
|
---|
| 157 | ** Name: void pio_getblock(dpeth_t *dep, u16_t offset,
|
---|
| 158 | ** int size, void *dst)
|
---|
| 159 | ** Function: Reads a block of packet from board (Prog. I/O).
|
---|
| 160 | */
|
---|
| 161 | static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
---|
| 162 | {
|
---|
| 163 |
|
---|
| 164 | /* Sets up board for reading */
|
---|
| 165 | ns_rw_setup(dep, CR_DM_RR, size, offset);
|
---|
| 166 |
|
---|
| 167 | #if PIO16 == 0
|
---|
| 168 | insb(dep->de_data_port, SELF, dst, size);
|
---|
| 169 | #else
|
---|
| 170 | if (dep->de_16bit == TRUE) {
|
---|
| 171 | insw(dep->de_data_port, dst, size);
|
---|
| 172 | } else {
|
---|
| 173 | insb(dep->de_data_port, dst, size);
|
---|
| 174 | }
|
---|
| 175 | #endif
|
---|
| 176 | return;
|
---|
| 177 | }
|
---|
| 178 |
|
---|
| 179 | /*
|
---|
| 180 | ** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 181 | ** Function: Copies a packet from board to user area (Prog. I/O).
|
---|
| 182 | */
|
---|
| 183 | static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 184 | {
|
---|
| 185 | phys_bytes phys_user;
|
---|
| 186 | iovec_dat_t *iovp = &dep->de_read_iovec;
|
---|
| 187 | unsigned offset; int bytes, ix = 0;
|
---|
| 188 |
|
---|
| 189 | /* Computes memory address (skipping receive header) */
|
---|
| 190 | offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
---|
| 191 | /* Sets up board for reading */
|
---|
| 192 | ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
|
---|
| 193 | (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
|
---|
| 194 |
|
---|
| 195 | do { /* Reads chuncks of packet into user area */
|
---|
| 196 |
|
---|
| 197 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
---|
| 198 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 199 |
|
---|
| 200 | if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
---|
| 201 |
|
---|
| 202 | /* Circular buffer wrap-around */
|
---|
| 203 | bytes = dep->de_stoppage * DP_PAGESIZE - offset;
|
---|
| 204 | insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
---|
| 205 | pktsize -= bytes;
|
---|
| 206 | iovp->iod_iovec[ix].iov_addr += bytes;
|
---|
| 207 | bytes = iovp->iod_iovec[ix].iov_size - bytes;
|
---|
| 208 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 209 | offset = dep->de_startpage * DP_PAGESIZE;
|
---|
| 210 | ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
|
---|
| 211 | }
|
---|
| 212 | insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
---|
| 213 | offset += bytes;
|
---|
| 214 |
|
---|
| 215 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
| 216 | dp_next_iovec(iovp);
|
---|
| 217 | ix = 0;
|
---|
| 218 | }
|
---|
| 219 | /* Till packet done */
|
---|
| 220 | } while ((pktsize -= bytes) > 0);
|
---|
| 221 | return;
|
---|
| 222 | }
|
---|
| 223 |
|
---|
| 224 | /*
|
---|
| 225 | ** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 226 | ** Function: Copies a packet from user area to board (Prog. I/O).
|
---|
| 227 | */
|
---|
| 228 | static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 229 | {
|
---|
| 230 | phys_bytes phys_user;
|
---|
| 231 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
| 232 | int bytes, ix = 0;
|
---|
| 233 |
|
---|
| 234 | /* Sets up board for writing */
|
---|
| 235 | ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
|
---|
| 236 |
|
---|
| 237 | do { /* Reads chuncks of packet from user area */
|
---|
| 238 |
|
---|
| 239 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
---|
| 240 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 241 | outsb(dep->de_data_port, iovp->iod_proc_nr,
|
---|
| 242 | (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
---|
| 243 |
|
---|
| 244 | if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
|
---|
| 245 | dp_next_iovec(iovp);
|
---|
| 246 | ix = 0;
|
---|
| 247 | }
|
---|
| 248 | /* Till packet done */
|
---|
| 249 | } while ((pktsize -= bytes) > 0);
|
---|
| 250 |
|
---|
| 251 | for (ix = 0; ix < 100; ix += 1) {
|
---|
| 252 | if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
---|
| 253 | }
|
---|
| 254 | if (ix == 100) {
|
---|
| 255 | panic(dep->de_name, RdmaErrMsg, NO_NUM);
|
---|
| 256 | }
|
---|
| 257 | return;
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | /*
|
---|
| 261 | ** Name: void ns_stats(dpeth_t * dep)
|
---|
| 262 | ** Function: Updates counters reading from device
|
---|
| 263 | */
|
---|
| 264 | static void ns_stats(dpeth_t * dep)
|
---|
| 265 | {
|
---|
| 266 |
|
---|
| 267 | dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
|
---|
| 268 | dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
|
---|
| 269 | dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
---|
| 270 | return;
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | /*
|
---|
| 274 | ** Name: void ns_dodump(dpeth_t * dep)
|
---|
| 275 | ** Function: Displays statistics (a request from F5 key).
|
---|
| 276 | */
|
---|
| 277 | static void ns_dodump(dpeth_t * dep)
|
---|
| 278 | {
|
---|
| 279 |
|
---|
| 280 | ns_stats(dep); /* Forces reading fo counters from board */
|
---|
| 281 | return;
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | /*
|
---|
| 285 | ** Name: void ns_reinit(dpeth_t *dep)
|
---|
| 286 | ** Function: Updates receiver configuration.
|
---|
| 287 | */
|
---|
| 288 | static void ns_reinit(dpeth_t * dep)
|
---|
| 289 | {
|
---|
| 290 | int dp_reg = 0;
|
---|
| 291 |
|
---|
| 292 | if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
|
---|
| 293 | if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
|
---|
| 294 | if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
|
---|
| 295 | outb_reg0(dep, DP_CR, CR_PS_P0);
|
---|
| 296 | outb_reg0(dep, DP_RCR, dp_reg);
|
---|
| 297 | return;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | /*
|
---|
| 301 | ** Name: void ns_send(dpeth_t * dep, int from_int, int size)
|
---|
| 302 | ** Function: Transfers packet to device and starts sending.
|
---|
| 303 | */
|
---|
| 304 | static void ns_send(dpeth_t * dep, int from_int, int size)
|
---|
| 305 | {
|
---|
| 306 | int queue;
|
---|
| 307 |
|
---|
| 308 | if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
|
---|
| 309 | if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
|
---|
| 310 | dep->de_send_s = size;
|
---|
| 311 | return;
|
---|
| 312 | }
|
---|
| 313 | (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
|
---|
| 314 | dep->bytes_Tx += (long) size;
|
---|
| 315 | dep->de_sendq[queue].sq_filled = TRUE;
|
---|
| 316 | dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
|
---|
| 317 | if (dep->de_sendq_tail == queue) { /* there it goes.. */
|
---|
| 318 | ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
|
---|
| 319 | } else
|
---|
| 320 | dep->de_sendq[queue].sq_size = size;
|
---|
| 321 |
|
---|
| 322 | if (++queue == dep->de_sendq_nr) queue = 0;
|
---|
| 323 | dep->de_sendq_head = queue;
|
---|
| 324 | dep->de_flags &= NOT(DEF_SENDING);
|
---|
| 325 |
|
---|
| 326 | return;
|
---|
| 327 | }
|
---|
| 328 |
|
---|
| 329 | /*
|
---|
| 330 | ** Name: void ns_reset(dpeth_t *dep)
|
---|
| 331 | ** Function: Resets device.
|
---|
| 332 | */
|
---|
| 333 | static void ns_reset(dpeth_t * dep)
|
---|
| 334 | {
|
---|
| 335 | int ix;
|
---|
| 336 |
|
---|
| 337 | /* Stop chip */
|
---|
| 338 | outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
|
---|
| 339 | outb_reg0(dep, DP_RBCR0, 0);
|
---|
| 340 | outb_reg0(dep, DP_RBCR1, 0);
|
---|
| 341 | for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
|
---|
| 342 | /* Do nothing */ ;
|
---|
| 343 | outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
|
---|
| 344 | outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
|
---|
| 345 | outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
|
---|
| 346 |
|
---|
| 347 | /* Acknowledge the ISR_RDC (remote dma) interrupt. */
|
---|
| 348 | for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
|
---|
| 349 | /* Do nothing */ ;
|
---|
| 350 | outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
|
---|
| 351 |
|
---|
| 352 | /* Reset the transmit ring. If we were transmitting a packet, we
|
---|
| 353 | * pretend that the packet is processed. Higher layers will
|
---|
| 354 | * retransmit if the packet wasn't actually sent. */
|
---|
| 355 | dep->de_sendq_head = dep->de_sendq_tail = 0;
|
---|
| 356 | for (ix = 0; ix < dep->de_sendq_nr; ix++)
|
---|
| 357 | dep->de_sendq[ix].sq_filled = FALSE;
|
---|
| 358 | ns_send(dep, TRUE, dep->de_send_s);
|
---|
| 359 | return;
|
---|
| 360 | }
|
---|
| 361 |
|
---|
| 362 | /*
|
---|
| 363 | ** Name: void ns_recv(dpeth_t *dep, int fromint, int size)
|
---|
| 364 | ** Function: Gets a packet from device
|
---|
| 365 | */
|
---|
| 366 | static void ns_recv(dpeth_t *dep, int fromint, int size)
|
---|
| 367 | {
|
---|
| 368 | dp_rcvhdr_t header;
|
---|
| 369 | dp_rcvhdr_t dummy;
|
---|
| 370 | unsigned pageno, curr, next;
|
---|
| 371 | vir_bytes length;
|
---|
| 372 | int packet_processed = FALSE;
|
---|
| 373 | #ifdef ETH_IGN_PROTO
|
---|
| 374 | u16_t eth_type;
|
---|
| 375 | #endif
|
---|
| 376 |
|
---|
| 377 | pageno = inb_reg0(dep, DP_BNRY) + 1;
|
---|
| 378 | if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
|
---|
| 379 |
|
---|
| 380 | do {
|
---|
| 381 | /* */
|
---|
| 382 | outb_reg0(dep, DP_CR, CR_PS_P1);
|
---|
| 383 | curr = inb_reg1(dep, DP_CURR);
|
---|
| 384 | outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
|
---|
| 385 |
|
---|
| 386 | if (curr == pageno) break;
|
---|
| 387 |
|
---|
| 388 | (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
|
---|
| 389 | #ifdef ETH_IGN_PROTO
|
---|
| 390 | (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type);
|
---|
| 391 | #endif
|
---|
| 392 | length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
|
---|
| 393 | next = header.dr_next;
|
---|
| 394 |
|
---|
| 395 | if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
|
---|
| 396 | printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
|
---|
| 397 | dep->de_stat.ets_recvErr += 1;
|
---|
| 398 | next = curr;
|
---|
| 399 |
|
---|
| 400 | } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
|
---|
| 401 | printf("%s: strange next page\n", dep->de_name);
|
---|
| 402 | dep->de_stat.ets_recvErr += 1;
|
---|
| 403 | next = curr;
|
---|
| 404 |
|
---|
| 405 | #ifdef ETH_IGN_PROTO
|
---|
| 406 | } else if (eth_type == eth_ign_proto) {
|
---|
| 407 | /* Hack: ignore packets of a given protocol */
|
---|
| 408 | static int first = TRUE;
|
---|
| 409 | if (first) {
|
---|
| 410 | first = FALSE;
|
---|
| 411 | printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
|
---|
| 412 | }
|
---|
| 413 | next = curr;
|
---|
| 414 | #endif
|
---|
| 415 | } else if (header.dr_status & RSR_FO) {
|
---|
| 416 | /* This is very serious, issue a warning and reset buffers */
|
---|
| 417 | printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
|
---|
| 418 | dep->de_stat.ets_fifoOver += 1;
|
---|
| 419 | next = curr;
|
---|
| 420 |
|
---|
| 421 | } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
|
---|
| 422 |
|
---|
| 423 | if (!(dep->de_flags & DEF_READING)) break;
|
---|
| 424 |
|
---|
| 425 | (dep->de_nic2userf) (dep, pageno, length);
|
---|
| 426 | dep->de_read_s = length;
|
---|
| 427 | dep->de_flags |= DEF_ACK_RECV;
|
---|
| 428 | dep->de_flags &= NOT(DEF_READING);
|
---|
| 429 | packet_processed = TRUE;
|
---|
| 430 | }
|
---|
| 431 | dep->bytes_Rx += (long) length;
|
---|
| 432 | dep->de_stat.ets_packetR += 1;
|
---|
| 433 | outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
|
---|
| 434 | pageno = next;
|
---|
| 435 |
|
---|
| 436 | } while (!packet_processed);
|
---|
| 437 | #if 0
|
---|
| 438 | if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
|
---|
| 439 | /* The chip is stopped, and all arrived packets delivered */
|
---|
| 440 | (*dep->de_resetf) (dep);
|
---|
| 441 | dep->de_flags &= NOT(DEF_STOPPED);
|
---|
| 442 | #endif
|
---|
| 443 | return;
|
---|
| 444 | }
|
---|
| 445 |
|
---|
| 446 | /*
|
---|
| 447 | ** Name: void ns_interrupt(dpeth_t * dep)
|
---|
| 448 | ** Function: Handles interrupt.
|
---|
| 449 | */
|
---|
| 450 | static void ns_interrupt(dpeth_t * dep)
|
---|
| 451 | {
|
---|
| 452 | int isr, tsr;
|
---|
| 453 | int size, queue;
|
---|
| 454 |
|
---|
| 455 | while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
|
---|
| 456 |
|
---|
| 457 | outb_reg0(dep, DP_ISR, isr);
|
---|
| 458 | if (isr & (ISR_PTX | ISR_TXE)) {
|
---|
| 459 |
|
---|
| 460 | tsr = inb_reg0(dep, DP_TSR);
|
---|
| 461 | if (tsr & TSR_PTX) {
|
---|
| 462 | dep->de_stat.ets_packetT++;
|
---|
| 463 | }
|
---|
| 464 | if (tsr & TSR_COL) dep->de_stat.ets_collision++;
|
---|
| 465 | if (tsr & (TSR_ABT | TSR_FU)) {
|
---|
| 466 | dep->de_stat.ets_fifoUnder++;
|
---|
| 467 | }
|
---|
| 468 | if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
|
---|
| 469 | printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
|
---|
| 470 | dep->de_stat.ets_sendErr++;
|
---|
| 471 | }
|
---|
| 472 | queue = dep->de_sendq_tail;
|
---|
| 473 |
|
---|
| 474 | if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
|
---|
| 475 | printf("%s: transmit interrupt, but not sending\n", dep->de_name);
|
---|
| 476 | continue;
|
---|
| 477 | }
|
---|
| 478 | dep->de_sendq[queue].sq_filled = FALSE;
|
---|
| 479 | if (++queue == dep->de_sendq_nr) queue = 0;
|
---|
| 480 | dep->de_sendq_tail = queue;
|
---|
| 481 | if (dep->de_sendq[queue].sq_filled) {
|
---|
| 482 | ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
|
---|
| 483 | dep->de_sendq[queue].sq_sendpage);
|
---|
| 484 | }
|
---|
| 485 | if (dep->de_flags & DEF_SENDING) {
|
---|
| 486 | ns_send(dep, TRUE, dep->de_send_s);
|
---|
| 487 | }
|
---|
| 488 | }
|
---|
| 489 | if (isr & ISR_PRX) {
|
---|
| 490 | ns_recv(dep, TRUE, 0);
|
---|
| 491 | }
|
---|
| 492 | if (isr & ISR_RXE) {
|
---|
| 493 | printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
|
---|
| 494 | dep->de_stat.ets_recvErr++;
|
---|
| 495 | }
|
---|
| 496 | if (isr & ISR_CNT) {
|
---|
| 497 | dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
|
---|
| 498 | dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
|
---|
| 499 | dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
---|
| 500 | }
|
---|
| 501 | if (isr & ISR_OVW) {
|
---|
| 502 | printf("%s: got overwrite warning\n", dep->de_name);
|
---|
| 503 | }
|
---|
| 504 | if (isr & ISR_RDC) {
|
---|
| 505 | /* Nothing to do */
|
---|
| 506 | }
|
---|
| 507 | if (isr & ISR_RST) {
|
---|
| 508 | /* This means we got an interrupt but the ethernet
|
---|
| 509 | * chip is shutdown. We set the flag DEF_STOPPED, and
|
---|
| 510 | * continue processing arrived packets. When the
|
---|
| 511 | * receive buffer is empty, we reset the dp8390. */
|
---|
| 512 | printf("%s: network interface stopped\n", dep->de_name);
|
---|
| 513 | dep->de_flags |= DEF_STOPPED;
|
---|
| 514 | break;
|
---|
| 515 | }
|
---|
| 516 | }
|
---|
| 517 | if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
|
---|
| 518 |
|
---|
| 519 | /* The chip is stopped, and all arrived packets delivered */
|
---|
| 520 | ns_reset(dep);
|
---|
| 521 | dep->de_flags &= NOT(DEF_STOPPED);
|
---|
| 522 | }
|
---|
| 523 | return;
|
---|
| 524 | }
|
---|
| 525 |
|
---|
| 526 | /*
|
---|
| 527 | ** Name: void ns_init(dpeth_t *dep)
|
---|
| 528 | ** Function: Initializes the NS 8390
|
---|
| 529 | */
|
---|
| 530 | void ns_init(dpeth_t * dep)
|
---|
| 531 | {
|
---|
| 532 | int dp_reg;
|
---|
| 533 | int ix;
|
---|
| 534 |
|
---|
| 535 | /* NS8390 initialization (as recommended in National Semiconductor specs) */
|
---|
| 536 | outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
|
---|
| 537 | #if PIO16 == 0
|
---|
| 538 | outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
---|
| 539 | #else
|
---|
| 540 | outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
|
---|
| 541 | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
---|
| 542 | #endif
|
---|
| 543 | outb_reg0(dep, DP_RBCR0, 0);
|
---|
| 544 | outb_reg0(dep, DP_RBCR1, 0);
|
---|
| 545 | outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
|
---|
| 546 | outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
|
---|
| 547 | outb_reg0(dep, DP_PSTART, dep->de_startpage);
|
---|
| 548 | outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
|
---|
| 549 | outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
|
---|
| 550 | outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
|
---|
| 551 | outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */
|
---|
| 552 |
|
---|
| 553 | /* Copies station address in page 1 registers */
|
---|
| 554 | outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
|
---|
| 555 | for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */
|
---|
| 556 | outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
|
---|
| 557 | for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */
|
---|
| 558 | outb_reg1(dep, ix, 0xFF);
|
---|
| 559 |
|
---|
| 560 | outb_reg1(dep, DP_CURR, dep->de_startpage);
|
---|
| 561 | outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
|
---|
| 562 |
|
---|
| 563 | inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */
|
---|
| 564 | inb_reg0(dep, DP_CNTR1);
|
---|
| 565 | inb_reg0(dep, DP_CNTR2);
|
---|
| 566 |
|
---|
| 567 | dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
|
---|
| 568 | outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
|
---|
| 569 | outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */
|
---|
| 570 |
|
---|
| 571 | dp_reg = 0;
|
---|
| 572 | if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
|
---|
| 573 | if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
|
---|
| 574 | if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
|
---|
| 575 | outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */
|
---|
| 576 | outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */
|
---|
| 577 |
|
---|
| 578 | outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */
|
---|
| 579 |
|
---|
| 580 | /* Initializes the send queue. */
|
---|
| 581 | for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
|
---|
| 582 | dep->de_sendq[ix].sq_filled = 0;
|
---|
| 583 | dep->de_sendq_head = dep->de_sendq_tail = 0;
|
---|
| 584 |
|
---|
| 585 | /* Device specific functions */
|
---|
| 586 | if (!dep->de_prog_IO) {
|
---|
| 587 | dep->de_user2nicf = mem_user2nic;
|
---|
| 588 | dep->de_nic2userf = mem_nic2user;
|
---|
| 589 | dep->de_getblockf = mem_getblock;
|
---|
| 590 | } else {
|
---|
| 591 | #if PIO16 == 0
|
---|
| 592 | dep->de_user2nicf = pio_user2nic;
|
---|
| 593 | dep->de_nic2userf = pio_nic2user;
|
---|
| 594 | dep->de_getblockf = pio_getblock;
|
---|
| 595 | #else
|
---|
| 596 | #error Missing I/O functions for pio 16 bits
|
---|
| 597 | #endif
|
---|
| 598 | }
|
---|
| 599 | dep->de_recvf = ns_recv;
|
---|
| 600 | dep->de_sendf = ns_send;
|
---|
| 601 | dep->de_flagsf = ns_reinit;
|
---|
| 602 | dep->de_resetf = ns_reset;
|
---|
| 603 | dep->de_getstatsf = ns_stats;
|
---|
| 604 | dep->de_dumpstatsf = ns_dodump;
|
---|
| 605 | dep->de_interruptf = ns_interrupt;
|
---|
| 606 |
|
---|
| 607 | return; /* Done */
|
---|
| 608 | }
|
---|
| 609 |
|
---|
| 610 | #if PIO16 == 1
|
---|
| 611 |
|
---|
| 612 | /*
|
---|
| 613 | ** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 614 | ** Function: Copies a packet from user area to board (Prog. I/O, 16bits).
|
---|
| 615 | */
|
---|
| 616 | static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 617 | {
|
---|
| 618 | u8_t two_bytes[2];
|
---|
| 619 | phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
|
---|
| 620 | vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
|
---|
| 621 | int bytes, ix = 0, odd_byte = 0;
|
---|
| 622 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
| 623 |
|
---|
| 624 | outb_reg0(dep, DP_ISR, ISR_RDC);
|
---|
| 625 | dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
|
---|
| 626 |
|
---|
| 627 | do {
|
---|
| 628 | bytes = iovp->iod_iovec[ix].iov_size;
|
---|
| 629 | if (bytes > pktsize) bytes = pktsize;
|
---|
| 630 |
|
---|
| 631 | phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
| 632 | if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
|
---|
| 633 |
|
---|
| 634 | if (odd_byte) {
|
---|
| 635 | phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
|
---|
| 636 | out_word(dep->de_data_port, *(u16_t *)two_bytes);
|
---|
| 637 | pktsize--;
|
---|
| 638 | bytes--;
|
---|
| 639 | phys_user++;
|
---|
| 640 | odd_byte = 0;
|
---|
| 641 | if (!bytes) continue;
|
---|
| 642 | }
|
---|
| 643 | ecount = bytes & NOT(0x0001);
|
---|
| 644 | if (ecount != 0) {
|
---|
| 645 | phys_outsw(dep->de_data_port, phys_user, ecount);
|
---|
| 646 | pktsize -= ecount;
|
---|
| 647 | bytes -= ecount;
|
---|
| 648 | phys_user += ecount;
|
---|
| 649 | }
|
---|
| 650 | if (bytes) {
|
---|
| 651 | phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
|
---|
| 652 | pktsize--;
|
---|
| 653 | bytes--;
|
---|
| 654 | phys_user++;
|
---|
| 655 | odd_byte = 1;
|
---|
| 656 | }
|
---|
| 657 | if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
|
---|
| 658 | dp_next_iovec(iovp);
|
---|
| 659 | ix = 0;
|
---|
| 660 | }
|
---|
| 661 |
|
---|
| 662 | } while (bytes > 0);
|
---|
| 663 |
|
---|
| 664 | if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
|
---|
| 665 | for (ix = 0; ix < 100; ix++) {
|
---|
| 666 | if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
---|
| 667 | }
|
---|
| 668 | if (ix == 100) {
|
---|
| 669 | panic(dep->de_name, RdmaErrMsg, NO_NUM);
|
---|
| 670 | }
|
---|
| 671 | return;
|
---|
| 672 | }
|
---|
| 673 |
|
---|
| 674 | /*
|
---|
| 675 | ** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
---|
| 676 | ** Function: Copies a packet from board to user area (Prog. I/O, 16bits).
|
---|
| 677 | */
|
---|
| 678 | static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
|
---|
| 679 | {
|
---|
| 680 | phys_bytes phys_user;
|
---|
| 681 | vir_bytes ecount;
|
---|
| 682 | int bytes, i;
|
---|
| 683 | u8_t two_bytes[2];
|
---|
| 684 | phys_bytes phys_2bytes;
|
---|
| 685 | int odd_byte;
|
---|
| 686 |
|
---|
| 687 | ecount = (count + 1) & ~1;
|
---|
| 688 | phys_2bytes = vir2phys(two_bytes);
|
---|
| 689 | odd_byte = 0;
|
---|
| 690 |
|
---|
| 691 | dp_read_setup(dep, ecount, nic_addr);
|
---|
| 692 |
|
---|
| 693 | i = 0;
|
---|
| 694 | while (count > 0) {
|
---|
| 695 | if (i >= IOVEC_NR) {
|
---|
| 696 | dp_next_iovec(iovp);
|
---|
| 697 | i = 0;
|
---|
| 698 | continue;
|
---|
| 699 | }
|
---|
| 700 | bytes = iovp->iod_iovec[i].iov_size;
|
---|
| 701 | if (bytes > count) bytes = count;
|
---|
| 702 |
|
---|
| 703 | phys_user = numap(iovp->iod_proc_nr,
|
---|
| 704 | iovp->iod_iovec[i].iov_addr, bytes);
|
---|
| 705 | if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
|
---|
| 706 | if (odd_byte) {
|
---|
| 707 | phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
|
---|
| 708 | count--;
|
---|
| 709 | bytes--;
|
---|
| 710 | phys_user++;
|
---|
| 711 | odd_byte = 0;
|
---|
| 712 | if (!bytes) continue;
|
---|
| 713 | }
|
---|
| 714 | ecount = bytes & ~1;
|
---|
| 715 | if (ecount != 0) {
|
---|
| 716 | phys_insw(dep->de_data_port, phys_user, ecount);
|
---|
| 717 | count -= ecount;
|
---|
| 718 | bytes -= ecount;
|
---|
| 719 | phys_user += ecount;
|
---|
| 720 | }
|
---|
| 721 | if (bytes) {
|
---|
| 722 | *(u16_t *) two_bytes = in_word(dep->de_data_port);
|
---|
| 723 | phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
|
---|
| 724 | count--;
|
---|
| 725 | bytes--;
|
---|
| 726 | phys_user++;
|
---|
| 727 | odd_byte = 1;
|
---|
| 728 | }
|
---|
| 729 | }
|
---|
| 730 | return;
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | #endif /* PIO16 == 1 */
|
---|
| 734 |
|
---|
| 735 | #endif /* ENABLE_DP8390 */
|
---|
| 736 |
|
---|
| 737 | /** end 8390.c **/
|
---|