1 /* $NetBSD: if_mc_obio.c,v 1.19 2021/01/24 05:20:23 rin Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 David Huang <khym@azeotrope.org> 5 * All rights reserved. 6 * 7 * Portions of this code are based on code by Denton Gentry <denny1@home.com> 8 * and Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 */ 30 31 /* 32 * Bus attachment and DMA routines for the mc driver (Centris/Quadra 33 * 660av and Quadra 840av onboard ethernet, based on the AMD Am79C940 34 * MACE ethernet chip). Also uses the PSC (Peripheral Subsystem 35 * Controller) for DMA to and from the MACE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: if_mc_obio.c,v 1.19 2021/01/24 05:20:23 rin Exp $"); 40 41 #include "opt_ddb.h" 42 43 #include <sys/param.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/socket.h> 47 #include <sys/systm.h> 48 49 #include <sys/rndsource.h> 50 51 #include <net/if.h> 52 #include <net/if_ether.h> 53 54 #include <uvm/uvm_extern.h> 55 56 #include <machine/bus.h> 57 #include <machine/psc.h> 58 59 #include <mac68k/obio/obiovar.h> 60 #include <mac68k/dev/if_mcreg.h> 61 #include <mac68k/dev/if_mcvar.h> 62 63 #define MACE_REG_BASE 0x50F1C000 64 #define MACE_PROM_BASE 0x50F08000 65 66 hide int mc_obio_match(device_t, cfdata_t, void *); 67 hide void mc_obio_attach(device_t, device_t, void *); 68 hide void mc_obio_init(struct mc_softc *); 69 hide void mc_obio_put(struct mc_softc *, u_int); 70 hide int mc_dmaintr(void *); 71 hide void mc_reset_rxdma(struct mc_softc *); 72 hide void mc_reset_rxdma_set(struct mc_softc *, int); 73 hide void mc_reset_txdma(struct mc_softc *); 74 hide int mc_obio_getaddr(struct mc_softc *, u_int8_t *); 75 76 CFATTACH_DECL_NEW(mc_obio, sizeof(struct mc_softc), 77 mc_obio_match, mc_obio_attach, NULL, NULL); 78 79 hide int 80 mc_obio_match(device_t parent, cfdata_t cf, void *aux) 81 { 82 struct obio_attach_args *oa = aux; 83 bus_space_handle_t bsh; 84 int found = 0; 85 86 if (current_mac_model->class != MACH_CLASSAV) 87 return 0; 88 89 if (bus_space_map(oa->oa_tag, MACE_REG_BASE, MC_REGSIZE, 0, &bsh)) 90 return 0; 91 92 /* 93 * Make sure the MACE's I/O space is readable, and if it is, 94 * try to read the CHIPID register. A MACE will always have 95 * 0x?940, where the ? depends on the chip version. 96 */ 97 if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0, 1)) { 98 if ((bus_space_read_1( 99 oa->oa_tag, bsh, MACE_REG(MACE_CHIPIDL)) == 0x40) && 100 ((bus_space_read_1( 101 oa->oa_tag, bsh, MACE_REG(MACE_CHIPIDH)) & 0xf) == 9)) 102 found = 1; 103 } 104 105 bus_space_unmap(oa->oa_tag, bsh, MC_REGSIZE); 106 107 return found; 108 } 109 110 hide void 111 mc_obio_attach(device_t parent, device_t self, void *aux) 112 { 113 struct obio_attach_args *oa = (struct obio_attach_args *)aux; 114 struct mc_softc *sc = device_private(self); 115 u_int8_t myaddr[ETHER_ADDR_LEN]; 116 int rsegs; 117 118 sc->sc_dev = self; 119 sc->sc_regt = oa->oa_tag; 120 sc->sc_biucc = XMTSP_64; 121 sc->sc_fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | 122 XMTBRST | RCVBRST; 123 sc->sc_plscc = PORTSEL_AUI; 124 125 if (bus_space_map(sc->sc_regt, MACE_REG_BASE, MC_REGSIZE, 0, 126 &sc->sc_regh)) { 127 printf(": failed to map space for MACE regs.\n"); 128 return; 129 } 130 131 if (mc_obio_getaddr(sc, myaddr)) { 132 printf(": failed to get MAC address.\n"); 133 return; 134 } 135 136 /* allocate memory for transmit and receive DMA buffers */ 137 sc->sc_dmat = oa->oa_dmat; 138 if (bus_dmamem_alloc(sc->sc_dmat, 2 * 0x800, 0, 0, &sc->sc_dmasegs_tx, 139 1, &rsegs, BUS_DMA_NOWAIT) != 0) { 140 printf(": failed to allocate TX DMA buffers.\n"); 141 return; 142 } 143 144 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dmasegs_tx, rsegs, 2 * 0x800, 145 (void*)&sc->sc_txbuf, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) { 146 printf(": failed to map TX DMA buffers.\n"); 147 return; 148 } 149 150 if (bus_dmamem_alloc(sc->sc_dmat, MC_RXDMABUFS * 0x800, 0, 0, 151 &sc->sc_dmasegs_rx, 1, &rsegs, BUS_DMA_NOWAIT) != 0) { 152 printf(": failed to allocate RX DMA buffers.\n"); 153 return; 154 } 155 156 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dmasegs_rx, rsegs, 157 MC_RXDMABUFS * 0x800, (void*)&sc->sc_rxbuf, 158 BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) { 159 printf(": failed to map RX DMA buffers.\n"); 160 return; 161 } 162 163 if (bus_dmamap_create(sc->sc_dmat, 2 * 0x800, 1, 2 * 0x800, 0, 164 BUS_DMA_NOWAIT, &sc->sc_dmam_tx) != 0) { 165 printf(": failed to allocate TX DMA map.\n"); 166 return; 167 } 168 169 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam_tx, sc->sc_txbuf, 170 2 * 0x800, NULL, BUS_DMA_NOWAIT) != 0) { 171 printf(": failed to map TX DMA mapping.\n"); 172 return; 173 } 174 175 if (bus_dmamap_create(sc->sc_dmat, MC_RXDMABUFS * 0x800, 1, 176 MC_RXDMABUFS * 0x800, 0, BUS_DMA_NOWAIT, &sc->sc_dmam_rx) != 0) { 177 printf(": failed to allocate RX DMA map.\n"); 178 return; 179 } 180 181 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam_rx, sc->sc_rxbuf, 182 MC_RXDMABUFS * 0x800, NULL, BUS_DMA_NOWAIT) != 0) { 183 printf(": failed to map RX DMA mapping.\n"); 184 return; 185 } 186 187 sc->sc_txbuf_phys = sc->sc_dmasegs_tx.ds_addr; 188 sc->sc_rxbuf_phys = sc->sc_dmasegs_rx.ds_addr; 189 190 sc->sc_bus_init = mc_obio_init; 191 sc->sc_putpacket = mc_obio_put; 192 193 /* disable receive DMA */ 194 psc_reg2(PSC_ENETRD_CTL) = 0x8800; 195 psc_reg2(PSC_ENETRD_CTL) = 0x1000; 196 psc_reg2(PSC_ENETRD_CMD + PSC_SET0) = 0x1100; 197 psc_reg2(PSC_ENETRD_CMD + PSC_SET1) = 0x1100; 198 199 /* disable transmit DMA */ 200 psc_reg2(PSC_ENETWR_CTL) = 0x8800; 201 psc_reg2(PSC_ENETWR_CTL) = 0x1000; 202 psc_reg2(PSC_ENETWR_CMD + PSC_SET0) = 0x1100; 203 psc_reg2(PSC_ENETWR_CMD + PSC_SET1) = 0x1100; 204 205 /* install interrupt handlers */ 206 add_psc_lev4_intr(PSCINTR_ENET_DMA, mc_dmaintr, sc); 207 add_psc_lev3_intr(mcintr, sc); 208 209 /* enable MACE DMA interrupts */ 210 psc_reg1(PSC_LEV4_IER) = 0x80 | (1 << PSCINTR_ENET_DMA); 211 212 /* don't know what this does */ 213 psc_reg2(PSC_ENETWR_CTL) = 0x9000; 214 psc_reg2(PSC_ENETRD_CTL) = 0x9000; 215 psc_reg2(PSC_ENETWR_CTL) = 0x0400; 216 psc_reg2(PSC_ENETRD_CTL) = 0x0400; 217 218 /* enable MACE interrupts */ 219 psc_reg1(PSC_LEV3_IER) = 0x80 | (1 << PSCINTR_ENET); 220 221 /* mcsetup returns 1 if something fails */ 222 if (mcsetup(sc, myaddr)) { 223 /* disable interrupts */ 224 psc_reg1(PSC_LEV4_IER) = (1 << PSCINTR_ENET_DMA); 225 psc_reg1(PSC_LEV3_IER) = (1 << PSCINTR_ENET); 226 /* remove interrupt handlers */ 227 remove_psc_lev4_intr(PSCINTR_ENET_DMA); 228 remove_psc_lev3_intr(); 229 230 bus_space_unmap(sc->sc_regt, sc->sc_regh, MC_REGSIZE); 231 return; 232 } 233 } 234 235 /* Bus-specific initialization */ 236 hide void 237 mc_obio_init(struct mc_softc *sc) 238 { 239 mc_reset_rxdma(sc); 240 mc_reset_txdma(sc); 241 } 242 243 hide void 244 mc_obio_put(struct mc_softc *sc, u_int len) 245 { 246 int offset = sc->sc_txset == 0 ? 0 : 0x800; 247 248 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_tx, offset, 0x800, 249 BUS_DMASYNC_PREWRITE); 250 psc_reg4(PSC_ENETWR_ADDR + sc->sc_txset) = sc->sc_txbuf_phys + offset; 251 psc_reg4(PSC_ENETWR_LEN + sc->sc_txset) = len; 252 psc_reg2(PSC_ENETWR_CMD + sc->sc_txset) = 0x9800; 253 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_tx, offset, 0x800, 254 BUS_DMASYNC_POSTWRITE); 255 256 sc->sc_txset ^= 0x10; 257 } 258 259 /* 260 * Interrupt handler for the MACE DMA completion interrupts 261 */ 262 int 263 mc_dmaintr(void *arg) 264 { 265 struct mc_softc *sc = arg; 266 u_int16_t status; 267 u_int32_t bufsleft, which; 268 int head; 269 270 /* 271 * Not sure what this does... figure out if this interrupt is 272 * really ours? 273 */ 274 while ((which = psc_reg4(0x804)) != psc_reg4(0x804)) 275 ; 276 if ((which & 0x60000000) == 0) 277 return 0; 278 279 /* Get the read channel status */ 280 status = psc_reg2(PSC_ENETRD_CTL); 281 if (status & 0x2000) { 282 /* I think this is an exceptional condition. Reset the DMA */ 283 mc_reset_rxdma(sc); 284 #ifdef MCDEBUG 285 printf("%s: resetting receive DMA channel (status 0x%04x)\n", 286 device_xname(sc->sc_dev), status); 287 #endif 288 } else if (status & 0x100) { 289 /* We've received some packets from the MACE */ 290 int offset; 291 292 /* Clear the interrupt */ 293 psc_reg2(PSC_ENETRD_CMD + sc->sc_rxset) = 0x1100; 294 295 /* See how may receive buffers are left */ 296 bufsleft = psc_reg4(PSC_ENETRD_LEN + sc->sc_rxset); 297 head = MC_RXDMABUFS - bufsleft; 298 299 #if 0 /* I don't think this should ever happen */ 300 if (head == sc->sc_tail) { 301 #ifdef MCDEBUG 302 printf("%s: head == tail: suspending DMA?\n", 303 device_xname(sc->sc_dev)); 304 #endif 305 psc_reg2(PSC_ENETRD_CMD + sc->sc_rxset) = 0x9000; 306 } 307 #endif 308 309 /* Loop through, processing each of the packets */ 310 for (; sc->sc_tail < head; sc->sc_tail++) { 311 offset = sc->sc_tail * 0x800; 312 313 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_rx, 314 PAGE_SIZE + offset, 0x800, 315 BUS_DMASYNC_PREREAD); 316 317 sc->sc_rxframe.rx_rcvcnt = sc->sc_rxbuf[offset]; 318 sc->sc_rxframe.rx_rcvsts = sc->sc_rxbuf[offset+2]; 319 sc->sc_rxframe.rx_rntpc = sc->sc_rxbuf[offset+4]; 320 sc->sc_rxframe.rx_rcvcc = sc->sc_rxbuf[offset+6]; 321 sc->sc_rxframe.rx_frame = sc->sc_rxbuf + offset + 16; 322 323 mc_rint(sc); 324 325 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmam_rx, 326 PAGE_SIZE + offset, 0x800, 327 BUS_DMASYNC_POSTREAD); 328 } 329 330 /* 331 * If we're out of buffers, reset this register set 332 * and switch to the other one. Otherwise, reactivate 333 * this set. 334 */ 335 if (bufsleft == 0) { 336 mc_reset_rxdma_set(sc, sc->sc_rxset); 337 sc->sc_rxset ^= 0x10; 338 } else 339 psc_reg2(PSC_ENETRD_CMD + sc->sc_rxset) = 0x9800; 340 } 341 342 /* Get the write channel status */ 343 status = psc_reg2(PSC_ENETWR_CTL); 344 if (status & 0x2000) { 345 /* I think this is an exceptional condition. Reset the DMA */ 346 mc_reset_txdma(sc); 347 #ifdef MCDEBUG 348 printf("%s: resetting transmit DMA channel (status 0x%04x)\n", 349 device_xname(sc->sc_dev), status); 350 #endif 351 } else if (status & 0x100) { 352 /* Clear the interrupt and switch register sets */ 353 psc_reg2(PSC_ENETWR_CMD + sc->sc_txseti) = 0x100; 354 sc->sc_txseti ^= 0x10; 355 } 356 357 return 1; 358 } 359 360 361 hide void 362 mc_reset_rxdma(struct mc_softc *sc) 363 { 364 u_int8_t maccc; 365 366 /* Disable receiver, reset the DMA channels */ 367 maccc = NIC_GET(sc, MACE_MACCC); 368 NIC_PUT(sc, MACE_MACCC, maccc & ~ENRCV); 369 psc_reg2(PSC_ENETRD_CTL) = 0x8800; 370 mc_reset_rxdma_set(sc, 0); 371 psc_reg2(PSC_ENETRD_CTL) = 0x400; 372 373 psc_reg2(PSC_ENETRD_CTL) = 0x8800; 374 mc_reset_rxdma_set(sc, 0x10); 375 psc_reg2(PSC_ENETRD_CTL) = 0x400; 376 377 /* Reenable receiver, reenable DMA */ 378 NIC_PUT(sc, MACE_MACCC, maccc); 379 sc->sc_rxset = 0; 380 381 psc_reg2(PSC_ENETRD_CMD + PSC_SET0) = 0x9800; 382 psc_reg2(PSC_ENETRD_CMD + PSC_SET1) = 0x9800; 383 } 384 385 hide void 386 mc_reset_rxdma_set(struct mc_softc *sc, int set) 387 { 388 /* disable DMA while modifying the registers, then reenable DMA */ 389 psc_reg2(PSC_ENETRD_CMD + set) = 0x0100; 390 psc_reg4(PSC_ENETRD_ADDR + set) = sc->sc_rxbuf_phys; 391 psc_reg4(PSC_ENETRD_LEN + set) = MC_RXDMABUFS; 392 psc_reg2(PSC_ENETRD_CMD + set) = 0x9800; 393 sc->sc_tail = 0; 394 } 395 396 hide void 397 mc_reset_txdma(struct mc_softc *sc) 398 { 399 u_int8_t maccc; 400 401 psc_reg2(PSC_ENETWR_CTL) = 0x8800; 402 maccc = NIC_GET(sc, MACE_MACCC); 403 NIC_PUT(sc, MACE_MACCC, maccc & ~ENXMT); 404 sc->sc_txset = sc->sc_txseti = 0; 405 psc_reg2(PSC_ENETWR_CTL) = 0x400; 406 NIC_PUT(sc, MACE_MACCC, maccc); 407 } 408 409 hide int 410 mc_obio_getaddr(struct mc_softc *sc, u_int8_t *lladdr) 411 { 412 bus_space_handle_t bsh; 413 u_char csum; 414 415 if (bus_space_map(sc->sc_regt, MACE_PROM_BASE, 8*16, 0, &bsh)) { 416 printf(": failed to map space to read MACE address.\n%s", 417 device_xname(sc->sc_dev)); 418 return (-1); 419 } 420 421 if (!mac68k_bus_space_probe(sc->sc_regt, bsh, 0, 1)) { 422 bus_space_unmap(sc->sc_regt, bsh, 8*16); 423 return (-1); 424 } 425 426 csum = mc_get_enaddr(sc->sc_regt, bsh, 1, lladdr); 427 if (csum != 0xff) 428 printf(": ethernet PROM checksum failed (0x%x != 0xff)\n%s", 429 (int)csum, device_xname(sc->sc_dev)); 430 431 bus_space_unmap(sc->sc_regt, bsh, 8*16); 432 433 return (csum == 0xff ? 0 : -1); 434 } 435