1/* $NetBSD: dp8390.c,v 1.5 2007/03/04 06:00:02 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 32int dp8390_iobase, dp8390_membase, dp8390_memsize; 33#if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA) 34int dp8390_is790; 35#endif 36uint8_t dp8390_cr_proto; 37uint8_t dp8390_dcr_reg; 38 39#define WE_IOBASE dp8390_iobase 40 41static u_short rec_page_start; 42static u_short rec_page_stop; 43static u_short next_packet; 44 45extern u_char eth_myaddr[6]; 46 47#ifndef _STANDALONE 48static void *vmembase; 49extern void *mapmem(int, int); 50extern void unmapmem(void *, int); 51extern int mapio(void); 52 53static void 54bbcopy(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 64static 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 69static void 70dp8390_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 150int 151dp8390_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 173void 174dp8390_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 194int 195EtherSend(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 220static void 221dp8390_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 255int 256EtherReceive(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