1 /* $NetBSD: dp8390.c,v 1.6 2008/12/14 18:46:33 christos Exp $ */ 2 3 /* 4 * Polling driver for National Semiconductor DS8390/WD83C690 based 5 * ethernet adapters. 6 * 7 * Copyright (c) 1998 Matthias Drochner. All rights reserved. 8 * 9 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. 10 * 11 * Copyright (C) 1993, David Greenman. This software may be used, modified, 12 * copied, distributed, and sold, in both source and binary form provided that 13 * the above copyright and these terms are retained. Under no circumstances is 14 * the author responsible for the proper functioning of this software, nor does 15 * the author assume any responsibility for damages incurred with its use. 16 */ 17 18 #include <sys/types.h> 19 #include <machine/pio.h> 20 21 #include <lib/libsa/stand.h> 22 #include <libi386.h> 23 24 #include <dev/ic/dp8390reg.h> 25 #include "dp8390.h" 26 #ifdef SUPPORT_NE2000 27 #include "ne.h" 28 #endif 29 30 #include "etherdrv.h" 31 32 int dp8390_iobase, dp8390_membase, dp8390_memsize; 33 #if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA) 34 int dp8390_is790; 35 #endif 36 uint8_t dp8390_cr_proto; 37 uint8_t dp8390_dcr_reg; 38 39 #define WE_IOBASE dp8390_iobase 40 41 static u_short rec_page_start; 42 static u_short rec_page_stop; 43 static u_short next_packet; 44 45 extern u_char eth_myaddr[6]; 46 47 #ifndef _STANDALONE 48 static void *vmembase; 49 extern void *mapmem(int, int); 50 extern void unmapmem(void *, int); 51 extern int mapio(void); 52 53 static void 54 bbcopy(void *src, void *dst, int len) 55 { 56 char *s = (char *)src; 57 char *d = (char *)dst; 58 59 while (len--) 60 *d++ = *s++; 61 } 62 #endif 63 64 static void dp8390_read(int, char *, u_short); 65 66 #define NIC_GET(reg) inb(WE_IOBASE + reg) 67 #define NIC_PUT(reg, val) outb(WE_IOBASE + reg, val) 68 69 static void 70 dp8390_init(void) 71 { 72 int i; 73 74 /* 75 * Initialize the NIC in the exact order outlined in the NS manual. 76 * This init procedure is "mandatory"...don't change what or when 77 * things happen. 78 */ 79 80 /* Set interface for page 0, remote DMA complete, stopped. */ 81 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP); 82 83 if (dp8390_dcr_reg & ED_DCR_LS) { 84 NIC_PUT(ED_P0_DCR, dp8390_dcr_reg); 85 } else { 86 /* 87 * Set FIFO threshold to 8, No auto-init Remote DMA, byte 88 * order=80x86, byte-wide DMA xfers, 89 */ 90 NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); 91 } 92 93 /* Clear remote byte count registers. */ 94 NIC_PUT(ED_P0_RBCR0, 0); 95 NIC_PUT(ED_P0_RBCR1, 0); 96 97 /* Tell RCR to do nothing for now. */ 98 NIC_PUT(ED_P0_RCR, ED_RCR_MON); 99 100 /* Place NIC in internal loopback mode. */ 101 NIC_PUT(ED_P0_TCR, ED_TCR_LB0); 102 103 /* Set lower bits of byte addressable framing to 0. */ 104 if (dp8390_is790) 105 NIC_PUT(0x09, 0); 106 107 /* Initialize receive buffer ring. */ 108 NIC_PUT(ED_P0_BNRY, rec_page_start); 109 NIC_PUT(ED_P0_PSTART, rec_page_start); 110 NIC_PUT(ED_P0_PSTOP, rec_page_stop); 111 112 /* 113 * Clear all interrupts. A '1' in each bit position clears the 114 * corresponding flag. 115 */ 116 NIC_PUT(ED_P0_ISR, 0xff); 117 118 /* 119 * Disable all interrupts. 120 */ 121 NIC_PUT(ED_P0_IMR, 0); 122 123 /* Program command register for page 1. */ 124 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP); 125 126 /* Copy out our station address. */ 127 for (i = 0; i < 6; ++i) 128 NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]); 129 130 /* 131 * Set current page pointer to one page after the boundary pointer, as 132 * recommended in the National manual. 133 */ 134 next_packet = rec_page_start + 1; 135 NIC_PUT(ED_P1_CURR, next_packet); 136 137 /* Program command register for page 0. */ 138 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP); 139 140 /* directed and broadcast */ 141 NIC_PUT(ED_P0_RCR, ED_RCR_AB); 142 143 /* Take interface out of loopback. */ 144 NIC_PUT(ED_P0_TCR, 0); 145 146 /* Fire up the interface. */ 147 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA); 148 } 149 150 int 151 dp8390_config(void) 152 { 153 #ifndef _STANDALONE 154 if (mapio()) { 155 printf("no IO access\n"); 156 return -1; 157 } 158 vmembase = mapmem(dp8390_membase, dp8390_memsize); 159 if (!vmembase) { 160 printf("no memory access\n"); 161 return -1; 162 } 163 #endif 164 165 rec_page_start = TX_PAGE_START + ED_TXBUF_SIZE; 166 rec_page_stop = TX_PAGE_START + (dp8390_memsize >> ED_PAGE_SHIFT); 167 168 dp8390_init(); 169 170 return 0; 171 } 172 173 void 174 dp8390_stop(void) 175 { 176 int n = 5000; 177 178 /* Stop everything on the interface, and select page 0 registers. */ 179 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP); 180 181 /* 182 * Wait for interface to enter stopped state, but limit # of checks to 183 * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but 184 * just in case it's an old one. 185 */ 186 while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n) 187 continue; 188 189 #ifndef _STANDALONE 190 unmapmem(vmembase, dp8390_memsize); 191 #endif 192 } 193 194 int 195 EtherSend(char *pkt, int len) 196 { 197 #ifdef SUPPORT_NE2000 198 ne2000_writemem(pkt, dp8390_membase, len); 199 #else 200 #ifdef _STANDALONE 201 vpbcopy(pkt, (void *)dp8390_membase, len); 202 #else 203 bbcopy(pkt, vmembase, len); 204 #endif 205 #endif 206 207 /* Set TX buffer start page. */ 208 NIC_PUT(ED_P0_TPSR, TX_PAGE_START); 209 210 /* Set TX length. */ 211 NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len); 212 NIC_PUT(ED_P0_TBCR1, len >> 8); 213 214 /* Set page 0, remote DMA complete, transmit packet, and *start*. */ 215 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA); 216 217 return len; 218 } 219 220 static void 221 dp8390_read(int buf, char *dest, u_short len) 222 { 223 u_short tmp_amount; 224 225 /* Does copy wrap to lower addr in ring buffer? */ 226 if (buf + len > dp8390_membase + dp8390_memsize) { 227 tmp_amount = dp8390_membase + dp8390_memsize - buf; 228 229 /* Copy amount up to end of NIC memory. */ 230 #ifdef SUPPORT_NE2000 231 ne2000_readmem(buf, dest, tmp_amount); 232 #else 233 #ifdef _STANDALONE 234 pvbcopy((void *)buf, dest, tmp_amount); 235 #else 236 bbcopy(vmembase + buf - dp8390_membase, dest, tmp_amount); 237 #endif 238 #endif 239 240 len -= tmp_amount; 241 buf = RX_BUFBASE + (rec_page_start << ED_PAGE_SHIFT); 242 dest += tmp_amount; 243 } 244 #ifdef SUPPORT_NE2000 245 ne2000_readmem(buf, dest, len); 246 #else 247 #ifdef _STANDALONE 248 pvbcopy((void *)buf, dest, len); 249 #else 250 bbcopy(vmembase + buf - dp8390_membase, dest, len); 251 #endif 252 #endif 253 } 254 255 int 256 EtherReceive(char *pkt, int maxlen) 257 { 258 struct dp8390_ring packet_hdr; 259 int packet_ptr; 260 u_short len; 261 u_char boundary, current; 262 #ifdef DP8390_OLDCHIPS 263 u_char nlen; 264 #endif 265 266 if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX)) 267 return 0; /* XXX error handling */ 268 269 /* Set NIC to page 1 registers to get 'current' pointer. */ 270 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STA); 271 272 /* 273 * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. 274 * it points to where new data has been buffered. The 'CURR' (current) 275 * register points to the logical end of the ring-buffer - i.e. it 276 * points to where additional new data will be added. We loop here 277 * until the logical beginning equals the logical end (or in other 278 * words, until the ring-buffer is empty). 279 */ 280 current = NIC_GET(ED_P1_CURR); 281 282 /* Set NIC to page 0 registers to update boundary register. */ 283 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA); 284 285 if (next_packet == current) 286 return 0; 287 288 /* Get pointer to this buffer's header structure. */ 289 packet_ptr = RX_BUFBASE + (next_packet << ED_PAGE_SHIFT); 290 291 /* 292 * The byte count includes a 4 byte header that was added by 293 * the NIC. 294 */ 295 #ifdef SUPPORT_NE2000 296 ne2000_readmem(packet_ptr, (void *)&packet_hdr, 4); 297 #else 298 #ifdef _STANDALONE 299 pvbcopy((void *)packet_ptr, &packet_hdr, 4); 300 #else 301 bbcopy(vmembase + packet_ptr - dp8390_membase, &packet_hdr, 4); 302 #endif 303 #endif 304 305 len = packet_hdr.count; 306 307 #ifdef DP8390_OLDCHIPS 308 /* 309 * Try do deal with old, buggy chips that sometimes duplicate 310 * the low byte of the length into the high byte. We do this 311 * by simply ignoring the high byte of the length and always 312 * recalculating it. 313 * 314 * NOTE: sc->next_packet is pointing at the current packet. 315 */ 316 if (packet_hdr.next_packet >= next_packet) 317 nlen = (packet_hdr.next_packet - next_packet); 318 else 319 nlen = ((packet_hdr.next_packet - rec_page_start) + 320 (rec_page_stop - next_packet)); 321 --nlen; 322 if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE) 323 --nlen; 324 len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT); 325 #ifdef DIAGNOSTIC 326 if (len != packet_hdr.count) { 327 printf(IFNAME ": length does not match next packet pointer\n"); 328 printf(IFNAME ": len %04x nlen %04x start %02x " 329 "first %02x curr %02x next %02x stop %02x\n", 330 packet_hdr.count, len, 331 rec_page_start, next_packet, current, 332 packet_hdr.next_packet, rec_page_stop); 333 } 334 #endif 335 #endif 336 337 if (packet_hdr.next_packet < rec_page_start || 338 packet_hdr.next_packet >= rec_page_stop) 339 panic(IFNAME ": RAM corrupt"); 340 341 len -= sizeof(struct dp8390_ring); 342 if (len < maxlen) { 343 /* Go get packet. */ 344 dp8390_read(packet_ptr + sizeof(struct dp8390_ring), 345 pkt, len); 346 } else 347 len = 0; 348 349 /* Update next packet pointer. */ 350 next_packet = packet_hdr.next_packet; 351 352 /* 353 * Update NIC boundary pointer - being careful to keep it one 354 * buffer behind (as recommended by NS databook). 355 */ 356 boundary = next_packet - 1; 357 if (boundary < rec_page_start) 358 boundary = rec_page_stop - 1; 359 NIC_PUT(ED_P0_BNRY, boundary); 360 361 return len; 362 } 363