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