1 /* $OpenBSD: sxie.c,v 1.22 2016/09/11 21:44:30 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> 4 * Copyright (c) 2013 Artturi Alm 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* TODO this should use dedicated dma for RX, atleast */ 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/sockio.h> 24 #include <sys/queue.h> 25 #include <sys/malloc.h> 26 #include <sys/device.h> 27 #include <sys/evcount.h> 28 #include <sys/socket.h> 29 #include <sys/timeout.h> 30 #include <sys/mbuf.h> 31 #include <machine/intr.h> 32 #include <machine/bus.h> 33 #include <machine/fdt.h> 34 35 #include "bpfilter.h" 36 37 #include <net/if.h> 38 #include <net/if_media.h> 39 #if NBPFILTER > 0 40 #include <net/bpf.h> 41 #endif 42 43 #include <netinet/in.h> 44 #include <netinet/if_ether.h> 45 46 #include <dev/mii/mii.h> 47 #include <dev/mii/miivar.h> 48 49 #include <armv7/sunxi/sunxireg.h> 50 51 #include <dev/ofw/openfirm.h> 52 #include <dev/ofw/ofw_clock.h> 53 #include <dev/ofw/ofw_pinctrl.h> 54 #include <dev/ofw/fdt.h> 55 56 /* configuration registers */ 57 #define SXIE_CR 0x0000 58 #define SXIE_TXMODE 0x0004 59 #define SXIE_TXFLOW 0x0008 60 #define SXIE_TXCR0 0x000c 61 #define SXIE_TXCR1 0x0010 62 #define SXIE_TXINS 0x0014 63 #define SXIE_TXPKTLEN0 0x0018 64 #define SXIE_TXPKTLEN1 0x001c 65 #define SXIE_TXSR 0x0020 66 #define SXIE_TXIO0 0x0024 67 #define SXIE_TXIO1 0x0028 68 #define SXIE_TXTSVL0 0x002c 69 #define SXIE_TXTSVH0 0x0030 70 #define SXIE_TXTSVL1 0x0034 71 #define SXIE_TXTSVH1 0x0038 72 #define SXIE_RXCR 0x003c 73 #define SXIE_RXHASH0 0x0040 74 #define SXIE_RXHASH1 0x0044 75 #define SXIE_RXSR 0x0048 76 #define SXIE_RXIO 0x004C 77 #define SXIE_RXFBC 0x0050 78 #define SXIE_INTCR 0x0054 79 #define SXIE_INTSR 0x0058 80 #define SXIE_MACCR0 0x005C 81 #define SXIE_MACCR1 0x0060 82 #define SXIE_MACIPGT 0x0064 83 #define SXIE_MACIPGR 0x0068 84 #define SXIE_MACCLRT 0x006C 85 #define SXIE_MACMFL 0x0070 86 #define SXIE_MACSUPP 0x0074 87 #define SXIE_MACTEST 0x0078 88 #define SXIE_MACMCFG 0x007C 89 #define SXIE_MACMCMD 0x0080 90 #define SXIE_MACMADR 0x0084 91 #define SXIE_MACMWTD 0x0088 92 #define SXIE_MACMRDD 0x008C 93 #define SXIE_MACMIND 0x0090 94 #define SXIE_MACSSRR 0x0094 95 #define SXIE_MACA0 0x0098 96 #define SXIE_MACA1 0x009c 97 #define SXIE_MACA2 0x00a0 98 99 /* i once spent hours on pretty defines, cvs up ate 'em. these shall do */ 100 #define SXIE_INTR_ENABLE 0x010f 101 #define SXIE_INTR_DISABLE 0x0000 102 #define SXIE_INTR_CLEAR 0x0000 103 104 #define SXIE_TX_FIFO0 0x0001 105 #define SXIE_TX_FIFO1 0x0002 106 107 #define SXIE_RX_ENABLE 0x0004 108 #define SXIE_TX_ENABLE 0x0003 109 #define SXIE_RXTX_ENABLE 0x0007 110 111 #define SXIE_RXDRQM 0x0002 112 #define SXIE_RXTM 0x0004 113 #define SXIE_RXFLUSH 0x0008 114 #define SXIE_RXPA 0x0010 115 #define SXIE_RXPCF 0x0020 116 #define SXIE_RXPCRCE 0x0040 117 #define SXIE_RXPLE 0x0080 118 #define SXIE_RXPOR 0x0100 119 #define SXIE_RXUCAD 0x10000 120 #define SXIE_RXDAF 0x20000 121 #define SXIE_RXMCO 0x100000 122 #define SXIE_RXMHF 0x200000 123 #define SXIE_RXBCO 0x400000 124 #define SXIE_RXSAF 0x1000000 125 #define SXIE_RXSAIF 0x2000000 126 127 #define SXIE_MACRXFC 0x0004 128 #define SXIE_MACTXFC 0x0008 129 #define SXIE_MACSOFTRESET 0x8000 130 131 #define SXIE_MACDUPLEX 0x0001 /* full = 1 */ 132 #define SXIE_MACFLC 0x0002 133 #define SXIE_MACHF 0x0004 134 #define SXIE_MACDCRC 0x0008 135 #define SXIE_MACCRC 0x0010 136 #define SXIE_MACPC 0x0020 137 #define SXIE_MACVC 0x0040 138 #define SXIE_MACADP 0x0080 139 #define SXIE_MACPRE 0x0100 140 #define SXIE_MACLPE 0x0200 141 #define SXIE_MACNB 0x1000 142 #define SXIE_MACBNB 0x2000 143 #define SXIE_MACED 0x4000 144 145 #define SXIE_RX_ERRLENOOR 0x0040 146 #define SXIE_RX_ERRLENCHK 0x0020 147 #define SXIE_RX_ERRCRC 0x0010 148 #define SXIE_RX_ERRRCV 0x0008 /* XXX receive code violation ? */ 149 #define SXIE_RX_ERRMASK 0x0070 150 151 #define SXIE_MII_TIMEOUT 100 152 #define SXIE_MAX_RXD 8 153 #define SXIE_MAX_PKT_SIZE ETHER_MAX_DIX_LEN 154 155 #define SXIE_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) 156 157 struct sxie_softc { 158 struct device sc_dev; 159 struct arpcom sc_ac; 160 struct mii_data sc_mii; 161 int sc_phyno; 162 bus_space_tag_t sc_iot; 163 bus_space_handle_t sc_ioh; 164 bus_space_handle_t sc_sid_ioh; 165 void *sc_ih; /* Interrupt handler */ 166 uint32_t intr_status; /* soft interrupt status */ 167 uint32_t pauseframe; 168 uint32_t txf_inuse; 169 }; 170 171 struct sxie_softc *sxie_sc; 172 173 int sxie_match(struct device *, void *, void *); 174 void sxie_attach(struct device *, struct device *, void *); 175 void sxie_setup_interface(struct sxie_softc *, struct device *); 176 void sxie_socware_init(struct sxie_softc *); 177 int sxie_ioctl(struct ifnet *, u_long, caddr_t); 178 void sxie_start(struct ifnet *); 179 void sxie_watchdog(struct ifnet *); 180 void sxie_init(struct sxie_softc *); 181 void sxie_stop(struct sxie_softc *); 182 void sxie_reset(struct sxie_softc *); 183 void sxie_iff(struct sxie_softc *, struct ifnet *); 184 int sxie_intr(void *); 185 void sxie_recv(struct sxie_softc *); 186 int sxie_miibus_readreg(struct device *, int, int); 187 void sxie_miibus_writereg(struct device *, int, int, int); 188 void sxie_miibus_statchg(struct device *); 189 int sxie_ifm_change(struct ifnet *); 190 void sxie_ifm_status(struct ifnet *, struct ifmediareq *); 191 192 struct cfattach sxie_ca = { 193 sizeof (struct sxie_softc), sxie_match, sxie_attach 194 }; 195 196 struct cfdriver sxie_cd = { 197 NULL, "sxie", DV_IFNET 198 }; 199 200 int 201 sxie_match(struct device *parent, void *match, void *aux) 202 { 203 struct fdt_attach_args *faa = aux; 204 205 return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-emac"); 206 } 207 208 void 209 sxie_attach(struct device *parent, struct device *self, void *aux) 210 { 211 struct sxie_softc *sc = (struct sxie_softc *) self; 212 struct fdt_attach_args *faa = aux; 213 struct mii_data *mii; 214 struct ifnet *ifp; 215 int s; 216 217 if (faa->fa_nreg < 1) 218 return; 219 220 pinctrl_byname(faa->fa_node, "default"); 221 222 sc->sc_iot = faa->fa_iot; 223 224 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 225 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 226 panic("sxie_attach: bus_space_map ioh failed!"); 227 228 if (bus_space_map(sc->sc_iot, SID_ADDR, SID_SIZE, 0, &sc->sc_sid_ioh)) 229 panic("sxie_attach: bus_space_map sid_ioh failed!"); 230 231 clock_enable_all(faa->fa_node); 232 233 sxie_socware_init(sc); 234 sc->txf_inuse = 0; 235 236 sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_NET, 237 sxie_intr, sc, sc->sc_dev.dv_xname); 238 239 s = splnet(); 240 241 printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); 242 243 /* XXX verify flags & capabilities */ 244 ifp = &sc->sc_ac.ac_if; 245 ifp->if_softc = sc; 246 strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 247 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 248 ifp->if_ioctl = sxie_ioctl; 249 ifp->if_start = sxie_start; 250 ifp->if_watchdog = sxie_watchdog; 251 ifp->if_capabilities = IFCAP_VLAN_MTU; /* XXX status check in recv? */ 252 253 IFQ_SET_MAXLEN(&ifp->if_snd, 1); 254 255 /* Initialize MII/media info. */ 256 mii = &sc->sc_mii; 257 mii->mii_ifp = ifp; 258 mii->mii_readreg = sxie_miibus_readreg; 259 mii->mii_writereg = sxie_miibus_writereg; 260 mii->mii_statchg = sxie_miibus_statchg; 261 mii->mii_flags = MIIF_AUTOTSLEEP; 262 263 ifmedia_init(&mii->mii_media, 0, sxie_ifm_change, sxie_ifm_status); 264 mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0); 265 266 if (LIST_FIRST(&mii->mii_phys) == NULL) { 267 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); 268 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); 269 } else 270 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 271 272 if_attach(ifp); 273 ether_ifattach(ifp); 274 splx(s); 275 276 sxie_sc = sc; 277 } 278 279 void 280 sxie_socware_init(struct sxie_softc *sc) 281 { 282 int have_mac = 0; 283 uint32_t reg; 284 285 /* MII clock cfg */ 286 SXICMS4(sc, SXIE_MACMCFG, 15 << 2, 13 << 2); 287 288 SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); 289 SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR); 290 291 /* 292 * If u-boot doesn't set emac, use the Security ID area 293 * to generate a consistent MAC address of. 294 */ 295 reg = SXIREAD4(sc, SXIE_MACA0); 296 if (reg != 0) { 297 sc->sc_ac.ac_enaddr[3] = reg >> 16 & 0xff; 298 sc->sc_ac.ac_enaddr[4] = reg >> 8 & 0xff; 299 sc->sc_ac.ac_enaddr[5] = reg & 0xff; 300 reg = SXIREAD4(sc, SXIE_MACA1); 301 sc->sc_ac.ac_enaddr[0] = reg >> 16 & 0xff; 302 sc->sc_ac.ac_enaddr[1] = reg >> 8 & 0xff; 303 sc->sc_ac.ac_enaddr[2] = reg & 0xff; 304 305 have_mac = 1; 306 } 307 308 reg = bus_space_read_4(sc->sc_iot, sc->sc_sid_ioh, 0x0); 309 310 if (!have_mac && reg != 0) { 311 sc->sc_ac.ac_enaddr[0] = 0x02; 312 sc->sc_ac.ac_enaddr[1] = reg & 0xff; 313 reg = bus_space_read_4(sc->sc_iot, sc->sc_sid_ioh, 0x0c); 314 sc->sc_ac.ac_enaddr[2] = reg >> 24 & 0xff; 315 sc->sc_ac.ac_enaddr[3] = reg >> 16 & 0xff; 316 sc->sc_ac.ac_enaddr[4] = reg >> 8 & 0xff; 317 sc->sc_ac.ac_enaddr[5] = reg & 0xff; 318 319 have_mac = 1; 320 } 321 322 if (!have_mac) 323 ether_fakeaddr(&sc->sc_ac.ac_if); 324 325 sc->sc_phyno = 1; 326 } 327 328 void 329 sxie_setup_interface(struct sxie_softc *sc, struct device *dev) 330 { 331 uint32_t clr_m, set_m; 332 333 /* configure TX */ 334 SXICMS4(sc, SXIE_TXMODE, 3, 1); /* cpu mode */ 335 336 /* configure RX */ 337 clr_m = SXIE_RXDRQM | SXIE_RXTM | SXIE_RXPA | SXIE_RXPCF | 338 SXIE_RXPCRCE | SXIE_RXPLE | SXIE_RXMHF | SXIE_RXSAF | 339 SXIE_RXSAIF; 340 set_m = SXIE_RXPOR | SXIE_RXUCAD | SXIE_RXDAF | SXIE_RXBCO; 341 SXICMS4(sc, SXIE_RXCR, clr_m, set_m); 342 343 /* configure MAC */ 344 SXISET4(sc, SXIE_MACCR0, SXIE_MACTXFC | SXIE_MACRXFC); 345 clr_m = SXIE_MACHF | SXIE_MACDCRC | SXIE_MACVC | SXIE_MACADP | 346 SXIE_MACPRE | SXIE_MACLPE | SXIE_MACNB | SXIE_MACBNB | 347 SXIE_MACED; 348 set_m = SXIE_MACFLC | SXIE_MACCRC | SXIE_MACPC; 349 set_m |= sxie_miibus_readreg(dev, sc->sc_phyno, 0) >> 8 & 1; 350 SXICMS4(sc, SXIE_MACCR1, clr_m, set_m); 351 352 /* XXX */ 353 SXIWRITE4(sc, SXIE_MACIPGT, 0x0015); 354 SXIWRITE4(sc, SXIE_MACIPGR, 0x0c12); 355 356 /* XXX set collision window */ 357 SXIWRITE4(sc, SXIE_MACCLRT, 0x370f); 358 359 /* set max frame length */ 360 SXIWRITE4(sc, SXIE_MACMFL, SXIE_MAX_PKT_SIZE); 361 362 /* set lladdr */ 363 SXIWRITE4(sc, SXIE_MACA0, 364 sc->sc_ac.ac_enaddr[3] << 16 | 365 sc->sc_ac.ac_enaddr[4] << 8 | 366 sc->sc_ac.ac_enaddr[5]); 367 SXIWRITE4(sc, SXIE_MACA1, 368 sc->sc_ac.ac_enaddr[0] << 16 | 369 sc->sc_ac.ac_enaddr[1] << 8 | 370 sc->sc_ac.ac_enaddr[2]); 371 372 sxie_reset(sc); 373 /* XXX possibly missing delay in here. */ 374 } 375 376 void 377 sxie_init(struct sxie_softc *sc) 378 { 379 struct ifnet *ifp = &sc->sc_ac.ac_if; 380 struct device *dev = (struct device *)sc; 381 int phyreg; 382 383 sxie_reset(sc); 384 385 SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); 386 387 SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR); 388 389 SXISET4(sc, SXIE_RXCR, SXIE_RXFLUSH); 390 391 /* soft reset */ 392 SXICLR4(sc, SXIE_MACCR0, SXIE_MACSOFTRESET); 393 394 /* zero rx counter */ 395 SXIWRITE4(sc, SXIE_RXFBC, 0); 396 397 sxie_setup_interface(sc, dev); 398 399 /* power up PHY */ 400 sxie_miibus_writereg(dev, sc->sc_phyno, 0, 401 sxie_miibus_readreg(dev, sc->sc_phyno, 0) & ~(1 << 11)); 402 delay(1000); 403 phyreg = sxie_miibus_readreg(dev, sc->sc_phyno, 0); 404 405 /* set duplex */ 406 SXICMS4(sc, SXIE_MACCR1, 1, phyreg >> 8 & 1); 407 408 /* set speed */ 409 SXICMS4(sc, SXIE_MACSUPP, 1 << 8, (phyreg >> 13 & 1) << 8); 410 411 SXISET4(sc, SXIE_CR, SXIE_RXTX_ENABLE); 412 413 /* Indicate we are up and running. */ 414 ifp->if_flags |= IFF_RUNNING; 415 ifq_clr_oactive(&ifp->if_snd); 416 417 SXISET4(sc, SXIE_INTCR, SXIE_INTR_ENABLE); 418 419 sxie_start(ifp); 420 } 421 422 int 423 sxie_intr(void *arg) 424 { 425 struct sxie_softc *sc = arg; 426 struct ifnet *ifp = &sc->sc_ac.ac_if; 427 uint32_t pending; 428 429 SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); 430 431 pending = SXIREAD4(sc, SXIE_INTSR); 432 SXIWRITE4(sc, SXIE_INTSR, pending); 433 434 /* 435 * Handle incoming packets. 436 */ 437 if (pending & 0x0100) { 438 if (ifp->if_flags & IFF_RUNNING) 439 sxie_recv(sc); 440 } 441 442 if (pending & (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { 443 ifq_clr_oactive(&ifp->if_snd); 444 if (pending & SXIE_TX_FIFO0) 445 ifp->if_opackets++; 446 if (pending & SXIE_TX_FIFO1) 447 ifp->if_opackets++; 448 sc->txf_inuse &= ~pending; 449 if (sc->txf_inuse == 0) 450 ifp->if_timer = 0; 451 else 452 ifp->if_timer = 5; 453 } 454 455 if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) 456 sxie_start(ifp); 457 458 SXISET4(sc, SXIE_INTCR, SXIE_INTR_ENABLE); 459 460 return 1; 461 } 462 463 /* 464 * XXX there's secondary tx fifo to be used. 465 */ 466 void 467 sxie_start(struct ifnet *ifp) 468 { 469 struct sxie_softc *sc = ifp->if_softc; 470 struct mbuf *m; 471 struct mbuf *head; 472 uint8_t *td; 473 uint32_t fifo; 474 uint32_t txbuf[SXIE_MAX_PKT_SIZE / sizeof(uint32_t)]; /* XXX !!! */ 475 476 if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) 477 ifq_set_oactive(&ifp->if_snd); 478 479 if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) 480 return; 481 482 td = (uint8_t *)&txbuf[0]; 483 m = NULL; 484 head = NULL; 485 trynext: 486 m = ifq_deq_begin(&ifp->if_snd); 487 if (m == NULL) 488 return; 489 490 if (m->m_pkthdr.len > SXIE_MAX_PKT_SIZE) { 491 ifq_deq_commit(&ifp->if_snd, m); 492 printf("sxie_start: packet too big\n"); 493 m_freem(m); 494 return; 495 } 496 497 if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { 498 ifq_deq_rollback(&ifp->if_snd, m); 499 printf("sxie_start: tx fifos in use.\n"); 500 ifq_set_oactive(&ifp->if_snd); 501 return; 502 } 503 504 /* select fifo */ 505 if (sc->txf_inuse & SXIE_TX_FIFO0) { 506 sc->txf_inuse |= SXIE_TX_FIFO1; 507 fifo = 1; 508 } else { 509 sc->txf_inuse |= SXIE_TX_FIFO0; 510 fifo = 0; 511 } 512 SXIWRITE4(sc, SXIE_TXINS, fifo); 513 514 /* set packet length */ 515 SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len); 516 517 /* copy the actual packet to fifo XXX through 'align buffer'.. */ 518 m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)td); 519 bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh, 520 SXIE_TXIO0 + (fifo * 4), 521 (uint32_t *)td, SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2); 522 523 /* transmit to PHY from fifo */ 524 SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1); 525 ifp->if_timer = 5; 526 ifq_deq_commit(&ifp->if_snd, m); 527 528 #if NBPFILTER > 0 529 if (ifp->if_bpf) 530 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 531 #endif 532 m_freem(m); 533 534 goto trynext; 535 } 536 537 void 538 sxie_stop(struct sxie_softc *sc) 539 { 540 struct ifnet *ifp = &sc->sc_ac.ac_if; 541 542 sxie_reset(sc); 543 544 ifp->if_flags &= ~IFF_RUNNING; 545 ifp->if_timer = 0; 546 ifq_clr_oactive(&ifp->if_snd); 547 } 548 549 void 550 sxie_reset(struct sxie_softc *sc) 551 { 552 /* reset the controller */ 553 SXIWRITE4(sc, SXIE_CR, 0); 554 delay(200); 555 SXIWRITE4(sc, SXIE_CR, 1); 556 delay(200); 557 } 558 559 void 560 sxie_watchdog(struct ifnet *ifp) 561 { 562 struct sxie_softc *sc = ifp->if_softc; 563 if (sc->pauseframe) { 564 ifp->if_timer = 5; 565 return; 566 } 567 printf("%s: watchdog tx timeout\n", sc->sc_dev.dv_xname); 568 ifp->if_oerrors++; 569 sxie_init(sc); 570 sxie_start(ifp); 571 } 572 573 /* 574 * XXX DMA? 575 */ 576 void 577 sxie_recv(struct sxie_softc *sc) 578 { 579 struct ifnet *ifp = &sc->sc_ac.ac_if; 580 uint32_t fbc, reg; 581 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 582 struct mbuf *m; 583 uint16_t pktstat; 584 int16_t pktlen; 585 int rlen; 586 char rxbuf[SXIE_MAX_PKT_SIZE]; /* XXX !!! */ 587 trynext: 588 fbc = SXIREAD4(sc, SXIE_RXFBC); 589 if (!fbc) 590 goto done; 591 592 /* 593 * first bit of MSB is packet valid flag, 594 * it is 'padded' with 0x43414d = "MAC" 595 */ 596 reg = SXIREAD4(sc, SXIE_RXIO); 597 if (reg != 0x0143414d) { /* invalid packet */ 598 /* disable, flush, enable */ 599 SXICLR4(sc, SXIE_CR, SXIE_RX_ENABLE); 600 SXISET4(sc, SXIE_RXCR, SXIE_RXFLUSH); 601 while (SXIREAD4(sc, SXIE_RXCR) & SXIE_RXFLUSH); 602 SXISET4(sc, SXIE_CR, SXIE_RX_ENABLE); 603 604 goto err_out; 605 } 606 607 reg = SXIREAD4(sc, SXIE_RXIO); 608 pktstat = (uint16_t)reg >> 16; 609 pktlen = (int16_t)reg; /* length of useful data */ 610 611 if (pktstat & SXIE_RX_ERRMASK || pktlen < ETHER_MIN_LEN) { 612 ifp->if_ierrors++; 613 goto trynext; 614 } 615 if (pktlen > SXIE_MAX_PKT_SIZE) 616 pktlen = SXIE_MAX_PKT_SIZE; /* XXX is truncating ok? */ 617 618 /* read the actual packet from fifo XXX through 'align buffer'.. */ 619 if (pktlen & 3) 620 rlen = SXIE_ROUNDUP(pktlen, 4); 621 else 622 rlen = pktlen; 623 bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh, 624 SXIE_RXIO, (uint32_t *)&rxbuf[0], rlen >> 2); 625 626 m = m_devget(&rxbuf[0], pktlen, ETHER_ALIGN); 627 if (m == NULL) { 628 ifp->if_ierrors++; 629 goto err_out; 630 } 631 632 ml_enqueue(&ml, m); 633 goto trynext; 634 err_out: 635 ifp->if_ierrors++; 636 done: 637 if_input(ifp, &ml); 638 } 639 640 int 641 sxie_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 642 { 643 struct sxie_softc *sc = ifp->if_softc; 644 struct ifreq *ifr = (struct ifreq *)data; 645 int s, error = 0; 646 647 s = splnet(); 648 649 switch (cmd) { 650 case SIOCSIFADDR: 651 if (!(ifp->if_flags & IFF_UP)) { 652 ifp->if_flags |= IFF_UP; 653 sxie_init(sc); 654 } 655 break; 656 case SIOCSIFFLAGS: 657 if (ifp->if_flags & IFF_UP) { 658 if (ifp->if_flags & IFF_RUNNING) 659 error = ENETRESET; 660 else 661 sxie_init(sc); 662 } else if (ifp->if_flags & IFF_RUNNING) 663 sxie_stop(sc); 664 break; 665 case SIOCGIFMEDIA: 666 case SIOCSIFMEDIA: 667 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 668 break; 669 default: 670 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 671 } 672 if (error == ENETRESET) { 673 if (ifp->if_flags & IFF_RUNNING) 674 sxie_iff(sc, ifp); 675 error = 0; 676 } 677 678 splx(s); 679 return error; 680 } 681 682 void 683 sxie_iff(struct sxie_softc *sc, struct ifnet *ifp) 684 { 685 /* XXX set interface features */ 686 } 687 688 /* 689 * MII 690 */ 691 int 692 sxie_miibus_readreg(struct device *dev, int phy, int reg) 693 { 694 struct sxie_softc *sc = (struct sxie_softc *)dev; 695 int timo = SXIE_MII_TIMEOUT; 696 697 SXIWRITE4(sc, SXIE_MACMADR, phy << 8 | reg); 698 699 SXIWRITE4(sc, SXIE_MACMCMD, 1); 700 while (SXIREAD4(sc, SXIE_MACMIND) & 1 && --timo) 701 delay(10); 702 #ifdef DIAGNOSTIC 703 if (!timo) 704 printf("%s: sxie_miibus_readreg timeout.\n", 705 sc->sc_dev.dv_xname); 706 #endif 707 708 SXIWRITE4(sc, SXIE_MACMCMD, 0); 709 710 return SXIREAD4(sc, SXIE_MACMRDD) & 0xffff; 711 } 712 713 void 714 sxie_miibus_writereg(struct device *dev, int phy, int reg, int val) 715 { 716 struct sxie_softc *sc = (struct sxie_softc *)dev; 717 int timo = SXIE_MII_TIMEOUT; 718 719 SXIWRITE4(sc, SXIE_MACMADR, phy << 8 | reg); 720 721 SXIWRITE4(sc, SXIE_MACMCMD, 1); 722 while (SXIREAD4(sc, SXIE_MACMIND) & 1 && --timo) 723 delay(10); 724 #ifdef DIAGNOSTIC 725 if (!timo) 726 printf("%s: sxie_miibus_readreg timeout.\n", 727 sc->sc_dev.dv_xname); 728 #endif 729 730 SXIWRITE4(sc, SXIE_MACMCMD, 0); 731 732 SXIWRITE4(sc, SXIE_MACMWTD, val); 733 } 734 735 void 736 sxie_miibus_statchg(struct device *dev) 737 { 738 /* XXX */ 739 #if 0 740 struct sxie_softc *sc = (struct sxie_softc *)dev; 741 742 switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { 743 case IFM_10_T: 744 case IFM_100_TX: 745 /*case IFM_1000_T: only on GMAC */ 746 break; 747 default: 748 break; 749 } 750 #endif 751 } 752 753 int 754 sxie_ifm_change(struct ifnet *ifp) 755 { 756 struct sxie_softc *sc = ifp->if_softc; 757 struct mii_data *mii = &sc->sc_mii; 758 759 if (mii->mii_instance) { 760 struct mii_softc *miisc; 761 762 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 763 mii_phy_reset(miisc); 764 } 765 return mii_mediachg(mii); 766 } 767 768 void 769 sxie_ifm_status(struct ifnet *ifp, struct ifmediareq *ifmr) 770 { 771 struct sxie_softc *sc = (struct sxie_softc *)ifp->if_softc; 772 773 mii_pollstat(&sc->sc_mii); 774 ifmr->ifm_active = sc->sc_mii.mii_media_active; 775 ifmr->ifm_status = sc->sc_mii.mii_media_status; 776 } 777