1 /* $NetBSD: if_le.c,v 1.6 2000/05/20 13:30:03 ragge Exp $ */ 2 /* 3 * Copyright (c) 1997, 1999 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of 17 * Lule}, Sweden and its contributors. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Standalone routine for MicroVAX LANCE chip. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/queue.h> 40 #include <sys/socket.h> 41 42 #include <net/if.h> 43 #include <net/if_ether.h> 44 45 #include <netinet/in.h> 46 #include <netinet/in_systm.h> 47 48 #include <../include/sid.h> 49 #include <../include/rpb.h> 50 51 #include <lib/libsa/netif.h> 52 #include <lib/libsa/stand.h> 53 54 #include <dev/ic/lancereg.h> 55 #include <dev/ic/am7990reg.h> 56 57 #include "vaxstand.h" 58 59 /* 60 * Buffer sizes. 61 */ 62 #define TLEN 1 63 #define NTBUF (1 << TLEN) 64 #define RLEN 3 65 #define NRBUF (1 << RLEN) 66 #define BUFSIZE 1518 67 68 #define QW_ALLOC(x) (((int)alloc((x) + 7) + 7) & ~7) 69 70 static int le_get(struct iodesc *, void *, size_t, time_t); 71 static int le_put(struct iodesc *, void *, size_t); 72 static void copyout(void *from, int dest, int len); 73 static void copyin(int src, void *to, int len); 74 75 struct netif_driver le_driver = { 76 0, 0, 0, 0, le_get, le_put, 77 }; 78 79 /* 80 * Init block & buffer descriptors according to DEC system 81 * specification documentation. 82 */ 83 struct initblock { 84 short ib_mode; 85 char ib_padr[6]; /* Ethernet address */ 86 int ib_ladrf1; 87 int ib_ladrf2; 88 int ib_rdr; /* Receive address */ 89 int ib_tdr; /* Transmit address */ 90 } *initblock = NULL; 91 92 struct nireg { 93 volatile u_short ni_rdp; /* data port */ 94 volatile short ni_pad0; 95 volatile short ni_rap; /* register select port */ 96 } *nireg; 97 98 99 volatile struct buffdesc { 100 int bd_adrflg; 101 short bd_bcnt; 102 short bd_mcnt; 103 } *rdesc, *tdesc; 104 105 static int addoff, kopiera = 0; 106 107 /* Flags in the address field */ 108 #define BR_OWN 0x80000000 109 #define BR_ERR 0x40000000 110 #define BR_FRAM 0x20000000 111 #define BR_OFLO 0x10000000 112 #define BR_CRC 0x08000000 113 #define BR_BUFF 0x04000000 114 #define BR_STP 0x02000000 115 #define BR_ENP 0x01000000 116 117 #define BT_OWN 0x80000000 118 #define BT_ERR 0x40000000 119 #define BT_MORE 0x10000000 120 #define BT_ONE 0x08000000 121 #define BT_DEF 0x04000000 122 #define BT_STP 0x02000000 123 #define BT_ENP 0x01000000 124 125 int next_rdesc, next_tdesc; 126 127 #define LEWRCSR(port, val) { \ 128 nireg->ni_rap = (port); \ 129 nireg->ni_rdp = (val); \ 130 } 131 132 #define LERDCSR(port) \ 133 (nireg->ni_rap = port, nireg->ni_rdp) 134 135 int 136 leopen(struct open_file *f, int adapt, int ctlr, int unit, int part) 137 { 138 int i, *ea; 139 volatile int to = 100000; 140 u_char eaddr[6]; 141 142 next_rdesc = next_tdesc = 0; 143 144 if (vax_boardtype == VAX_BTYP_650 && 145 ((vax_siedata >> 8) & 0xff) == VAX_SIE_KA640) { 146 kopiera = 1; 147 ea = (void *)0x20084200; 148 nireg = (void *)0x20084400; 149 } else { 150 *(int *)0x20080014 = 0; /* Be sure we do DMA in low 16MB */ 151 ea = (void *)0x20090000; /* XXX ethernetadressen */ 152 nireg = (void *)0x200e0000; 153 } 154 if (askname == 0) /* Override if autoboot */ 155 nireg = (void *)bootrpb.csrphy; 156 else /* Tell kernel from where we booted */ 157 bootrpb.csrphy = (int)nireg; 158 159 if (vax_boardtype == VAX_BTYP_43) 160 addoff = 0x28000000; 161 else 162 addoff = 0; 163 igen: 164 LEWRCSR(LE_CSR0, LE_C0_STOP); 165 while (to--) 166 ; 167 168 for (i = 0; i < 6; i++) 169 eaddr[i] = ea[i] & 0377; 170 171 if (initblock == NULL) { 172 (void *)initblock = 173 (char *)QW_ALLOC(sizeof(struct initblock)) + addoff; 174 initblock->ib_mode = LE_MODE_NORMAL; 175 bcopy(eaddr, initblock->ib_padr, 6); 176 initblock->ib_ladrf1 = 0; 177 initblock->ib_ladrf2 = 0; 178 179 (int)rdesc = QW_ALLOC(sizeof(struct buffdesc) * NRBUF) + addoff; 180 initblock->ib_rdr = (RLEN << 29) | (int)rdesc; 181 if (kopiera) 182 initblock->ib_rdr -= (int)initblock; 183 (int)tdesc = QW_ALLOC(sizeof(struct buffdesc) * NTBUF) + addoff; 184 initblock->ib_tdr = (TLEN << 29) | (int)tdesc; 185 if (kopiera) 186 initblock->ib_tdr -= (int)initblock; 187 if (kopiera) 188 copyout(initblock, 0, sizeof(struct initblock)); 189 190 for (i = 0; i < NRBUF; i++) { 191 rdesc[i].bd_adrflg = QW_ALLOC(BUFSIZE) | BR_OWN; 192 if (kopiera) 193 rdesc[i].bd_adrflg -= (int)initblock; 194 rdesc[i].bd_bcnt = -BUFSIZE; 195 rdesc[i].bd_mcnt = 0; 196 } 197 if (kopiera) 198 copyout((void *)rdesc, (int)rdesc - (int)initblock, 199 sizeof(struct buffdesc) * NRBUF); 200 201 for (i = 0; i < NTBUF; i++) { 202 tdesc[i].bd_adrflg = QW_ALLOC(BUFSIZE); 203 if (kopiera) 204 tdesc[i].bd_adrflg -= (int)initblock; 205 tdesc[i].bd_bcnt = 0xf000; 206 tdesc[i].bd_mcnt = 0; 207 } 208 if (kopiera) 209 copyout((void *)tdesc, (int)tdesc - (int)initblock, 210 sizeof(struct buffdesc) * NTBUF); 211 } 212 213 if (kopiera) { 214 LEWRCSR(LE_CSR1, 0); 215 LEWRCSR(LE_CSR2, 0); 216 } else { 217 LEWRCSR(LE_CSR1, (int)initblock & 0xffff); 218 LEWRCSR(LE_CSR2, ((int)initblock >> 16) & 0xff); 219 } 220 221 LEWRCSR(LE_CSR0, LE_C0_INIT); 222 223 to = 100000; 224 while (to--) { 225 if (LERDCSR(LE_CSR0) & LE_C0_IDON) 226 break; 227 if (LERDCSR(LE_CSR0) & LE_C0_ERR) { 228 printf("lance init error: csr0 %x\n", LERDCSR(LE_CSR0)); 229 goto igen; 230 } 231 } 232 233 LEWRCSR(LE_CSR0, LE_C0_INEA | LE_C0_STRT | LE_C0_IDON); 234 235 net_devinit(f, &le_driver, eaddr); 236 return 0; 237 } 238 239 int 240 le_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout) 241 { 242 int csr, len; 243 volatile int to = 100000 * timeout; 244 245 retry: 246 if (to-- == 0) 247 return 0; 248 249 csr = LERDCSR(LE_CSR0); 250 LEWRCSR(LE_CSR0, csr & (LE_C0_BABL|LE_C0_MISS|LE_C0_MERR|LE_C0_RINT)); 251 252 if (kopiera) 253 copyin((int)&rdesc[next_rdesc] - (int)initblock, 254 (void *)&rdesc[next_rdesc], sizeof(struct buffdesc)); 255 if (rdesc[next_rdesc].bd_adrflg & BR_OWN) 256 goto retry; 257 258 if (rdesc[next_rdesc].bd_adrflg & BR_ERR) 259 len = 0; 260 else { 261 if ((len = rdesc[next_rdesc].bd_mcnt - 4) > maxlen) 262 len = maxlen; 263 264 if (kopiera) 265 copyin((rdesc[next_rdesc].bd_adrflg&0xffffff), 266 pkt, len); 267 else 268 bcopy((char *)(rdesc[next_rdesc].bd_adrflg&0xffffff) + 269 addoff, pkt, len); 270 } 271 272 rdesc[next_rdesc].bd_mcnt = 0; 273 rdesc[next_rdesc].bd_adrflg |= BR_OWN; 274 if (kopiera) 275 copyout((void *)&rdesc[next_rdesc], (int)&rdesc[next_rdesc] - 276 (int)initblock, sizeof(struct buffdesc)); 277 if (++next_rdesc >= NRBUF) 278 next_rdesc = 0; 279 280 281 if (len == 0) 282 goto retry; 283 return len; 284 } 285 286 int 287 le_put(struct iodesc *desc, void *pkt, size_t len) 288 { 289 volatile int to = 100000; 290 int csr; 291 292 retry: 293 if (--to == 0) 294 return -1; 295 296 csr = LERDCSR(LE_CSR0); 297 LEWRCSR(LE_CSR0, csr & (LE_C0_MISS|LE_C0_CERR|LE_C0_TINT)); 298 299 if (kopiera) 300 copyin((int)&tdesc[next_tdesc] - (int)initblock, 301 (void *)&tdesc[next_tdesc], sizeof(struct buffdesc)); 302 if (tdesc[next_tdesc].bd_adrflg & BT_OWN) 303 goto retry; 304 305 if (kopiera) 306 copyout(pkt, (tdesc[next_tdesc].bd_adrflg & 0xffffff), len); 307 else 308 bcopy(pkt, (char *)(tdesc[next_tdesc].bd_adrflg & 0xffffff) + 309 addoff, len); 310 tdesc[next_tdesc].bd_bcnt = 311 (len < ETHER_MIN_LEN ? -ETHER_MIN_LEN : -len); 312 tdesc[next_tdesc].bd_mcnt = 0; 313 tdesc[next_tdesc].bd_adrflg |= BT_OWN | BT_STP | BT_ENP; 314 if (kopiera) 315 copyout((void *)&tdesc[next_tdesc], (int)&tdesc[next_tdesc] - 316 (int)initblock, sizeof(struct buffdesc)); 317 318 LEWRCSR(LE_CSR0, LE_C0_TDMD); 319 320 to = 100000; 321 while (((LERDCSR(LE_CSR0) & LE_C0_TINT) == 0) && --to) 322 ; 323 324 LEWRCSR(LE_CSR0, LE_C0_TINT); 325 if (++next_tdesc >= NTBUF) 326 next_tdesc = 0; 327 328 if (to) 329 return len; 330 331 return -1; 332 } 333 334 int 335 leclose(struct open_file *f) 336 { 337 LEWRCSR(LE_CSR0, LE_C0_STOP); 338 339 return 0; 340 } 341 342 void 343 copyout(void *f, int dest, int len) 344 { 345 short *from = f; 346 short *toaddr; 347 348 toaddr = (short *)0x20120000 + dest; 349 350 while (len > 0) { 351 *toaddr = *from++; 352 toaddr += 2; 353 len -= 2; 354 } 355 } 356 357 void 358 copyin(int src, void *f, int len) 359 { 360 short *to = f; 361 short *fromaddr; 362 363 fromaddr = (short *)0x20120000 + src; 364 365 while (len > 0) { 366 *to++ = *fromaddr; 367 fromaddr += 2; 368 len -= 2; 369 } 370 } 371