1 /* $NetBSD: le_poll.c,v 1.6 2018/03/08 03:12:02 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1993 Adam Glass 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Adam Glass. 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 Adam Glass ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "sboot.h" 35 #include "if_lereg.h" 36 37 struct { 38 struct lereg1 *sc_r1; /* LANCE registers */ 39 struct lereg2 *sc_r2; /* RAM */ 40 int next_rmd; 41 int next_tmd; 42 } le_softc; 43 44 static void le_error(const char *, struct lereg1 *); 45 static void le_reset(u_char *); 46 static int le_poll(void *, int); 47 48 static void 49 le_error(const char *str, struct lereg1 *ler1) 50 { 51 52 /* ler1->ler1_rap = LE_CSRO done in caller */ 53 if (ler1->ler1_rdp & LE_C0_BABL) { 54 printf("le0: been babbling, found by '%s'\n", str); 55 callrom(); 56 } 57 if (ler1->ler1_rdp & LE_C0_CERR) { 58 ler1->ler1_rdp = LE_C0_CERR; 59 } 60 if (ler1->ler1_rdp & LE_C0_MISS) { 61 ler1->ler1_rdp = LE_C0_MISS; 62 } 63 if (ler1->ler1_rdp & LE_C0_MERR) { 64 printf("le0: memory error in '%s'\n", str); 65 callrom(); 66 } 67 } 68 69 static void 70 le_reset(u_char *myea) 71 { 72 struct lereg1 *ler1 = le_softc.sc_r1; 73 struct lereg2 *ler2 = le_softc.sc_r2; 74 unsigned int a; 75 int timo = 100000, stat = 0, i; 76 77 ler1->ler1_rap = LE_CSR0; 78 ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */ 79 80 memset(ler2, 0, sizeof(*ler2)); 81 82 ler2->ler2_mode = LE_MODE_NORMAL; 83 ler2->ler2_padr[0] = myea[1]; 84 ler2->ler2_padr[1] = myea[0]; 85 ler2->ler2_padr[2] = myea[3]; 86 ler2->ler2_padr[3] = myea[2]; 87 ler2->ler2_padr[4] = myea[5]; 88 ler2->ler2_padr[5] = myea[4]; 89 90 91 ler2->ler2_ladrf0 = 0; 92 ler2->ler2_ladrf1 = 0; 93 94 a = (u_int)ler2->ler2_rmd; 95 ler2->ler2_rlen = LE_RLEN | (a >> 16); 96 ler2->ler2_rdra = a & LE_ADDR_LOW_MASK; 97 98 a = (u_int)ler2->ler2_tmd; 99 ler2->ler2_tlen = LE_TLEN | (a >> 16); 100 ler2->ler2_tdra = a & LE_ADDR_LOW_MASK; 101 102 ler1->ler1_rap = LE_CSR1; 103 a = (u_int)ler2; 104 ler1->ler1_rdp = a & LE_ADDR_LOW_MASK; 105 ler1->ler1_rap = LE_CSR2; 106 ler1->ler1_rdp = a >> 16; 107 108 for (i = 0; i < LERBUF; i++) { 109 a = (u_int)&ler2->ler2_rbuf[i]; 110 ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK; 111 ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; 112 ler2->ler2_rmd[i].rmd1_hadr = a >> 16; 113 ler2->ler2_rmd[i].rmd2 = -LEMTU; 114 ler2->ler2_rmd[i].rmd3 = 0; 115 } 116 for (i = 0; i < LETBUF; i++) { 117 a = (u_int)&ler2->ler2_tbuf[i]; 118 ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK; 119 ler2->ler2_tmd[i].tmd1_bits = 0; 120 ler2->ler2_tmd[i].tmd1_hadr = a >> 16; 121 ler2->ler2_tmd[i].tmd2 = 0; 122 ler2->ler2_tmd[i].tmd3 = 0; 123 } 124 125 ler1->ler1_rap = LE_CSR3; 126 ler1->ler1_rdp = LE_C3_BSWP; 127 128 ler1->ler1_rap = LE_CSR0; 129 ler1->ler1_rdp = LE_C0_INIT; 130 do { 131 if (--timo == 0) { 132 printf("le0: init timeout, stat = 0x%x\n", stat); 133 break; 134 } 135 stat = ler1->ler1_rdp; 136 } while ((stat & LE_C0_IDON) == 0); 137 138 ler1->ler1_rdp = LE_C0_IDON; 139 le_softc.next_rmd = 0; 140 le_softc.next_tmd = 0; 141 ler1->ler1_rap = LE_CSR0; 142 ler1->ler1_rdp = LE_C0_STRT; 143 } 144 145 static int 146 le_poll(void *pkt, int len) 147 { 148 struct lereg1 *ler1 = le_softc.sc_r1; 149 struct lereg2 *ler2 = le_softc.sc_r2; 150 unsigned int a; 151 int length; 152 struct lermd *rmd; 153 154 ler1->ler1_rap = LE_CSR0; 155 if ((ler1->ler1_rdp & LE_C0_RINT) != 0) 156 ler1->ler1_rdp = LE_C0_RINT; 157 rmd = &ler2->ler2_rmd[le_softc.next_rmd]; 158 if (rmd->rmd1_bits & LE_R1_OWN) { 159 return 0; 160 } 161 if (ler1->ler1_rdp & LE_C0_ERR) 162 le_error("le_poll", ler1); 163 if (rmd->rmd1_bits & LE_R1_ERR) { 164 printf("le0_poll: rmd status 0x%x\n", rmd->rmd1_bits); 165 length = 0; 166 goto cleanup; 167 } 168 if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != (LE_R1_STP|LE_R1_ENP)) { 169 printf("le_poll: chained packet\n"); 170 callrom(); 171 } 172 173 length = rmd->rmd3; 174 if (length >= LEMTU) { 175 length = 0; 176 printf("csr0 when bad things happen: %x\n", ler1->ler1_rdp); 177 callrom(); 178 goto cleanup; 179 } 180 if (length == 0) 181 goto cleanup; 182 length -= 4; 183 if (length > 0) 184 memcpy(pkt, (char *)&ler2->ler2_rbuf[le_softc.next_rmd], 185 length); 186 187 cleanup: 188 a = (u_int)&ler2->ler2_rbuf[le_softc.next_rmd]; 189 rmd->rmd0 = a & LE_ADDR_LOW_MASK; 190 rmd->rmd1_hadr = a >> 16; 191 rmd->rmd2 = -LEMTU; 192 le_softc.next_rmd = 193 (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1); 194 rmd->rmd1_bits = LE_R1_OWN; 195 return length; 196 } 197 198 int le_put(u_char *pkt, size_t len) 199 { 200 struct lereg1 *ler1 = le_softc.sc_r1; 201 struct lereg2 *ler2 = le_softc.sc_r2; 202 struct letmd *tmd; 203 int timo = 100000, stat = 0; 204 unsigned int a; 205 206 ler1->ler1_rap = LE_CSR0; 207 if (ler1->ler1_rdp & LE_C0_ERR) 208 le_error("le_put(way before xmit)", ler1); 209 tmd = &ler2->ler2_tmd[le_softc.next_tmd]; 210 while (tmd->tmd1_bits & LE_T1_OWN) { 211 printf("le0: output buffer busy\n"); 212 } 213 memcpy((char *)ler2->ler2_tbuf[le_softc.next_tmd], pkt, len); 214 if (len < 64) 215 tmd->tmd2 = -64; 216 else 217 tmd->tmd2 = -len; 218 tmd->tmd3 = 0; 219 if (ler1->ler1_rdp & LE_C0_ERR) 220 le_error("le_put(before xmit)", ler1); 221 tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN; 222 a = (u_int)&ler2->ler2_tbuf[le_softc.next_tmd]; 223 tmd->tmd0 = a & LE_ADDR_LOW_MASK; 224 tmd->tmd1_hadr = a >> 16; 225 ler1->ler1_rdp = LE_C0_TDMD; 226 if (ler1->ler1_rdp & LE_C0_ERR) 227 le_error("le_put(after xmit)", ler1); 228 do { 229 if (--timo == 0) { 230 printf("le0: transmit timeout, stat = 0x%x\n", 231 stat); 232 if (ler1->ler1_rdp & LE_C0_ERR) 233 le_error("le_put(timeout)", ler1); 234 break; 235 } 236 stat = ler1->ler1_rdp; 237 } while ((stat & LE_C0_TINT) == 0); 238 ler1->ler1_rdp = LE_C0_TINT; 239 if (ler1->ler1_rdp & LE_C0_ERR) { 240 if ((ler1->ler1_rdp & 241 (LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR)) != 242 LE_C0_CERR) { 243 printf("le_put: xmit error, buf %d\n", 244 le_softc.next_tmd); 245 le_error("le_put(xmit error)", ler1); 246 } 247 le_softc.next_tmd = 0; 248 #if 0 249 (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1; 250 #endif 251 if (tmd->tmd1_bits & LE_T1_ERR) 252 printf("le0: transmit error, error = 0x%x\n", 253 tmd->tmd3); 254 return -1; 255 } 256 return len; 257 } 258 259 int le_get(u_char *pkt, size_t len, u_long timeout) 260 { 261 int cc; 262 int now, then; 263 int stopat = time() + timeout; 264 then = 0; 265 266 cc = 0; 267 while ((now = time()) < stopat && !cc) { 268 cc = le_poll(pkt, len); 269 if (then != now) { 270 #ifdef LE_DEBUG 271 printf("%d \r", stopat - now); 272 #endif 273 then = now; 274 } 275 if (cc && (pkt[0] != myea[0] || pkt[1] != myea[1] || 276 pkt[2] != myea[2] || pkt[3] != myea[3] || 277 pkt[4] != myea[4] || pkt[5] != myea[5])) { 278 cc = 0; /* ignore broadcast / multicast */ 279 #ifdef LE_DEBUG 280 printf("reject (%d sec left)\n", stopat - now); 281 #endif 282 } 283 } 284 #ifdef LE_DEBUG 285 printf("\n"); 286 #endif 287 return cc; 288 } 289 290 void le_init(void) 291 { 292 int *ea = (int *)LANCE_ADDR; 293 u_long *eram = (u_long *)ERAM_ADDR; 294 u_long e = *ea; 295 296 if ((e & 0x2fffff00) == 0x2fffff00) { 297 printf("ERROR: ethernet address not set! Use LSAD.\n"); 298 callrom(); 299 } 300 myea[0] = 0x08; 301 myea[1] = 0x00; 302 myea[2] = 0x3e; 303 e = e >> 8; 304 myea[5] = e & 0xff; 305 e = e >> 8; 306 myea[4] = e & 0xff; 307 e = e >> 8; 308 myea[3] = e; 309 printf("le0: ethernet address: %x:%x:%x:%x:%x:%x\n", 310 myea[0], myea[1], myea[2], myea[3], myea[4], myea[5]); 311 memset(&le_softc, 0, sizeof(le_softc)); 312 le_softc.sc_r1 = (struct lereg1 *)LANCE_REG_ADDR; 313 le_softc.sc_r2 = (struct lereg2 *)(*eram - (1024*1024)); 314 le_reset(myea); 315 } 316 317 void le_end(void) 318 { 319 struct lereg1 *ler1 = le_softc.sc_r1; 320 321 ler1->ler1_rap = LE_CSR0; 322 ler1->ler1_rdp = LE_C0_STOP; 323 } 324