[BACK]Return to if_mc_obio.c CVS log [TXT][DIR] Up to [local] / sys / arch / mac68k / dev

Annotation of sys/arch/mac68k/dev/if_mc_obio.c, Revision 1.1.1.1

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

CVSweb