1 1.36 andvar /* $NetBSD: if_smap.c,v 1.36 2023/11/05 21:50:27 andvar Exp $ */ 2 1.1 uch 3 1.1 uch /*- 4 1.1 uch * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.1 uch * All rights reserved. 6 1.1 uch * 7 1.1 uch * This code is derived from software contributed to The NetBSD Foundation 8 1.1 uch * by UCHIYAMA Yasushi. 9 1.1 uch * 10 1.1 uch * Redistribution and use in source and binary forms, with or without 11 1.1 uch * modification, are permitted provided that the following conditions 12 1.1 uch * are met: 13 1.1 uch * 1. Redistributions of source code must retain the above copyright 14 1.1 uch * notice, this list of conditions and the following disclaimer. 15 1.1 uch * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 uch * notice, this list of conditions and the following disclaimer in the 17 1.1 uch * documentation and/or other materials provided with the distribution. 18 1.1 uch * 19 1.1 uch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 uch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 uch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 uch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 uch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 uch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 uch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 uch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 uch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 uch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 uch * POSSIBILITY OF SUCH DAMAGE. 30 1.1 uch */ 31 1.5 lukem 32 1.5 lukem #include <sys/cdefs.h> 33 1.36 andvar __KERNEL_RCSID(0, "$NetBSD: if_smap.c,v 1.36 2023/11/05 21:50:27 andvar Exp $"); 34 1.1 uch 35 1.1 uch #include "debug_playstation2.h" 36 1.1 uch 37 1.1 uch #include <sys/param.h> 38 1.1 uch #include <sys/systm.h> 39 1.20 martin #include <sys/device.h> 40 1.1 uch #include <sys/syslog.h> 41 1.1 uch #include <sys/mbuf.h> 42 1.1 uch #include <sys/ioctl.h> 43 1.20 martin #include <sys/rndsource.h> 44 1.1 uch #include <sys/socket.h> 45 1.33 thorpej #include <sys/kmem.h> 46 1.1 uch 47 1.1 uch #include <playstation2/ee/eevar.h> 48 1.1 uch 49 1.1 uch #include <net/if.h> 50 1.1 uch #include <net/if_dl.h> 51 1.1 uch #include <net/if_types.h> 52 1.1 uch #include <net/if_ether.h> 53 1.1 uch #include <net/if_media.h> 54 1.25 msaitoh #include <net/bpf.h> 55 1.1 uch 56 1.1 uch #include <dev/mii/miivar.h> 57 1.1 uch 58 1.1 uch #include <netinet/in.h> 59 1.1 uch #include <netinet/in_systm.h> 60 1.1 uch #include <netinet/in_var.h> 61 1.1 uch #include <netinet/ip.h> 62 1.1 uch #include <netinet/if_inarp.h> 63 1.1 uch 64 1.1 uch #include <playstation2/dev/spdvar.h> 65 1.1 uch #include <playstation2/dev/spdreg.h> 66 1.1 uch #include <playstation2/dev/emac3var.h> 67 1.1 uch #include <playstation2/dev/if_smapreg.h> 68 1.1 uch 69 1.1 uch #ifdef SMAP_DEBUG 70 1.1 uch #include <playstation2/ee/gsvar.h> 71 1.1 uch int smap_debug = 0; 72 1.1 uch #define DPRINTF(fmt, args...) \ 73 1.1 uch if (smap_debug) \ 74 1.29 msaitoh printf("%s: " fmt, __func__ , ##args) 75 1.1 uch #define DPRINTFN(n, arg) \ 76 1.1 uch if (smap_debug > (n)) \ 77 1.29 msaitoh printf("%s: " fmt, __func__ , ##args) 78 1.1 uch #define STATIC 79 1.1 uch struct smap_softc *__sc; 80 1.1 uch void __smap_status(int); 81 1.1 uch void __smap_lock_check(const char *, int); 82 1.10 perry #define FUNC_ENTER() __smap_lock_check(__func__, 1) 83 1.10 perry #define FUNC_EXIT() __smap_lock_check(__func__, 0) 84 1.1 uch #else 85 1.1 uch #define DPRINTF(arg...) ((void)0) 86 1.1 uch #define DPRINTFN(n, arg...) ((void)0) 87 1.1 uch #define STATIC static 88 1.1 uch #define FUNC_ENTER() ((void)0) 89 1.1 uch #define FUNC_EXIT() ((void)0) 90 1.1 uch #endif 91 1.1 uch 92 1.1 uch struct smap_softc { 93 1.1 uch struct emac3_softc emac3; 94 1.1 uch struct ethercom ethercom; 95 1.1 uch 96 1.1 uch u_int32_t *tx_buf; 97 1.1 uch u_int32_t *rx_buf; 98 1.1 uch struct smap_desc *tx_desc; 99 1.1 uch struct smap_desc *rx_desc; 100 1.1 uch 101 1.1 uch #define SMAP_FIFO_ALIGN 4 102 1.1 uch int tx_buf_freesize; /* buffer usage */ 103 1.1 uch int tx_desc_cnt; /* descriptor usage */ 104 1.1 uch u_int16_t tx_fifo_ptr; 105 1.1 uch int tx_done_index, tx_start_index; 106 1.1 uch int rx_done_index; 107 1.1 uch 108 1.18 riastrad krndsource_t rnd_source; 109 1.1 uch }; 110 1.1 uch 111 1.34 riastrad #define DEVNAME (device_xname(sc->emac3.dev)) 112 1.1 uch #define ROUND4(x) (((x) + 3) & ~3) 113 1.1 uch #define ROUND16(x) (((x) + 15) & ~15) 114 1.1 uch 115 1.1 uch STATIC int smap_match(struct device *, struct cfdata *, void *); 116 1.1 uch STATIC void smap_attach(struct device *, struct device *, void *); 117 1.1 uch 118 1.20 martin CFATTACH_DECL_NEW(smap, sizeof (struct smap_softc), 119 1.3 thorpej smap_match, smap_attach, NULL, NULL); 120 1.1 uch 121 1.1 uch STATIC int smap_intr(void *); 122 1.1 uch STATIC void smap_rxeof(void *); 123 1.1 uch STATIC void smap_txeof(void *); 124 1.1 uch STATIC void smap_start(struct ifnet *); 125 1.1 uch STATIC void smap_watchdog(struct ifnet *); 126 1.9 christos STATIC int smap_ioctl(struct ifnet *, u_long, void *); 127 1.1 uch STATIC int smap_init(struct ifnet *); 128 1.1 uch STATIC void smap_stop(struct ifnet *, int); 129 1.1 uch 130 1.1 uch STATIC int smap_get_eaddr(struct smap_softc *, u_int8_t *); 131 1.1 uch STATIC int smap_fifo_init(struct smap_softc *); 132 1.1 uch STATIC int smap_fifo_reset(bus_addr_t); 133 1.1 uch STATIC void smap_desc_init(struct smap_softc *); 134 1.1 uch 135 1.1 uch int 136 1.1 uch smap_match(struct device *parent, struct cfdata *cf, void *aux) 137 1.1 uch { 138 1.1 uch struct spd_attach_args *spa = aux; 139 1.1 uch 140 1.1 uch if (spa->spa_slot != SPD_NIC) 141 1.1 uch return (0); 142 1.1 uch 143 1.1 uch return (1); 144 1.1 uch } 145 1.1 uch 146 1.1 uch void 147 1.1 uch smap_attach(struct device *parent, struct device *self, void *aux) 148 1.1 uch { 149 1.1 uch struct spd_attach_args *spa = aux; 150 1.34 riastrad struct smap_softc *sc = device_private(self); 151 1.1 uch struct emac3_softc *emac3 = &sc->emac3; 152 1.1 uch struct ifnet *ifp = &sc->ethercom.ec_if; 153 1.1 uch struct mii_data *mii = &emac3->mii; 154 1.1 uch void *txbuf, *rxbuf; 155 1.1 uch u_int16_t r; 156 1.1 uch 157 1.1 uch #ifdef SMAP_DEBUG 158 1.1 uch __sc = sc; 159 1.1 uch #endif 160 1.1 uch 161 1.35 thorpej sc->emac3.dev = self; 162 1.34 riastrad 163 1.1 uch printf(": %s\n", spa->spa_product_name); 164 1.1 uch 165 1.1 uch /* SPD EEPROM */ 166 1.1 uch if (smap_get_eaddr(sc, emac3->eaddr) != 0) 167 1.1 uch return; 168 1.1 uch 169 1.1 uch printf("%s: Ethernet address %s\n", DEVNAME, 170 1.1 uch ether_sprintf(emac3->eaddr)); 171 1.1 uch 172 1.1 uch /* disable interrupts */ 173 1.1 uch r = _reg_read_2(SPD_INTR_ENABLE_REG16); 174 1.1 uch r &= ~(SPD_INTR_RXEND | SPD_INTR_TXEND | SPD_INTR_RXDNV | 175 1.1 uch SPD_INTR_EMAC3); 176 1.1 uch _reg_write_2(SPD_INTR_ENABLE_REG16, r); 177 1.1 uch emac3_intr_disable(); 178 1.1 uch 179 1.1 uch /* clear pending interrupts */ 180 1.1 uch _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND | SPD_INTR_TXEND | 181 1.1 uch SPD_INTR_RXDNV); 182 1.1 uch emac3_intr_clear(); 183 1.1 uch 184 1.1 uch /* buffer descriptor mode */ 185 1.1 uch _reg_write_1(SMAP_DESC_MODE_REG8, 0); 186 1.1 uch 187 1.1 uch if (smap_fifo_init(sc) != 0) 188 1.1 uch return; 189 1.1 uch 190 1.1 uch if (emac3_init(&sc->emac3) != 0) 191 1.1 uch return; 192 1.1 uch emac3_intr_disable(); 193 1.1 uch emac3_disable(); 194 1.1 uch 195 1.1 uch smap_desc_init(sc); 196 1.1 uch 197 1.1 uch /* allocate temporary buffer */ 198 1.33 thorpej txbuf = kmem_alloc(ETHER_MAX_LEN - ETHER_CRC_LEN + SMAP_FIFO_ALIGN + 16, 199 1.33 thorpej KM_SLEEP); 200 1.33 thorpej rxbuf = kmem_alloc(ETHER_MAX_LEN + SMAP_FIFO_ALIGN + 16, KM_SLEEP); 201 1.1 uch sc->tx_buf = (u_int32_t *)ROUND16((vaddr_t)txbuf); 202 1.1 uch sc->rx_buf = (u_int32_t *)ROUND16((vaddr_t)rxbuf); 203 1.1 uch 204 1.29 msaitoh /* 205 1.29 msaitoh * setup MI layer 206 1.1 uch */ 207 1.1 uch strcpy(ifp->if_xname, DEVNAME); 208 1.1 uch ifp->if_softc = sc; 209 1.1 uch ifp->if_start = smap_start; 210 1.1 uch ifp->if_ioctl = smap_ioctl; 211 1.1 uch ifp->if_init = smap_init; 212 1.1 uch ifp->if_stop = smap_stop; 213 1.1 uch ifp->if_watchdog= smap_watchdog; 214 1.28 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 215 1.1 uch IFQ_SET_READY(&ifp->if_snd); 216 1.1 uch 217 1.1 uch /* ifmedia setup. */ 218 1.1 uch mii->mii_ifp = ifp; 219 1.1 uch mii->mii_readreg = emac3_phy_readreg; 220 1.1 uch mii->mii_writereg = emac3_phy_writereg; 221 1.1 uch mii->mii_statchg = emac3_phy_statchg; 222 1.11 dyoung sc->ethercom.ec_mii = mii; 223 1.11 dyoung ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); 224 1.34 riastrad mii_attach(emac3->dev, mii, 0xffffffff, MII_PHY_ANY, 225 1.1 uch MII_OFFSET_ANY, 0); 226 1.29 msaitoh 227 1.1 uch /* Choose a default media. */ 228 1.1 uch if (LIST_FIRST(&mii->mii_phys) == NULL) { 229 1.30 msaitoh ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); 230 1.30 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); 231 1.1 uch } else { 232 1.30 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 233 1.1 uch } 234 1.1 uch 235 1.1 uch if_attach(ifp); 236 1.22 ozaki if_deferred_start_init(ifp, NULL); 237 1.1 uch ether_ifattach(ifp, emac3->eaddr); 238 1.29 msaitoh 239 1.1 uch spd_intr_establish(SPD_NIC, smap_intr, sc); 240 1.1 uch 241 1.1 uch rnd_attach_source(&sc->rnd_source, DEVNAME, 242 1.17 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 243 1.1 uch } 244 1.1 uch 245 1.1 uch int 246 1.9 christos smap_ioctl(struct ifnet *ifp, u_long command, void *data) 247 1.1 uch { 248 1.1 uch struct smap_softc *sc = ifp->if_softc; 249 1.1 uch int error, s; 250 1.1 uch 251 1.1 uch s = splnet(); 252 1.1 uch 253 1.11 dyoung error = ether_ioctl(ifp, command, data); 254 1.11 dyoung 255 1.11 dyoung if (error == ENETRESET) { 256 1.11 dyoung if (ifp->if_flags & IFF_RUNNING) 257 1.11 dyoung emac3_setmulti(&sc->emac3, &sc->ethercom); 258 1.11 dyoung error = 0; 259 1.1 uch } 260 1.1 uch 261 1.1 uch splx(s); 262 1.1 uch 263 1.1 uch return (error); 264 1.1 uch } 265 1.1 uch 266 1.1 uch int 267 1.1 uch smap_intr(void *arg) 268 1.1 uch { 269 1.1 uch struct smap_softc *sc = arg; 270 1.1 uch struct ifnet *ifp; 271 1.1 uch u_int16_t cause, disable, r; 272 1.1 uch 273 1.1 uch cause = _reg_read_2(SPD_INTR_STATUS_REG16) & 274 1.1 uch _reg_read_2(SPD_INTR_ENABLE_REG16); 275 1.1 uch 276 1.1 uch disable = cause & (SPD_INTR_RXDNV | SPD_INTR_TXDNV); 277 1.1 uch if (disable) { 278 1.1 uch r = _reg_read_2(SPD_INTR_ENABLE_REG16); 279 1.1 uch r &= ~disable; 280 1.1 uch _reg_write_2(SPD_INTR_ENABLE_REG16, r); 281 1.1 uch 282 1.1 uch printf("%s: invalid descriptor. (%c%c)\n", DEVNAME, 283 1.1 uch disable & SPD_INTR_RXDNV ? 'R' : '_', 284 1.1 uch disable & SPD_INTR_TXDNV ? 'T' : '_'); 285 1.1 uch 286 1.1 uch if (disable & SPD_INTR_RXDNV) 287 1.1 uch smap_rxeof(arg); 288 1.1 uch 289 1.1 uch _reg_write_2(SPD_INTR_CLEAR_REG16, disable); 290 1.1 uch } 291 1.1 uch 292 1.1 uch if (cause & SPD_INTR_TXEND) { 293 1.1 uch _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_TXEND); 294 1.1 uch if (_reg_read_1(SMAP_RXFIFO_FRAME_REG8) > 0) 295 1.1 uch cause |= SPD_INTR_RXEND; 296 1.1 uch smap_txeof(arg); 297 1.1 uch } 298 1.1 uch 299 1.1 uch if (cause & SPD_INTR_RXEND) { 300 1.1 uch _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND); 301 1.1 uch smap_rxeof(arg); 302 1.1 uch if (sc->tx_desc_cnt > 0 && 303 1.1 uch sc->tx_desc_cnt > _reg_read_1(SMAP_TXFIFO_FRAME_REG8)) 304 1.1 uch smap_txeof(arg); 305 1.1 uch } 306 1.1 uch 307 1.1 uch if (cause & SPD_INTR_EMAC3) 308 1.1 uch emac3_intr(arg); 309 1.29 msaitoh 310 1.4 wiz /* if transmission is pending, start here */ 311 1.1 uch ifp = &sc->ethercom.ec_if; 312 1.22 ozaki if_schedule_deferred_start(ifp); 313 1.1 uch rnd_add_uint32(&sc->rnd_source, cause | sc->tx_fifo_ptr << 16); 314 1.1 uch 315 1.1 uch return (1); 316 1.1 uch } 317 1.1 uch 318 1.1 uch void 319 1.1 uch smap_rxeof(void *arg) 320 1.1 uch { 321 1.1 uch struct smap_softc *sc = arg; 322 1.1 uch struct smap_desc *d; 323 1.1 uch struct ifnet *ifp = &sc->ethercom.ec_if; 324 1.1 uch struct mbuf *m; 325 1.1 uch u_int16_t r16, stat; 326 1.1 uch u_int32_t *p; 327 1.1 uch int i, j, sz, rxsz, cnt; 328 1.1 uch 329 1.1 uch FUNC_ENTER(); 330 1.1 uch 331 1.1 uch i = sc->rx_done_index; 332 1.1 uch 333 1.1 uch for (cnt = 0;; cnt++, i = (i + 1) & 0x3f) { 334 1.1 uch m = NULL; 335 1.1 uch d = &sc->rx_desc[i]; 336 1.1 uch stat = d->stat; 337 1.1 uch 338 1.1 uch if ((stat & SMAP_RXDESC_EMPTY) != 0) { 339 1.1 uch break; 340 1.1 uch } else if (stat & 0x7fff) { 341 1.32 thorpej if_statinc(ifp, if_ierrors); 342 1.1 uch goto next_packet; 343 1.1 uch } 344 1.1 uch 345 1.1 uch sz = d->sz; 346 1.1 uch rxsz = ROUND4(sz); 347 1.1 uch 348 1.1 uch KDASSERT(sz >= ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN); 349 1.1 uch KDASSERT(sz <= ETHER_MAX_LEN); 350 1.1 uch 351 1.1 uch /* load data from FIFO */ 352 1.1 uch _reg_write_2(SMAP_RXFIFO_PTR_REG16, d->ptr & 0x3ffc); 353 1.1 uch p = sc->rx_buf; 354 1.1 uch for (j = 0; j < rxsz; j += sizeof(u_int32_t)) { 355 1.1 uch *p++ = _reg_read_4(SMAP_RXFIFO_DATA_REG); 356 1.1 uch } 357 1.1 uch 358 1.1 uch /* put to mbuf */ 359 1.1 uch MGETHDR(m, M_DONTWAIT, MT_DATA); 360 1.1 uch if (m == NULL) { 361 1.1 uch printf("%s: unable to allocate Rx mbuf\n", DEVNAME); 362 1.32 thorpej if_statinc(ifp, if_ierrors); 363 1.1 uch goto next_packet; 364 1.1 uch } 365 1.1 uch 366 1.1 uch if (sz > (MHLEN - 2)) { 367 1.1 uch MCLGET(m, M_DONTWAIT); 368 1.1 uch if ((m->m_flags & M_EXT) == 0) { 369 1.1 uch printf("%s: unable to allocate Rx cluster\n", 370 1.1 uch DEVNAME); 371 1.1 uch m_freem(m); 372 1.1 uch m = NULL; 373 1.32 thorpej if_statinc(ifp, if_ierrors); 374 1.1 uch goto next_packet; 375 1.1 uch } 376 1.1 uch } 377 1.1 uch 378 1.1 uch m->m_data += 2; /* for alignment */ 379 1.21 ozaki m_set_rcvif(m, ifp); 380 1.1 uch m->m_pkthdr.len = m->m_len = sz; 381 1.9 christos memcpy(mtod(m, void *), (void *)sc->rx_buf, sz); 382 1.1 uch 383 1.1 uch next_packet: 384 1.1 uch _reg_write_1(SMAP_RXFIFO_FRAME_DEC_REG8, 1); 385 1.1 uch 386 1.1 uch /* free descriptor */ 387 1.1 uch d->sz = 0; 388 1.1 uch d->ptr = 0; 389 1.1 uch d->stat = SMAP_RXDESC_EMPTY; 390 1.1 uch _wbflush(); 391 1.29 msaitoh 392 1.23 ozaki if (m != NULL) 393 1.19 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 394 1.1 uch } 395 1.1 uch sc->rx_done_index = i; 396 1.1 uch 397 1.1 uch r16 = _reg_read_2(SPD_INTR_ENABLE_REG16); 398 1.1 uch if (((r16 & SPD_INTR_RXDNV) == 0) && cnt > 0) { 399 1.1 uch r16 |= SPD_INTR_RXDNV; 400 1.1 uch _reg_write_2(SPD_INTR_ENABLE_REG16, r16); 401 1.1 uch } 402 1.1 uch 403 1.1 uch FUNC_EXIT(); 404 1.1 uch } 405 1.1 uch 406 1.1 uch void 407 1.1 uch smap_txeof(void *arg) 408 1.1 uch { 409 1.1 uch struct smap_softc *sc = arg; 410 1.1 uch struct ifnet *ifp = &sc->ethercom.ec_if; 411 1.1 uch struct smap_desc *d; 412 1.1 uch int i; 413 1.1 uch 414 1.1 uch FUNC_ENTER(); 415 1.1 uch 416 1.1 uch /* clear the timeout timer. */ 417 1.1 uch ifp->if_timer = 0; 418 1.1 uch 419 1.1 uch /* garbage collect */ 420 1.1 uch for (i = sc->tx_done_index;; i = (i + 1) & 0x3f) { 421 1.1 uch u_int16_t stat; 422 1.1 uch 423 1.1 uch d = &sc->tx_desc[i]; 424 1.1 uch stat = d->stat; 425 1.1 uch if (stat & SMAP_TXDESC_READY) { 426 1.1 uch /* all descriptor processed. */ 427 1.1 uch break; 428 1.1 uch } else if (stat & 0x7fff) { 429 1.1 uch if (stat & (SMAP_TXDESC_ECOLL | SMAP_TXDESC_LCOLL | 430 1.1 uch SMAP_TXDESC_MCOLL | SMAP_TXDESC_SCOLL)) 431 1.32 thorpej if_statinc(ifp, if_collisions); 432 1.1 uch else 433 1.32 thorpej if_statinc(ifp, if_oerrors); 434 1.1 uch } else { 435 1.32 thorpej if_statinc(ifp, if_opackets); 436 1.1 uch } 437 1.1 uch 438 1.1 uch if (sc->tx_desc_cnt == 0) 439 1.1 uch break; 440 1.29 msaitoh 441 1.1 uch sc->tx_buf_freesize += ROUND4(d->sz); 442 1.1 uch sc->tx_desc_cnt--; 443 1.1 uch 444 1.1 uch d->sz = 0; 445 1.1 uch d->ptr = 0; 446 1.1 uch d->stat = 0; 447 1.1 uch _wbflush(); 448 1.1 uch } 449 1.1 uch sc->tx_done_index = i; 450 1.1 uch 451 1.1 uch FUNC_EXIT(); 452 1.1 uch } 453 1.1 uch 454 1.1 uch void 455 1.1 uch smap_start(struct ifnet *ifp) 456 1.1 uch { 457 1.1 uch struct smap_softc *sc = ifp->if_softc; 458 1.1 uch struct smap_desc *d; 459 1.1 uch struct mbuf *m0, *m; 460 1.1 uch u_int8_t *p, *q; 461 1.1 uch u_int32_t *r; 462 1.1 uch int i, sz, pktsz; 463 1.1 uch u_int16_t fifop; 464 1.1 uch u_int16_t r16; 465 1.1 uch 466 1.1 uch KDASSERT(ifp->if_flags & IFF_RUNNING); 467 1.1 uch FUNC_ENTER(); 468 1.1 uch 469 1.1 uch while (1) { 470 1.1 uch IFQ_POLL(&ifp->if_snd, m0); 471 1.1 uch if (m0 == NULL) 472 1.1 uch goto end; 473 1.1 uch 474 1.1 uch pktsz = m0->m_pkthdr.len; 475 1.1 uch KDASSERT(pktsz <= ETHER_MAX_LEN - ETHER_CRC_LEN); 476 1.1 uch sz = ROUND4(pktsz); 477 1.1 uch 478 1.1 uch if (sz > sc->tx_buf_freesize || 479 1.1 uch sc->tx_desc_cnt >= SMAP_DESC_MAX || 480 1.1 uch emac3_tx_done() != 0) { 481 1.1 uch goto end; 482 1.1 uch } 483 1.1 uch 484 1.1 uch IFQ_DEQUEUE(&ifp->if_snd, m0); 485 1.1 uch KDASSERT(m0 != NULL); 486 1.27 msaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 487 1.1 uch 488 1.1 uch p = (u_int8_t *)sc->tx_buf; 489 1.1 uch q = p + sz; 490 1.1 uch /* copy to temporary buffer area */ 491 1.1 uch for (m = m0; m != 0; m = m->m_next) { 492 1.9 christos memcpy(p, mtod(m, void *), m->m_len); 493 1.1 uch p += m->m_len; 494 1.1 uch } 495 1.1 uch m_freem(m0); 496 1.1 uch 497 1.1 uch /* zero padding area */ 498 1.1 uch for (; p < q; p++) 499 1.1 uch *p = 0; 500 1.1 uch 501 1.1 uch /* put to FIFO */ 502 1.1 uch fifop = sc->tx_fifo_ptr; 503 1.1 uch KDASSERT((fifop & 3) == 0); 504 1.1 uch _reg_write_2(SMAP_TXFIFO_PTR_REG16, fifop); 505 1.1 uch sc->tx_fifo_ptr = (fifop + sz) & 0xfff; 506 1.1 uch 507 1.1 uch r = sc->tx_buf; 508 1.1 uch for (i = 0; i < sz; i += sizeof(u_int32_t)) 509 1.8 perry *(volatile u_int32_t *)SMAP_TXFIFO_DATA_REG = *r++; 510 1.1 uch _wbflush(); 511 1.1 uch 512 1.1 uch /* put FIFO to EMAC3 */ 513 1.1 uch d = &sc->tx_desc[sc->tx_start_index]; 514 1.1 uch KDASSERT((d->stat & SMAP_TXDESC_READY) == 0); 515 1.1 uch 516 1.1 uch d->sz = pktsz; 517 1.1 uch d->ptr = fifop + SMAP_TXBUF_BASE; 518 1.1 uch d->stat = SMAP_TXDESC_READY | SMAP_TXDESC_GENFCS | 519 1.1 uch SMAP_TXDESC_GENPAD; 520 1.1 uch _wbflush(); 521 1.1 uch 522 1.1 uch sc->tx_buf_freesize -= sz; 523 1.1 uch sc->tx_desc_cnt++; 524 1.1 uch sc->tx_start_index = (sc->tx_start_index + 1) & 0x3f; 525 1.1 uch _reg_write_1(SMAP_TXFIFO_FRAME_INC_REG8, 1); 526 1.1 uch 527 1.1 uch emac3_tx_kick(); 528 1.1 uch r16 = _reg_read_2(SPD_INTR_ENABLE_REG16); 529 1.1 uch if ((r16 & SPD_INTR_TXDNV) == 0) { 530 1.1 uch r16 |= SPD_INTR_TXDNV; 531 1.1 uch _reg_write_2(SPD_INTR_ENABLE_REG16, r16); 532 1.1 uch } 533 1.1 uch } 534 1.1 uch end: 535 1.1 uch /* set watchdog timer */ 536 1.1 uch ifp->if_timer = 5; 537 1.1 uch 538 1.1 uch FUNC_EXIT(); 539 1.1 uch } 540 1.1 uch 541 1.1 uch void 542 1.1 uch smap_watchdog(struct ifnet *ifp) 543 1.1 uch { 544 1.1 uch struct smap_softc *sc = ifp->if_softc; 545 1.1 uch 546 1.29 msaitoh printf("%s: watchdog timeout\n", DEVNAME); 547 1.32 thorpej if_statinc(ifp, if_oerrors); 548 1.1 uch 549 1.1 uch smap_fifo_init(sc); 550 1.1 uch smap_desc_init(sc); 551 1.1 uch emac3_reset(&sc->emac3); 552 1.1 uch } 553 1.1 uch 554 1.1 uch int 555 1.1 uch smap_init(struct ifnet *ifp) 556 1.1 uch { 557 1.1 uch struct smap_softc *sc = ifp->if_softc; 558 1.1 uch u_int16_t r16; 559 1.11 dyoung int rc; 560 1.1 uch 561 1.1 uch smap_fifo_init(sc); 562 1.1 uch emac3_reset(&sc->emac3); 563 1.1 uch smap_desc_init(sc); 564 1.1 uch 565 1.1 uch _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND | SPD_INTR_TXEND | 566 1.1 uch SPD_INTR_RXDNV); 567 1.1 uch emac3_intr_clear(); 568 1.1 uch 569 1.1 uch r16 = _reg_read_2(SPD_INTR_ENABLE_REG16); 570 1.1 uch r16 |= SPD_INTR_EMAC3 | SPD_INTR_RXEND | SPD_INTR_TXEND | 571 1.1 uch SPD_INTR_RXDNV; 572 1.1 uch _reg_write_2(SPD_INTR_ENABLE_REG16, r16); 573 1.1 uch emac3_intr_enable(); 574 1.1 uch 575 1.1 uch emac3_enable(); 576 1.1 uch 577 1.1 uch /* Program the multicast filter, if necessary. */ 578 1.1 uch emac3_setmulti(&sc->emac3, &sc->ethercom); 579 1.1 uch 580 1.1 uch /* Set current media. */ 581 1.11 dyoung if ((rc = mii_mediachg(&sc->emac3.mii)) == ENXIO) 582 1.11 dyoung rc = 0; 583 1.11 dyoung else if (rc != 0) 584 1.11 dyoung return rc; 585 1.1 uch 586 1.1 uch ifp->if_flags |= IFF_RUNNING; 587 1.1 uch 588 1.29 msaitoh return (0); 589 1.1 uch } 590 1.1 uch 591 1.1 uch void 592 1.1 uch smap_stop(struct ifnet *ifp, int disable) 593 1.1 uch { 594 1.1 uch struct smap_softc *sc = ifp->if_softc; 595 1.1 uch 596 1.1 uch mii_down(&sc->emac3.mii); 597 1.1 uch 598 1.35 thorpej ifp->if_flags &= ~IFF_RUNNING; 599 1.12 dyoung 600 1.1 uch if (disable) 601 1.1 uch emac3_disable(); 602 1.1 uch } 603 1.1 uch 604 1.1 uch /* 605 1.1 uch * FIFO 606 1.1 uch */ 607 1.1 uch int 608 1.1 uch smap_fifo_init(struct smap_softc *sc) 609 1.1 uch { 610 1.1 uch 611 1.1 uch if (smap_fifo_reset(SMAP_TXFIFO_CTRL_REG8) != 0) 612 1.1 uch goto error; 613 1.1 uch 614 1.1 uch if (smap_fifo_reset(SMAP_RXFIFO_CTRL_REG8) != 0) 615 1.1 uch goto error; 616 1.1 uch 617 1.1 uch return (0); 618 1.1 uch error: 619 1.1 uch printf("%s: FIFO reset not complete.\n", DEVNAME); 620 1.1 uch 621 1.1 uch return (1); 622 1.1 uch } 623 1.1 uch 624 1.1 uch int 625 1.1 uch smap_fifo_reset(bus_addr_t a) 626 1.1 uch { 627 1.1 uch int retry = 10000; 628 1.1 uch 629 1.1 uch _reg_write_1(a, SMAP_FIFO_RESET); 630 1.1 uch 631 1.1 uch while ((_reg_read_1(a) & SMAP_FIFO_RESET) && --retry > 0) 632 1.1 uch ; 633 1.1 uch 634 1.1 uch return (retry == 0); 635 1.1 uch } 636 1.1 uch 637 1.1 uch /* 638 1.1 uch * Buffer descriptor 639 1.1 uch */ 640 1.1 uch void 641 1.1 uch smap_desc_init(struct smap_softc *sc) 642 1.1 uch { 643 1.1 uch struct smap_desc *d; 644 1.1 uch int i; 645 1.1 uch 646 1.1 uch sc->tx_desc = (void *)SMAP_TXDESC_BASE; 647 1.1 uch sc->rx_desc = (void *)SMAP_RXDESC_BASE; 648 1.29 msaitoh 649 1.1 uch sc->tx_buf_freesize = SMAP_TXBUF_SIZE; 650 1.1 uch sc->tx_fifo_ptr = 0; 651 1.1 uch sc->tx_start_index = 0; 652 1.1 uch sc->tx_done_index = 0; 653 1.1 uch sc->rx_done_index = 0; 654 1.1 uch 655 1.24 dholland /* initialize entry */ 656 1.1 uch d = sc->tx_desc; 657 1.1 uch for (i = 0; i < SMAP_DESC_MAX; i++, d++) { 658 1.1 uch d->stat = 0; 659 1.1 uch d->__reserved = 0; 660 1.1 uch d->sz = 0; 661 1.1 uch d->ptr = 0; 662 1.1 uch } 663 1.29 msaitoh 664 1.1 uch d = sc->rx_desc; 665 1.1 uch for (i = 0; i < SMAP_DESC_MAX; i++, d++) { 666 1.1 uch d->stat = SMAP_RXDESC_EMPTY; 667 1.1 uch d->__reserved = 0; 668 1.1 uch d->sz = 0; 669 1.1 uch d->ptr = 0; 670 1.1 uch } 671 1.1 uch _wbflush(); 672 1.1 uch } 673 1.1 uch 674 1.1 uch 675 1.1 uch /* 676 1.1 uch * EEPROM 677 1.1 uch */ 678 1.1 uch int 679 1.1 uch smap_get_eaddr(struct smap_softc *sc, u_int8_t *eaddr) 680 1.1 uch { 681 1.1 uch u_int16_t checksum, *p = (u_int16_t *)eaddr; 682 1.1 uch 683 1.1 uch spd_eeprom_read(0, p, 3); 684 1.1 uch spd_eeprom_read(3, &checksum, 1); 685 1.1 uch 686 1.1 uch if (checksum != (u_int16_t)(p[0] + p[1] + p[2])) { 687 1.1 uch printf("%s: Ethernet address checksum error.(%s)\n", 688 1.1 uch DEVNAME, ether_sprintf(eaddr)); 689 1.1 uch return (1); 690 1.1 uch } 691 1.1 uch 692 1.1 uch return (0); 693 1.1 uch } 694 1.1 uch 695 1.1 uch #ifdef SMAP_DEBUG 696 1.1 uch #include <mips/locore.h> 697 1.1 uch void 698 1.1 uch __smap_lock_check(const char *func, int enter) 699 1.1 uch { 700 1.1 uch static int cnt; 701 1.1 uch static const char *last; 702 1.1 uch 703 1.1 uch cnt += enter ? 1 : -1; 704 1.1 uch 705 1.1 uch if (cnt < 0 || cnt > 1) 706 1.1 uch panic("%s cnt=%d last=%s", func, cnt, last); 707 1.1 uch 708 1.1 uch last = func; 709 1.1 uch } 710 1.1 uch 711 1.1 uch void 712 1.1 uch __smap_status(int msg) 713 1.1 uch { 714 1.1 uch static int cnt; 715 1.36 andvar DPRINTF("%d: tx=%d rx=%d txcnt=%d free=%d cnt=%d\n", msg, 716 1.1 uch _reg_read_1(SMAP_TXFIFO_FRAME_REG8), 717 1.1 uch _reg_read_1(SMAP_RXFIFO_FRAME_REG8), __sc->tx_desc_cnt, 718 1.1 uch __sc->tx_buf_freesize, cnt++); 719 1.1 uch } 720 1.1 uch #endif /* SMAP_DEBUG */ 721