1 1.16 tsutsui /* $NetBSD: if_le.c,v 1.16 2024/04/29 14:42:07 tsutsui Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 1993 Adam Glass 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Redistribution and use in source and binary forms, with or without 8 1.1 thorpej * modification, are permitted provided that the following conditions 9 1.1 thorpej * are met: 10 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 11 1.1 thorpej * notice, this list of conditions and the following disclaimer. 12 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 14 1.1 thorpej * documentation and/or other materials provided with the distribution. 15 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 16 1.1 thorpej * must display the following acknowledgement: 17 1.1 thorpej * This product includes software developed by Adam Glass. 18 1.1 thorpej * 4. The name of the Author may not be used to endorse or promote products 19 1.1 thorpej * derived from this software without specific prior written permission. 20 1.1 thorpej * 21 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND 22 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 thorpej * SUCH DAMAGE. 32 1.1 thorpej */ 33 1.1 thorpej 34 1.1 thorpej #include <sys/param.h> 35 1.1 thorpej #include <sys/types.h> 36 1.1 thorpej 37 1.4 drochner #include <net/if_ether.h> 38 1.1 thorpej #include <netinet/in.h> 39 1.1 thorpej #include <netinet/in_systm.h> 40 1.1 thorpej 41 1.7 tsutsui #include <lib/libsa/stand.h> 42 1.7 tsutsui #include <lib/libsa/net.h> 43 1.1 thorpej #include <lib/libsa/netif.h> 44 1.1 thorpej 45 1.7 tsutsui #include <lib/libkern/libkern.h> 46 1.7 tsutsui 47 1.1 thorpej #include <hp300/stand/common/device.h> 48 1.1 thorpej #include <hp300/stand/common/if_lereg.h> 49 1.1 thorpej #include <hp300/stand/common/samachdep.h> 50 1.1 thorpej 51 1.1 thorpej #ifndef NLE 52 1.1 thorpej #define NLE 1 53 1.1 thorpej #endif 54 1.1 thorpej 55 1.7 tsutsui struct le_softc { 56 1.7 tsutsui struct lereg0 *sc_r0; /* DIO registers */ 57 1.7 tsutsui struct lereg1 *sc_r1; /* LANCE registers */ 58 1.7 tsutsui void *sc_mem; 59 1.7 tsutsui struct init_block *sc_init; 60 1.7 tsutsui struct mds *sc_rd, *sc_td; 61 1.7 tsutsui u_char *sc_rbuf, *sc_tbuf; 62 1.7 tsutsui int sc_next_rd, sc_next_td; 63 1.7 tsutsui u_char sc_addr[ETHER_ADDR_LEN]; 64 1.7 tsutsui }; 65 1.7 tsutsui 66 1.7 tsutsui struct le_sel { 67 1.7 tsutsui int le_id; 68 1.7 tsutsui int le_regs; 69 1.7 tsutsui int le_mem; 70 1.7 tsutsui int le_nvram; 71 1.7 tsutsui int le_heat; 72 1.7 tsutsui int le_bonus; 73 1.7 tsutsui }; 74 1.7 tsutsui 75 1.14 tsutsui static int le_probe(struct netif *, void *); 76 1.14 tsutsui static int le_match(struct netif *, void *); 77 1.14 tsutsui static void le_init(struct iodesc *, void *); 78 1.14 tsutsui static int le_get(struct iodesc *, void *, size_t, saseconds_t); 79 1.14 tsutsui static int le_put(struct iodesc *, void *, size_t); 80 1.14 tsutsui static void le_end(struct netif *); 81 1.7 tsutsui 82 1.7 tsutsui static inline void lewrcsr(struct le_softc *, uint16_t, uint16_t); 83 1.7 tsutsui static inline uint16_t lerdcsr(struct le_softc *, uint16_t); 84 1.7 tsutsui 85 1.7 tsutsui static void leinit(void); 86 1.7 tsutsui static void le_error(int, char *, uint16_t); 87 1.7 tsutsui static void lememinit(struct le_softc *); 88 1.7 tsutsui static void le_reset(int, u_char *); 89 1.7 tsutsui static int le_poll(struct iodesc *, void *, int); 90 1.7 tsutsui 91 1.1 thorpej #ifdef LE_DEBUG 92 1.1 thorpej int le_debug = 0; 93 1.1 thorpej #endif 94 1.1 thorpej 95 1.14 tsutsui static struct le_sel le0conf[] = { 96 1.1 thorpej /* offsets for: ID REGS MEM NVRAM le_heat le_bonus*/ 97 1.1 thorpej { 0, 0x4000, 0x8000, 0xC008, 1, 10 } 98 1.1 thorpej }; 99 1.6 drochner #define NLE0CONF (sizeof(le0conf) / sizeof(le0conf[0])) 100 1.1 thorpej 101 1.15 tsutsui static struct netif_stats le_stats[]; 102 1.1 thorpej 103 1.14 tsutsui static struct netif_dif le_ifs[] = { 104 1.1 thorpej /* dif_unit dif_nsel dif_stats dif_private */ 105 1.6 drochner { 0, NLE0CONF, &le_stats[0], le0conf, }, 106 1.1 thorpej }; 107 1.6 drochner #define NLE_IFS (sizeof(le_ifs) / sizeof(le_ifs[0])) 108 1.1 thorpej 109 1.15 tsutsui static struct netif_stats le_stats[NLE_IFS]; 110 1.1 thorpej 111 1.1 thorpej struct netif_driver le_driver = { 112 1.1 thorpej "le", /* netif_bname */ 113 1.1 thorpej le_match, /* netif_match */ 114 1.1 thorpej le_probe, /* netif_probe */ 115 1.1 thorpej le_init, /* netif_init */ 116 1.1 thorpej le_get, /* netif_get */ 117 1.1 thorpej le_put, /* netif_put */ 118 1.1 thorpej le_end, /* netif_end */ 119 1.1 thorpej le_ifs, /* netif_ifs */ 120 1.6 drochner NLE_IFS /* netif_nifs */ 121 1.1 thorpej }; 122 1.1 thorpej 123 1.14 tsutsui static struct le_softc le_softc[NLE]; 124 1.1 thorpej 125 1.1 thorpej static inline void 126 1.8 tsutsui lewrcsr(struct le_softc *sc, uint16_t port, uint16_t val) 127 1.1 thorpej { 128 1.7 tsutsui struct lereg0 *ler0 = sc->sc_r0; 129 1.7 tsutsui struct lereg1 *ler1 = sc->sc_r1; 130 1.1 thorpej 131 1.1 thorpej do { 132 1.1 thorpej ler1->ler1_rap = port; 133 1.1 thorpej } while ((ler0->ler0_status & LE_ACK) == 0); 134 1.1 thorpej do { 135 1.1 thorpej ler1->ler1_rdp = val; 136 1.1 thorpej } while ((ler0->ler0_status & LE_ACK) == 0); 137 1.1 thorpej } 138 1.1 thorpej 139 1.7 tsutsui static inline uint16_t 140 1.8 tsutsui lerdcsr(struct le_softc *sc, uint16_t port) 141 1.1 thorpej { 142 1.7 tsutsui struct lereg0 *ler0 = sc->sc_r0; 143 1.7 tsutsui struct lereg1 *ler1 = sc->sc_r1; 144 1.7 tsutsui uint16_t val; 145 1.1 thorpej 146 1.1 thorpej do { 147 1.1 thorpej ler1->ler1_rap = port; 148 1.1 thorpej } while ((ler0->ler0_status & LE_ACK) == 0); 149 1.1 thorpej do { 150 1.1 thorpej val = ler1->ler1_rdp; 151 1.1 thorpej } while ((ler0->ler0_status & LE_ACK) == 0); 152 1.7 tsutsui return val; 153 1.1 thorpej } 154 1.1 thorpej 155 1.7 tsutsui static void 156 1.8 tsutsui leinit(void) 157 1.1 thorpej { 158 1.7 tsutsui struct hp_hw *hw; 159 1.1 thorpej struct le_softc *sc; 160 1.1 thorpej struct le_sel *sels; 161 1.7 tsutsui int i, n; 162 1.1 thorpej char *cp; 163 1.7 tsutsui 164 1.1 thorpej i = 0; 165 1.1 thorpej 166 1.1 thorpej for (hw = sc_table; i < NLE && hw < &sc_table[MAXCTLRS]; hw++) { 167 1.1 thorpej #ifdef LE_DEBUG 168 1.1 thorpej if (le_debug) 169 1.1 thorpej printf("found type %x\n", hw->hw_type); 170 1.1 thorpej #endif 171 1.1 thorpej 172 1.1 thorpej #if 0 173 1.1 thorpej if (!HW_ISDEV(hw, D_LAN)) 174 1.1 thorpej continue; 175 1.1 thorpej #endif 176 1.1 thorpej 177 1.7 tsutsui sels = (struct le_sel *)le_ifs[i].dif_private; 178 1.1 thorpej 179 1.1 thorpej sc = &le_softc[i]; 180 1.7 tsutsui sc->sc_r0 = (struct lereg0 *)(sels->le_id + (int)hw->hw_kva); 181 1.1 thorpej 182 1.7 tsutsui if (sc->sc_r0->ler0_id != LEID) 183 1.7 tsutsui continue; 184 1.1 thorpej 185 1.7 tsutsui sc->sc_r1 = (struct lereg1 *)(sels->le_regs + (int)hw->hw_kva); 186 1.7 tsutsui sc->sc_mem = (struct lereg2 *)(sels->le_mem + (int)hw->hw_kva); 187 1.1 thorpej 188 1.1 thorpej #ifdef LE_DEBUG 189 1.1 thorpej if (le_debug) 190 1.1 thorpej printf("le%d: DIO=%x regs=%x mem=%x\n", 191 1.1 thorpej i, sc->sc_r0, sc->sc_r1, sc->sc_mem); 192 1.1 thorpej #endif 193 1.7 tsutsui 194 1.1 thorpej /* 195 1.1 thorpej * Read the ethernet address off the board, one nibble at a time. 196 1.1 thorpej */ 197 1.1 thorpej cp = (char *)(sels->le_nvram + (int)hw->hw_kva); 198 1.1 thorpej for (n = 0; n < sizeof(sc->sc_addr); n++) { 199 1.1 thorpej sc->sc_addr[n] = (*++cp & 0xF) << 4; 200 1.1 thorpej cp++; 201 1.1 thorpej sc->sc_addr[n] |= *++cp & 0xF; 202 1.1 thorpej cp++; 203 1.1 thorpej } 204 1.1 thorpej #ifdef LE_DEBUG 205 1.1 thorpej if (le_debug) 206 1.1 thorpej printf("le%d at sc%d physical address %s\n", 207 1.1 thorpej i, hw->hw_sc, ether_sprintf(sc->sc_addr)); 208 1.1 thorpej #endif 209 1.10 christos hw->hw_pa = (void *) i; /* XXX for autoconfig */ 210 1.1 thorpej i++; 211 1.1 thorpej } 212 1.1 thorpej } 213 1.1 thorpej 214 1.14 tsutsui static int 215 1.8 tsutsui le_match(struct netif *nif, void *machdep_hint) 216 1.1 thorpej { 217 1.1 thorpej struct le_sel *sels; 218 1.1 thorpej char *name = machdep_hint; 219 1.1 thorpej int rv = 0; 220 1.1 thorpej 221 1.1 thorpej if (nif->nif_sel < le_ifs[nif->nif_unit].dif_nsel) { 222 1.1 thorpej sels = (struct le_sel *)le_ifs[nif->nif_unit].dif_private; 223 1.1 thorpej rv = sels[nif->nif_sel].le_heat; 224 1.1 thorpej if (name && !strncmp(le_driver.netif_bname, name, 2)) 225 1.1 thorpej rv += sels[nif->nif_sel].le_bonus; 226 1.1 thorpej } 227 1.1 thorpej #ifdef LE_DEBUG 228 1.1 thorpej if (le_debug) 229 1.1 thorpej printf("le%d: sel %d --> %d\n", nif->nif_unit, nif->nif_sel, 230 1.1 thorpej rv); 231 1.1 thorpej #endif 232 1.1 thorpej return rv; 233 1.1 thorpej } 234 1.1 thorpej 235 1.14 tsutsui static int 236 1.8 tsutsui le_probe(struct netif *nif, void *machdep_hint) 237 1.1 thorpej { 238 1.7 tsutsui #if 0 239 1.1 thorpej char *cp; 240 1.1 thorpej int i; 241 1.7 tsutsui #endif 242 1.1 thorpej 243 1.1 thorpej /* the set unit is the current unit */ 244 1.1 thorpej #ifdef LE_DEBUG 245 1.1 thorpej if (le_debug) 246 1.1 thorpej printf("le%d.%d: le_probe called\n", nif->nif_unit, nif->nif_sel); 247 1.1 thorpej #endif 248 1.1 thorpej /* XXX reset controller */ 249 1.1 thorpej return 0; 250 1.1 thorpej } 251 1.1 thorpej 252 1.1 thorpej #ifdef MEM_SUMMARY 253 1.7 tsutsui void 254 1.8 tsutsui le_mem_summary(int unit) 255 1.1 thorpej { 256 1.1 thorpej struct lereg1 *ler1 = le_softc.sc_r1; 257 1.1 thorpej struct lereg2 *ler2 = le_softc.sc_r2; 258 1.7 tsutsui int i; 259 1.7 tsutsui 260 1.1 thorpej printf("le%d: ler1 = %x\n", unit, ler1); 261 1.1 thorpej printf("le%d: ler2 = %x\n", unit, ler2); 262 1.7 tsutsui 263 1.1 thorpej #if 0 264 1.1 thorpej ler1->ler1_rap = LE_CSR0; 265 1.1 thorpej ler1->ler1_rdp = LE_STOP; 266 1.1 thorpej printf("le%d: csr0 = %x\n", unit, ler1->ler1_rdp); 267 1.1 thorpej ler1->ler1_rap = LE_CSR1; 268 1.1 thorpej printf("le%d: csr1 = %x\n", unit, ler1->ler1_rdp); 269 1.1 thorpej ler1->ler1_rap = LE_CSR2; 270 1.1 thorpej printf("le%d: csr2 = %x\n", unit, ler1->ler1_rdp); 271 1.1 thorpej ler1->ler1_rap = LE_CSR3; 272 1.1 thorpej printf("le%d: csr3 = %x\n", unit, ler1->ler1_rdp); 273 1.1 thorpej #endif 274 1.1 thorpej printf("le%d: ladrf[0] = %x\n", unit, ler2->ler2_ladrf[0]); 275 1.1 thorpej printf("le%d: ladrf[1] = %x\n", unit, ler2->ler2_ladrf[1]); 276 1.1 thorpej printf("le%d: ler2_rdra = %x\n", unit, ler2->ler2_rdra); 277 1.1 thorpej printf("le%d: ler2_rlen = %x\n", unit, ler2->ler2_rlen); 278 1.7 tsutsui printf("le%d: ler2_tdra = %x\n", unit, ler2->ler2_tdra); 279 1.1 thorpej printf("le%d: ler2_tlen = %x\n", unit, ler2->ler2_tlen); 280 1.1 thorpej 281 1.1 thorpej for (i = 0; i < LERBUF; i++) { 282 1.1 thorpej printf("le%d: ler2_rmd[%d].rmd0 (ladr) = %x\n", unit, i, 283 1.1 thorpej ler2->ler2_rmd[i].rmd0); 284 1.1 thorpej printf("le%d: ler2_rmd[%d].rmd1 = %x\n", unit, i, 285 1.1 thorpej ler2->ler2_rmd[i].rmd1); 286 1.1 thorpej printf("le%d: ler2_rmd[%d].rmd2 (-bcnt) = %x\n", unit, i, 287 1.1 thorpej ler2->ler2_rmd[i].rmd2); 288 1.1 thorpej printf("le%d: ler2_rmd[%d].rmd3 (mcnt) = %x\n", unit, i, 289 1.1 thorpej ler2->ler2_rmd[i].rmd3); 290 1.1 thorpej printf("le%d: ler2_rbuf[%d] addr = %x\n", unit, i, 291 1.1 thorpej &ler2->ler2_rbuf[i]); 292 1.1 thorpej } 293 1.1 thorpej for (i = 0; i < LETBUF; i++) { 294 1.1 thorpej printf("le%d: ler2_tmd[%d].tmd0 = %x\n", unit, i, 295 1.1 thorpej ler2->ler2_tmd[i].tmd0); 296 1.1 thorpej printf("le%d: ler2_tmd[%d].tmd1 = %x\n", unit, i, 297 1.1 thorpej ler2->ler2_tmd[i].tmd1); 298 1.1 thorpej printf("le%d: ler2_tmd[%d].tmd2 (bcnt) = %x\n", unit, i, 299 1.1 thorpej ler2->ler2_tmd[i].tmd2); 300 1.1 thorpej printf("le%d: ler2_tmd[%d].tmd3 = %x\n", unit, i, 301 1.1 thorpej ler2->ler2_tmd[i].tmd3); 302 1.1 thorpej printf("le%d: ler2_tbuf[%d] addr = %x\n", unit, i, 303 1.1 thorpej &ler2->ler2_tbuf[i]); 304 1.1 thorpej } 305 1.1 thorpej } 306 1.1 thorpej #else 307 1.1 thorpej #define le_mem_summary(u) 308 1.1 thorpej #endif 309 1.1 thorpej 310 1.14 tsutsui static void 311 1.8 tsutsui le_error(int unit, char *str, uint16_t stat) 312 1.1 thorpej { 313 1.1 thorpej 314 1.1 thorpej if (stat & LE_BABL) 315 1.5 provos panic("le%d: been babbling, found by '%s'", unit, str); 316 1.1 thorpej if (stat & LE_CERR) 317 1.1 thorpej le_stats[unit].collision_error++; 318 1.1 thorpej if (stat & LE_MISS) 319 1.1 thorpej le_stats[unit].missed++; 320 1.7 tsutsui if (stat & LE_MERR) { 321 1.1 thorpej printf("le%d: memory error in '%s'\n", unit, str); 322 1.1 thorpej le_mem_summary(unit); 323 1.1 thorpej panic("bye"); 324 1.1 thorpej } 325 1.1 thorpej } 326 1.1 thorpej 327 1.1 thorpej #define LANCE_ADDR(sc, a) \ 328 1.1 thorpej ((u_long)(a) - (u_long)sc->sc_mem) 329 1.1 thorpej 330 1.1 thorpej /* LANCE initialization block set up. */ 331 1.14 tsutsui static void 332 1.8 tsutsui lememinit(struct le_softc *sc) 333 1.1 thorpej { 334 1.1 thorpej int i; 335 1.7 tsutsui u_char *mem; 336 1.1 thorpej u_long a; 337 1.1 thorpej 338 1.1 thorpej /* 339 1.1 thorpej * At this point we assume that the memory allocated to the Lance is 340 1.1 thorpej * quadword aligned. If it isn't then the initialisation is going 341 1.1 thorpej * fail later on. 342 1.1 thorpej */ 343 1.1 thorpej mem = sc->sc_mem; 344 1.1 thorpej 345 1.7 tsutsui sc->sc_init = (void *)mem; 346 1.1 thorpej sc->sc_init->mode = LE_NORMAL; 347 1.1 thorpej for (i = 0; i < ETHER_ADDR_LEN; i++) 348 1.1 thorpej sc->sc_init->padr[i] = sc->sc_addr[i^1]; 349 1.1 thorpej sc->sc_init->ladrf[0] = sc->sc_init->ladrf[1] = 0; 350 1.1 thorpej mem += sizeof(struct init_block); 351 1.1 thorpej 352 1.7 tsutsui sc->sc_rd = (void *)mem; 353 1.1 thorpej a = LANCE_ADDR(sc, mem); 354 1.1 thorpej sc->sc_init->rdra = a; 355 1.1 thorpej sc->sc_init->rlen = ((a >> 16) & 0xff) | (RLEN << 13); 356 1.1 thorpej mem += NRBUF * sizeof(struct mds); 357 1.1 thorpej 358 1.7 tsutsui sc->sc_td = (void *)mem; 359 1.1 thorpej a = LANCE_ADDR(sc, mem); 360 1.1 thorpej sc->sc_init->tdra = a; 361 1.1 thorpej sc->sc_init->tlen = ((a >> 16) & 0xff) | (TLEN << 13); 362 1.1 thorpej mem += NTBUF * sizeof(struct mds); 363 1.1 thorpej 364 1.7 tsutsui /* 365 1.1 thorpej * Set up receive ring descriptors. 366 1.1 thorpej */ 367 1.1 thorpej sc->sc_rbuf = mem; 368 1.1 thorpej for (i = 0; i < NRBUF; i++) { 369 1.1 thorpej a = LANCE_ADDR(sc, mem); 370 1.1 thorpej sc->sc_rd[i].addr = a; 371 1.1 thorpej sc->sc_rd[i].flags = ((a >> 16) & 0xff) | LE_OWN; 372 1.1 thorpej sc->sc_rd[i].bcnt = -BUFSIZE; 373 1.1 thorpej sc->sc_rd[i].mcnt = 0; 374 1.1 thorpej mem += BUFSIZE; 375 1.1 thorpej } 376 1.1 thorpej 377 1.7 tsutsui /* 378 1.1 thorpej * Set up transmit ring descriptors. 379 1.1 thorpej */ 380 1.1 thorpej sc->sc_tbuf = mem; 381 1.1 thorpej for (i = 0; i < NTBUF; i++) { 382 1.1 thorpej a = LANCE_ADDR(sc, mem); 383 1.1 thorpej sc->sc_td[i].addr = a; 384 1.1 thorpej sc->sc_td[i].flags = ((a >> 16) & 0xff); 385 1.1 thorpej sc->sc_td[i].bcnt = 0xf000; 386 1.1 thorpej sc->sc_td[i].mcnt = 0; 387 1.1 thorpej mem += BUFSIZE; 388 1.1 thorpej } 389 1.1 thorpej } 390 1.1 thorpej 391 1.14 tsutsui static void 392 1.8 tsutsui le_reset(int unit, u_char *myea) 393 1.1 thorpej { 394 1.1 thorpej struct le_softc *sc = &le_softc[unit]; 395 1.1 thorpej u_long a; 396 1.7 tsutsui int timo = 100000; 397 1.1 thorpej 398 1.1 thorpej #ifdef LE_DEBUG 399 1.1 thorpej if (le_debug) { 400 1.1 thorpej printf("le%d: le_reset called\n", unit); 401 1.1 thorpej printf(" r0=%x, r1=%x, mem=%x, addr=%x:%x:%x:%x:%x:%x\n", 402 1.1 thorpej sc->sc_r0, sc->sc_r1, sc->sc_mem, 403 1.1 thorpej sc->sc_addr[0], sc->sc_addr[1], sc->sc_addr[2], 404 1.1 thorpej sc->sc_addr[3], sc->sc_addr[4], sc->sc_addr[5]); 405 1.1 thorpej } 406 1.1 thorpej #endif 407 1.1 thorpej lewrcsr(sc, 0, LE_STOP); 408 1.1 thorpej for (timo = 1000; timo; timo--); 409 1.1 thorpej 410 1.1 thorpej sc->sc_next_rd = sc->sc_next_td = 0; 411 1.7 tsutsui 412 1.1 thorpej /* Set up LANCE init block. */ 413 1.1 thorpej lememinit(sc); 414 1.1 thorpej 415 1.1 thorpej if (myea) 416 1.7 tsutsui memcpy(myea, sc->sc_addr, ETHER_ADDR_LEN); 417 1.1 thorpej 418 1.1 thorpej /* Turn on byte swapping. */ 419 1.1 thorpej lewrcsr(sc, 3, LE_BSWP); 420 1.1 thorpej 421 1.1 thorpej /* Give LANCE the physical address of its init block. */ 422 1.1 thorpej a = LANCE_ADDR(sc, sc->sc_init); 423 1.1 thorpej lewrcsr(sc, 1, a); 424 1.1 thorpej lewrcsr(sc, 2, (a >> 16) & 0xff); 425 1.1 thorpej 426 1.1 thorpej #ifdef LE_DEBUG 427 1.1 thorpej if (le_debug) 428 1.1 thorpej printf("le%d: before init\n", unit); 429 1.1 thorpej #endif 430 1.1 thorpej 431 1.1 thorpej /* Try to initialize the LANCE. */ 432 1.1 thorpej lewrcsr(sc, 0, LE_INIT); 433 1.1 thorpej 434 1.1 thorpej /* Wait for initialization to finish. */ 435 1.1 thorpej for (timo = 100000; timo; timo--) 436 1.1 thorpej if (lerdcsr(sc, 0) & LE_IDON) 437 1.1 thorpej break; 438 1.1 thorpej 439 1.1 thorpej if (lerdcsr(sc, 0) & LE_IDON) { 440 1.1 thorpej /* Start the LANCE. */ 441 1.1 thorpej lewrcsr(sc, 0, LE_INEA | LE_STRT | LE_IDON); 442 1.1 thorpej } else 443 1.1 thorpej printf("le%d: card failed to initialize\n", unit); 444 1.1 thorpej 445 1.1 thorpej #ifdef LE_DEBUG 446 1.1 thorpej if (le_debug) 447 1.1 thorpej printf("le%d: after init\n", unit); 448 1.1 thorpej #endif 449 1.1 thorpej 450 1.1 thorpej le_mem_summary(unit); 451 1.1 thorpej } 452 1.1 thorpej 453 1.14 tsutsui static int 454 1.8 tsutsui le_poll(struct iodesc *desc, void *pkt, int len) 455 1.1 thorpej { 456 1.1 thorpej int unit = /*nif->nif_unit*/0; 457 1.1 thorpej struct le_softc *sc = &le_softc[unit]; 458 1.1 thorpej int length; 459 1.1 thorpej volatile struct mds *cdm; 460 1.7 tsutsui int stat; 461 1.1 thorpej 462 1.1 thorpej #ifdef LE_DEBUG 463 1.1 thorpej if (/*le_debug*/0) 464 1.1 thorpej printf("le%d: le_poll called. next_rd=%d\n", unit, sc->sc_next_rd); 465 1.1 thorpej #endif 466 1.1 thorpej stat = lerdcsr(sc, 0); 467 1.1 thorpej lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_RINT)); 468 1.1 thorpej cdm = &sc->sc_rd[sc->sc_next_rd]; 469 1.1 thorpej if (cdm->flags & LE_OWN) 470 1.1 thorpej return 0; 471 1.1 thorpej #ifdef LE_DEBUG 472 1.1 thorpej if (le_debug) { 473 1.1 thorpej printf("next_rd %d\n", sc->sc_next_rd); 474 1.1 thorpej printf("cdm->flags %x\n", cdm->flags); 475 1.1 thorpej printf("cdm->bcnt %x, cdm->mcnt %x\n", cdm->bcnt, cdm->mcnt); 476 1.1 thorpej printf("cdm->rbuf msg %d buf %d\n", cdm->mcnt, -cdm->bcnt ); 477 1.1 thorpej } 478 1.1 thorpej #endif 479 1.1 thorpej if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 480 1.1 thorpej le_error(unit, "le_poll", stat); 481 1.1 thorpej if (cdm->flags & (LE_FRAM | LE_OFLO | LE_CRC | LE_RBUFF)) { 482 1.1 thorpej printf("le%d_poll: rmd status 0x%x\n", unit, cdm->flags); 483 1.1 thorpej length = 0; 484 1.1 thorpej goto cleanup; 485 1.1 thorpej } 486 1.1 thorpej if ((cdm->flags & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) 487 1.5 provos panic("le_poll: chained packet"); 488 1.1 thorpej 489 1.1 thorpej length = cdm->mcnt; 490 1.1 thorpej #ifdef LE_DEBUG 491 1.1 thorpej if (le_debug) 492 1.1 thorpej printf("le_poll: length %d\n", length); 493 1.1 thorpej #endif 494 1.1 thorpej if (length >= BUFSIZE) { 495 1.16 tsutsui printf("le%d_poll: invalid length %d, status 0x%x\n", 496 1.16 tsutsui unit, length, stat); 497 1.1 thorpej length = 0; 498 1.1 thorpej goto cleanup; 499 1.1 thorpej } 500 1.1 thorpej if (!length) 501 1.1 thorpej goto cleanup; 502 1.1 thorpej length -= 4; 503 1.1 thorpej 504 1.1 thorpej if (length > 0) { 505 1.1 thorpej /* 506 1.1 thorpej * If the length of the packet is greater than the size of the 507 1.1 thorpej * buffer, we have to truncate it, to avoid Bad Things. 508 1.1 thorpej * XXX Is this the right thing to do? 509 1.1 thorpej */ 510 1.1 thorpej if (length > len) 511 1.1 thorpej length = len; 512 1.1 thorpej 513 1.7 tsutsui memcpy(pkt, sc->sc_rbuf + (BUFSIZE * sc->sc_next_rd), length); 514 1.1 thorpej } 515 1.1 thorpej 516 1.1 thorpej cleanup: 517 1.1 thorpej cdm->mcnt = 0; 518 1.1 thorpej cdm->flags |= LE_OWN; 519 1.1 thorpej if (++sc->sc_next_rd >= NRBUF) 520 1.1 thorpej sc->sc_next_rd = 0; 521 1.1 thorpej #ifdef LE_DEBUG 522 1.1 thorpej if (le_debug) 523 1.1 thorpej printf("new next_rd %d\n", sc->sc_next_rd); 524 1.1 thorpej #endif 525 1.1 thorpej 526 1.1 thorpej return length; 527 1.1 thorpej } 528 1.1 thorpej 529 1.14 tsutsui static int 530 1.8 tsutsui le_put(struct iodesc *desc, void *pkt, size_t len) 531 1.1 thorpej { 532 1.1 thorpej int unit = /*nif->nif_unit*/0; 533 1.1 thorpej struct le_softc *sc = &le_softc[unit]; 534 1.1 thorpej volatile struct mds *cdm; 535 1.13 tsutsui int timo, stat; 536 1.13 tsutsui #if 0 537 1.13 tsutsui int i; 538 1.13 tsutsui #endif 539 1.1 thorpej 540 1.1 thorpej le_put_loop: 541 1.1 thorpej timo = 100000; 542 1.1 thorpej 543 1.1 thorpej #ifdef LE_DEBUG 544 1.1 thorpej if (le_debug) 545 1.1 thorpej printf("le%d: le_put called. next_td=%d\n", unit, sc->sc_next_td); 546 1.1 thorpej #endif 547 1.1 thorpej stat = lerdcsr(sc, 0); 548 1.1 thorpej lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_TINT)); 549 1.1 thorpej if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 550 1.1 thorpej le_error(unit, "le_put(way before xmit)", stat); 551 1.1 thorpej cdm = &sc->sc_td[sc->sc_next_td]; 552 1.13 tsutsui #if 0 553 1.7 tsutsui i = 0; 554 1.1 thorpej while (cdm->flags & LE_OWN) { 555 1.1 thorpej if ((i % 100) == 0) 556 1.1 thorpej printf("le%d: output buffer busy - flags=%x\n", 557 1.1 thorpej unit, cdm->flags); 558 1.1 thorpej if (i++ > 500) break; 559 1.1 thorpej } 560 1.1 thorpej if (cdm->flags & LE_OWN) 561 1.1 thorpej getchar(); 562 1.1 thorpej #else 563 1.1 thorpej while (cdm->flags & LE_OWN); 564 1.1 thorpej #endif 565 1.7 tsutsui memcpy(sc->sc_tbuf + (BUFSIZE * sc->sc_next_td), pkt, len); 566 1.1 thorpej if (len < ETHER_MIN_LEN) 567 1.1 thorpej cdm->bcnt = -ETHER_MIN_LEN; 568 1.7 tsutsui else 569 1.1 thorpej cdm->bcnt = -len; 570 1.1 thorpej cdm->mcnt = 0; 571 1.1 thorpej cdm->flags |= LE_OWN | LE_STP | LE_ENP; 572 1.1 thorpej stat = lerdcsr(sc, 0); 573 1.1 thorpej if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 574 1.1 thorpej le_error(unit, "le_put(before xmit)", stat); 575 1.1 thorpej lewrcsr(sc, 0, LE_TDMD); 576 1.1 thorpej stat = lerdcsr(sc, 0); 577 1.1 thorpej if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 578 1.1 thorpej le_error(unit, "le_put(after xmit)", stat); 579 1.1 thorpej do { 580 1.1 thorpej if (--timo == 0) { 581 1.1 thorpej printf("le%d: transmit timeout, stat = 0x%x\n", 582 1.1 thorpej unit, stat); 583 1.1 thorpej if (stat & LE_SERR) 584 1.1 thorpej le_error(unit, "le_put(timeout)", stat); 585 1.1 thorpej if (stat & LE_INIT) { 586 1.7 tsutsui printf("le%d: reset and retry packet\n", unit); 587 1.1 thorpej lewrcsr(sc, 0, LE_TINT); /* sanity */ 588 1.7 tsutsui leinit(); 589 1.1 thorpej goto le_put_loop; 590 1.1 thorpej } 591 1.1 thorpej break; 592 1.1 thorpej } 593 1.1 thorpej stat = lerdcsr(sc, 0); 594 1.1 thorpej } while ((stat & LE_TINT) == 0); 595 1.1 thorpej lewrcsr(sc, 0, LE_TINT); 596 1.1 thorpej if (stat & (LE_BABL |/* LE_CERR |*/ LE_MISS | LE_MERR)) { 597 1.1 thorpej printf("le_put: xmit error, buf %d\n", sc->sc_next_td); 598 1.1 thorpej le_error(unit, "le_put(xmit error)", stat); 599 1.1 thorpej } 600 1.1 thorpej if (++sc->sc_next_td >= NTBUF) 601 1.1 thorpej sc->sc_next_td = 0; 602 1.1 thorpej if (cdm->flags & LE_DEF) 603 1.1 thorpej le_stats[unit].deferred++; 604 1.1 thorpej if (cdm->flags & LE_ONE) 605 1.1 thorpej le_stats[unit].collisions++; 606 1.1 thorpej if (cdm->flags & LE_MORE) 607 1.2 scottr le_stats[unit].collisions += 2; 608 1.1 thorpej if (cdm->flags & LE_ERR) { 609 1.2 scottr if (cdm->mcnt & LE_UFLO) 610 1.2 scottr printf("le%d: transmit underflow\n", unit); 611 1.2 scottr if (cdm->mcnt & LE_LCOL) 612 1.2 scottr le_stats[unit].collisions++; 613 1.2 scottr if (cdm->mcnt & LE_LCAR) 614 1.2 scottr printf("le%d: lost carrier\n", unit); 615 1.2 scottr if (cdm->mcnt & LE_RTRY) 616 1.2 scottr le_stats[unit].collisions += 16; 617 1.1 thorpej return -1; 618 1.1 thorpej } 619 1.1 thorpej #ifdef LE_DEBUG 620 1.1 thorpej if (le_debug) { 621 1.1 thorpej printf("le%d: le_put() successful: sent %d\n", unit, len); 622 1.1 thorpej printf("le%d: le_put(): flags: %x mcnt: %x\n", unit, 623 1.1 thorpej (unsigned int) cdm->flags, 624 1.1 thorpej (unsigned int) cdm->mcnt); 625 1.1 thorpej } 626 1.1 thorpej #endif 627 1.1 thorpej return len; 628 1.1 thorpej } 629 1.1 thorpej 630 1.1 thorpej 631 1.14 tsutsui static int 632 1.11 tsutsui le_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout) 633 1.1 thorpej { 634 1.11 tsutsui satime_t t; 635 1.1 thorpej int cc; 636 1.1 thorpej 637 1.1 thorpej t = getsecs(); 638 1.12 tsutsui do { 639 1.1 thorpej cc = le_poll(desc, pkt, len); 640 1.12 tsutsui } while (cc == 0 && (getsecs() - t) < timeout); 641 1.1 thorpej return cc; 642 1.1 thorpej } 643 1.1 thorpej 644 1.14 tsutsui static void 645 1.8 tsutsui le_init(struct iodesc *desc, void *machdep_hint) 646 1.1 thorpej { 647 1.1 thorpej struct netif *nif = desc->io_netif; 648 1.1 thorpej int unit = nif->nif_unit; 649 1.1 thorpej 650 1.1 thorpej /* Get machine's common ethernet interface. This is done in leinit() */ 651 1.1 thorpej /* machdep_common_ether(myea); */ 652 1.1 thorpej leinit(); 653 1.1 thorpej 654 1.1 thorpej #ifdef LE_DEBUG 655 1.1 thorpej if (le_debug) 656 1.1 thorpej printf("le%d: le_init called\n", unit); 657 1.1 thorpej #endif 658 1.1 thorpej unit = 0; 659 1.1 thorpej le_reset(unit, desc->myea); 660 1.1 thorpej } 661 1.1 thorpej 662 1.14 tsutsui static void 663 1.8 tsutsui le_end(struct netif *nif) 664 1.1 thorpej { 665 1.1 thorpej int unit = nif->nif_unit; 666 1.1 thorpej 667 1.1 thorpej #ifdef LE_DEBUG 668 1.1 thorpej if (le_debug) 669 1.1 thorpej printf("le%d: le_end called\n", unit); 670 1.1 thorpej #endif 671 1.1 thorpej 672 1.1 thorpej lewrcsr(&le_softc[unit], 0, LE_STOP); 673 1.1 thorpej } 674