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