1 /* $NetBSD: le_poll.c,v 1.4 2001/11/08 21:40:25 scw 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(str, ler1) 50 const char *str; 51 struct lereg1 *ler1; 52 { 53 /* ler1->ler1_rap = LE_CSRO done in caller */ 54 if (ler1->ler1_rdp & LE_C0_BABL) { 55 printf("le0: been babbling, found by '%s'\n", str); 56 callrom(); 57 } 58 if (ler1->ler1_rdp & LE_C0_CERR) { 59 ler1->ler1_rdp = LE_C0_CERR; 60 } 61 if (ler1->ler1_rdp & LE_C0_MISS) { 62 ler1->ler1_rdp = LE_C0_MISS; 63 } 64 if (ler1->ler1_rdp & LE_C0_MERR) { 65 printf("le0: memory error in '%s'\n", str); 66 callrom(); 67 } 68 69 } 70 71 static void 72 le_reset(myea) 73 u_char *myea; 74 { 75 struct lereg1 *ler1 = le_softc.sc_r1; 76 struct lereg2 *ler2 = le_softc.sc_r2; 77 unsigned int a; 78 int timo = 100000, stat = 0, i; 79 80 ler1->ler1_rap = LE_CSR0; 81 ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */ 82 83 memset(ler2, 0, sizeof(*ler2)); 84 85 ler2->ler2_mode = LE_MODE_NORMAL; 86 ler2->ler2_padr[0] = myea[1]; 87 ler2->ler2_padr[1] = myea[0]; 88 ler2->ler2_padr[2] = myea[3]; 89 ler2->ler2_padr[3] = myea[2]; 90 ler2->ler2_padr[4] = myea[5]; 91 ler2->ler2_padr[5] = myea[4]; 92 93 94 ler2->ler2_ladrf0 = 0; 95 ler2->ler2_ladrf1 = 0; 96 97 a = (u_int)ler2->ler2_rmd; 98 ler2->ler2_rlen = LE_RLEN | (a >> 16); 99 ler2->ler2_rdra = a & LE_ADDR_LOW_MASK; 100 101 a = (u_int)ler2->ler2_tmd; 102 ler2->ler2_tlen = LE_TLEN | (a >> 16); 103 ler2->ler2_tdra = a & LE_ADDR_LOW_MASK; 104 105 ler1->ler1_rap = LE_CSR1; 106 a = (u_int)ler2; 107 ler1->ler1_rdp = a & LE_ADDR_LOW_MASK; 108 ler1->ler1_rap = LE_CSR2; 109 ler1->ler1_rdp = a >> 16; 110 111 for (i = 0; i < LERBUF; i++) { 112 a = (u_int)&ler2->ler2_rbuf[i]; 113 ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK; 114 ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; 115 ler2->ler2_rmd[i].rmd1_hadr = a >> 16; 116 ler2->ler2_rmd[i].rmd2 = -LEMTU; 117 ler2->ler2_rmd[i].rmd3 = 0; 118 } 119 for (i = 0; i < LETBUF; i++) { 120 a = (u_int)&ler2->ler2_tbuf[i]; 121 ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK; 122 ler2->ler2_tmd[i].tmd1_bits = 0; 123 ler2->ler2_tmd[i].tmd1_hadr = a >> 16; 124 ler2->ler2_tmd[i].tmd2 = 0; 125 ler2->ler2_tmd[i].tmd3 = 0; 126 } 127 128 ler1->ler1_rap = LE_CSR3; 129 ler1->ler1_rdp = LE_C3_BSWP; 130 131 ler1->ler1_rap = LE_CSR0; 132 ler1->ler1_rdp = LE_C0_INIT; 133 do { 134 if (--timo == 0) { 135 printf("le0: init timeout, stat = 0x%x\n", stat); 136 break; 137 } 138 stat = ler1->ler1_rdp; 139 } while ((stat & LE_C0_IDON) == 0); 140 141 ler1->ler1_rdp = LE_C0_IDON; 142 le_softc.next_rmd = 0; 143 le_softc.next_tmd = 0; 144 ler1->ler1_rap = LE_CSR0; 145 ler1->ler1_rdp = LE_C0_STRT; 146 } 147 148 static int 149 le_poll(pkt, len) 150 void *pkt; 151 int len; 152 { 153 struct lereg1 *ler1 = le_softc.sc_r1; 154 struct lereg2 *ler2 = le_softc.sc_r2; 155 unsigned int a; 156 int length; 157 struct lermd *rmd; 158 159 ler1->ler1_rap = LE_CSR0; 160 if ((ler1->ler1_rdp & LE_C0_RINT) != 0) 161 ler1->ler1_rdp = LE_C0_RINT; 162 rmd = &ler2->ler2_rmd[le_softc.next_rmd]; 163 if (rmd->rmd1_bits & LE_R1_OWN) { 164 return(0); 165 } 166 if (ler1->ler1_rdp & LE_C0_ERR) 167 le_error("le_poll", ler1); 168 if (rmd->rmd1_bits & LE_R1_ERR) { 169 printf("le0_poll: rmd status 0x%x\n", rmd->rmd1_bits); 170 length = 0; 171 goto cleanup; 172 } 173 if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != (LE_R1_STP|LE_R1_ENP)) { 174 printf("le_poll: chained packet\n"); 175 callrom(); 176 } 177 178 length = rmd->rmd3; 179 if (length >= LEMTU) { 180 length = 0; 181 printf("csr0 when bad things happen: %x\n", ler1->ler1_rdp); 182 callrom(); 183 goto cleanup; 184 } 185 if (!length) goto cleanup; 186 length -= 4; 187 if (length > 0) 188 memcpy(pkt, (char *)&ler2->ler2_rbuf[le_softc.next_rmd], length); 189 190 cleanup: 191 a = (u_int)&ler2->ler2_rbuf[le_softc.next_rmd]; 192 rmd->rmd0 = a & LE_ADDR_LOW_MASK; 193 rmd->rmd1_hadr = a >> 16; 194 rmd->rmd2 = -LEMTU; 195 le_softc.next_rmd = 196 (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1); 197 rmd->rmd1_bits = LE_R1_OWN; 198 return length; 199 } 200 201 int le_put(pkt, len) 202 u_char *pkt; 203 size_t len; 204 { 205 struct lereg1 *ler1 = le_softc.sc_r1; 206 struct lereg2 *ler2 = le_softc.sc_r2; 207 struct letmd *tmd; 208 int timo = 100000, stat = 0; 209 unsigned int a; 210 211 ler1->ler1_rap = LE_CSR0; 212 if (ler1->ler1_rdp & LE_C0_ERR) 213 le_error("le_put(way before xmit)", ler1); 214 tmd = &ler2->ler2_tmd[le_softc.next_tmd]; 215 while(tmd->tmd1_bits & LE_T1_OWN) { 216 printf("le0: output buffer busy\n"); 217 } 218 memcpy((char *)ler2->ler2_tbuf[le_softc.next_tmd], pkt, len); 219 if (len < 64) 220 tmd->tmd2 = -64; 221 else 222 tmd->tmd2 = -len; 223 tmd->tmd3 = 0; 224 if (ler1->ler1_rdp & LE_C0_ERR) 225 le_error("le_put(before xmit)", ler1); 226 tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN; 227 a = (u_int)&ler2->ler2_tbuf[le_softc.next_tmd]; 228 tmd->tmd0 = a & LE_ADDR_LOW_MASK; 229 tmd->tmd1_hadr = a >> 16; 230 ler1->ler1_rdp = LE_C0_TDMD; 231 if (ler1->ler1_rdp & LE_C0_ERR) 232 le_error("le_put(after xmit)", ler1); 233 do { 234 if (--timo == 0) { 235 printf("le0: transmit timeout, stat = 0x%x\n", 236 stat); 237 if (ler1->ler1_rdp & LE_C0_ERR) 238 le_error("le_put(timeout)", ler1); 239 break; 240 } 241 stat = ler1->ler1_rdp; 242 } while ((stat & LE_C0_TINT) == 0); 243 ler1->ler1_rdp = LE_C0_TINT; 244 if (ler1->ler1_rdp & LE_C0_ERR) { 245 if ((ler1->ler1_rdp & (LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR)) != 246 LE_C0_CERR) 247 printf("le_put: xmit error, buf %d\n", le_softc.next_tmd); 248 le_error("le_put(xmit error)", ler1); 249 } 250 le_softc.next_tmd = 0; 251 /* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/ 252 if (tmd->tmd1_bits & LE_T1_ERR) { 253 printf("le0: transmit error, error = 0x%x\n", 254 tmd->tmd3); 255 return -1; 256 } 257 return len; 258 } 259 260 int le_get(pkt, len, timeout) 261 u_char *pkt; 262 size_t len; 263 u_long timeout; 264 { 265 int cc; 266 int now, then; 267 int stopat = time() + timeout; 268 then = 0; 269 270 cc = 0; 271 while ((now = time()) < stopat && !cc) { 272 cc = le_poll(pkt, len); 273 if (then != now) { 274 #ifdef LE_DEBUG 275 printf("%d \r", stopat - now); 276 #endif 277 then = now; 278 } 279 if (cc && (pkt[0] != myea[0] || pkt[1] != myea[1] || 280 pkt[2] != myea[2] || pkt[3] != myea[3] || 281 pkt[4] != myea[4] || pkt[5] != myea[5])) { 282 cc = 0; /* ignore broadcast / multicast */ 283 #ifdef LE_DEBUG 284 printf("reject (%d sec left)\n", stopat - now); 285 #endif 286 } 287 } 288 #ifdef LE_DEBUG 289 printf("\n"); 290 #endif 291 return cc; 292 } 293 294 void le_init() 295 { 296 int *ea = (int *) LANCE_ADDR; 297 u_long *eram = (u_long *) ERAM_ADDR; 298 u_long e = *ea; 299 if (( e & 0x2fffff00 ) == 0x2fffff00) { 300 printf("ERROR: ethernet address not set! Use LSAD.\n"); 301 callrom(); 302 } 303 myea[0] = 0x08; 304 myea[1] = 0x00; 305 myea[2] = 0x3e; 306 e = e >> 8; 307 myea[5] = e & 0xff; 308 e = e >> 8; 309 myea[4] = e & 0xff; 310 e = e >> 8; 311 myea[3] = e; 312 printf("le0: ethernet address: %x:%x:%x:%x:%x:%x\n", 313 myea[0], myea[1], myea[2], myea[3], myea[4], myea[5]); 314 memset(&le_softc, 0, sizeof(le_softc)); 315 le_softc.sc_r1 = (struct lereg1 *) LANCE_REG_ADDR; 316 le_softc.sc_r2 = (struct lereg2 *)(*eram - (1024*1024)); 317 le_reset(myea); 318 } 319 320 void le_end() 321 { 322 struct lereg1 *ler1 = le_softc.sc_r1; 323 324 ler1->ler1_rap = LE_CSR0; 325 ler1->ler1_rdp = LE_C0_STOP; 326 } 327