[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     ! 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