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

Annotation of sys/arch/sparc64/dev/pci_machdep.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pci_machdep.c,v 1.30 2007/08/04 16:39:15 kettenis Exp $       */
        !             2: /*     $NetBSD: pci_machdep.c,v 1.22 2001/07/20 00:07:13 eeh Exp $     */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1999, 2000 Matthew R. Green
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. 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,
        !            24:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            25:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
        !            26:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            27:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            29:  * SUCH DAMAGE.
        !            30:  */
        !            31:
        !            32: /*
        !            33:  * functions expected by the MI PCI code.
        !            34:  */
        !            35:
        !            36: #ifdef DEBUG
        !            37: #define SPDB_CONF      0x01
        !            38: #define SPDB_INTR      0x04
        !            39: #define SPDB_INTMAP    0x08
        !            40: #define SPDB_PROBE     0x20
        !            41: int sparc_pci_debug = 0x0;
        !            42: #define DPRINTF(l, s)  do { if (sparc_pci_debug & l) printf s; } while (0)
        !            43: #else
        !            44: #define DPRINTF(l, s)  do { } while (0)
        !            45: #endif
        !            46:
        !            47: #include <sys/types.h>
        !            48: #include <sys/param.h>
        !            49: #include <sys/time.h>
        !            50: #include <sys/systm.h>
        !            51: #include <sys/errno.h>
        !            52: #include <sys/device.h>
        !            53: #include <sys/malloc.h>
        !            54:
        !            55: #define _SPARC_BUS_DMA_PRIVATE
        !            56: #include <machine/bus.h>
        !            57: #include <machine/autoconf.h>
        !            58: #include <machine/openfirm.h>
        !            59: #include <dev/pci/pcivar.h>
        !            60: #include <dev/pci/pcireg.h>
        !            61:
        !            62: #include <dev/ofw/ofw_pci.h>
        !            63:
        !            64: #include <sparc64/dev/iommureg.h>
        !            65: #include <sparc64/dev/iommuvar.h>
        !            66: #include <sparc64/dev/psychoreg.h>
        !            67: #include <sparc64/dev/psychovar.h>
        !            68: #include <sparc64/sparc64/cache.h>
        !            69:
        !            70: /* this is a base to be copied */
        !            71: struct sparc_pci_chipset _sparc_pci_chipset = {
        !            72:        NULL,
        !            73: };
        !            74:
        !            75: static int pci_bus_frequency(int node);
        !            76:
        !            77: /*
        !            78:  * functions provided to the MI code.
        !            79:  */
        !            80:
        !            81: void
        !            82: pci_attach_hook(parent, self, pba)
        !            83:        struct device *parent;
        !            84:        struct device *self;
        !            85:        struct pcibus_attach_args *pba;
        !            86: {
        !            87:        /* Don't do anything */
        !            88: }
        !            89:
        !            90: int
        !            91: pci_bus_maxdevs(pc, busno)
        !            92:        pci_chipset_tag_t pc;
        !            93:        int busno;
        !            94: {
        !            95:
        !            96:        return 32;
        !            97: }
        !            98:
        !            99: pcitag_t
        !           100: pci_make_tag(pc, b, d, f)
        !           101:        pci_chipset_tag_t pc;
        !           102:        int b;
        !           103:        int d;
        !           104:        int f;
        !           105: {
        !           106:        struct ofw_pci_register reg;
        !           107:        pcitag_t tag;
        !           108:        int busrange[2];
        !           109:        int node, len;
        !           110: #ifdef DEBUG
        !           111:        char name[80];
        !           112:        bzero(name, sizeof(name));
        !           113: #endif
        !           114:
        !           115:        /*
        !           116:         * Hunt for the node that corresponds to this device
        !           117:         *
        !           118:         * We could cache this info in an array in the parent
        !           119:         * device... except then we have problems with devices
        !           120:         * attached below pci-pci bridges, and we would need to
        !           121:         * add special code to the pci-pci bridge to cache this
        !           122:         * info.
        !           123:         */
        !           124:
        !           125:        tag = PCITAG_CREATE(-1, b, d, f);
        !           126:        node = pc->rootnode;
        !           127:        /*
        !           128:         * First make sure we're on the right bus.  If our parent
        !           129:         * has a bus-range property and we're not in the range,
        !           130:         * then we're obviously on the wrong bus.  So go up one
        !           131:         * level.
        !           132:         */
        !           133: #ifdef DEBUG
        !           134:        if (sparc_pci_debug & SPDB_PROBE) {
        !           135:                OF_getprop(node, "name", &name, sizeof(name));
        !           136:                printf("curnode %x %s\n", node, name);
        !           137:        }
        !           138: #endif
        !           139: #if 0
        !           140:        while ((OF_getprop(OF_parent(node), "bus-range", (void *)&busrange,
        !           141:                sizeof(busrange)) == sizeof(busrange)) &&
        !           142:                (b < busrange[0] || b > busrange[1])) {
        !           143:                /* Out of range, go up one */
        !           144:                node = OF_parent(node);
        !           145: #ifdef DEBUG
        !           146:                if (sparc_pci_debug & SPDB_PROBE) {
        !           147:                        OF_getprop(node, "name", &name, sizeof(name));
        !           148:                        printf("going up to node %x %s\n", node, name);
        !           149:                }
        !           150: #endif
        !           151:        }
        !           152: #endif
        !           153:        /*
        !           154:         * Now traverse all peers until we find the node or we find
        !           155:         * the right bridge.
        !           156:         *
        !           157:         * XXX We go up one and down one to make sure nobody's missed.
        !           158:         * but this should not be necessary.
        !           159:         */
        !           160:        for (node = ((node)); node; node = OF_peer(node)) {
        !           161:
        !           162: #ifdef DEBUG
        !           163:                if (sparc_pci_debug & SPDB_PROBE) {
        !           164:                        OF_getprop(node, "name", &name, sizeof(name));
        !           165:                        printf("checking node %x %s\n", node, name);
        !           166:                }
        !           167: #endif
        !           168:
        !           169: #if 1
        !           170:                /*
        !           171:                 * Check for PCI-PCI bridges.  If the device we want is
        !           172:                 * in the bus-range for that bridge, work our way down.
        !           173:                 */
        !           174:                while ((OF_getprop(node, "bus-range", (void *)&busrange,
        !           175:                        sizeof(busrange)) == sizeof(busrange)) &&
        !           176:                        (b >= busrange[0] && b <= busrange[1])) {
        !           177:                        /* Go down 1 level */
        !           178:                        node = OF_child(node);
        !           179: #ifdef DEBUG
        !           180:                        if (sparc_pci_debug & SPDB_PROBE) {
        !           181:                                OF_getprop(node, "name", &name, sizeof(name));
        !           182:                                printf("going down to node %x %s\n",
        !           183:                                        node, name);
        !           184:                        }
        !           185: #endif
        !           186:                }
        !           187: #endif
        !           188:                /*
        !           189:                 * We only really need the first `reg' property.
        !           190:                 *
        !           191:                 * For simplicity, we'll query the `reg' when we
        !           192:                 * need it.  Otherwise we could malloc() it, but
        !           193:                 * that gets more complicated.
        !           194:                 */
        !           195:                len = OF_getproplen(node, "reg");
        !           196:                if (len < sizeof(reg))
        !           197:                        continue;
        !           198:                if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
        !           199:                        panic("pci_probe_bus: OF_getprop len botch");
        !           200:
        !           201:                if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi))
        !           202:                        continue;
        !           203:                if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
        !           204:                        continue;
        !           205:                if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi))
        !           206:                        continue;
        !           207:
        !           208:                /* Got a match */
        !           209:                tag = PCITAG_CREATE(node, b, d, f);
        !           210:
        !           211:                return (tag);
        !           212:        }
        !           213:        /* No device found -- return a dead tag */
        !           214:        return (tag);
        !           215: }
        !           216:
        !           217: void
        !           218: pci_decompose_tag(pc, tag, bp, dp, fp)
        !           219:        pci_chipset_tag_t pc;
        !           220:        pcitag_t tag;
        !           221:        int *bp, *dp, *fp;
        !           222: {
        !           223:
        !           224:        if (bp != NULL)
        !           225:                *bp = PCITAG_BUS(tag);
        !           226:        if (dp != NULL)
        !           227:                *dp = PCITAG_DEV(tag);
        !           228:        if (fp != NULL)
        !           229:                *fp = PCITAG_FUN(tag);
        !           230: }
        !           231:
        !           232: static int
        !           233: pci_bus_frequency(int node)
        !           234: {
        !           235:        int len, bus_frequency;
        !           236:
        !           237:        len = OF_getproplen(node, "clock-frequency");
        !           238:        if (len < sizeof(bus_frequency)) {
        !           239:                DPRINTF(SPDB_PROBE,
        !           240:                    ("pci_bus_frequency: clock-frequency len %d too small\n",
        !           241:                     len));
        !           242:                return 33;
        !           243:        }
        !           244:        if (OF_getprop(node, "clock-frequency", &bus_frequency,
        !           245:                       sizeof(bus_frequency)) != len) {
        !           246:                DPRINTF(SPDB_PROBE,
        !           247:                    ("pci_bus_frequency: could not read clock-frequency\n"));
        !           248:                return 33;
        !           249:        }
        !           250:        return bus_frequency / 1000000;
        !           251: }
        !           252:
        !           253: int
        !           254: sparc64_pci_enumerate_bus(struct pci_softc *sc,
        !           255:     int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
        !           256: {
        !           257:        struct ofw_pci_register reg;
        !           258:        pci_chipset_tag_t pc = sc->sc_pc;
        !           259:        pcitag_t tag;
        !           260:        pcireg_t class, csr, bhlc, ic;
        !           261:        int node, b, d, f, ret;
        !           262:        int bus_frequency, lt, cl, cacheline;
        !           263:        char name[30];
        !           264:
        !           265:        if (sc->sc_bridgetag)
        !           266:                node = PCITAG_NODE(*sc->sc_bridgetag);
        !           267:        else
        !           268:                node = pc->rootnode;
        !           269:
        !           270:        bus_frequency = pci_bus_frequency(node);
        !           271:
        !           272:        /*
        !           273:         * Make sure the cache line size is at least as big as the
        !           274:         * ecache line and the streaming cache (64 byte).
        !           275:         */
        !           276:        cacheline = max(cacheinfo.ec_linesize, 64);
        !           277:        KASSERT((cacheline/64)*64 == cacheline &&
        !           278:            (cacheline/cacheinfo.ec_linesize)*cacheinfo.ec_linesize == cacheline &&
        !           279:            (cacheline/4)*4 == cacheline);
        !           280:
        !           281:        for (node = OF_child(node); node != 0 && node != -1;
        !           282:             node = OF_peer(node)) {
        !           283:                name[0] = name[29] = 0;
        !           284:                OF_getprop(node, "name", name, sizeof(name));
        !           285:
        !           286:                if (OF_getprop(node, "class-code", &class, sizeof(class)) !=
        !           287:                    sizeof(class))
        !           288:                        continue;
        !           289:                if (OF_getprop(node, "reg", &reg, sizeof(reg)) < sizeof(reg))
        !           290:                        panic("pci_enumerate_bus: \"%s\" regs too small", name);
        !           291:
        !           292:                b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi);
        !           293:                d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
        !           294:                f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi);
        !           295:
        !           296:                if (sc->sc_bus != b) {
        !           297:                        printf("%s: WARNING: incorrect bus # for \"%s\" "
        !           298:                        "(%d/%d/%d)\n", sc->sc_dev.dv_xname, name, b, d, f);
        !           299:                        continue;
        !           300:                }
        !           301:
        !           302:                tag = PCITAG_CREATE(node, b, d, f);
        !           303:
        !           304:                /*
        !           305:                 * Turn on parity and fast-back-to-back for the device.
        !           306:                 */
        !           307:                csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        !           308:                if (csr & PCI_STATUS_BACKTOBACK_SUPPORT)
        !           309:                        csr |= PCI_COMMAND_BACKTOBACK_ENABLE;
        !           310:                csr |= PCI_COMMAND_PARITY_ENABLE;
        !           311:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
        !           312:
        !           313:                /*
        !           314:                 * Initialize the latency timer register for busmaster
        !           315:                 * devices to work properly.
        !           316:                 *   latency-timer = min-grant * bus-freq / 4  (from FreeBSD)
        !           317:                 * Also initialize the cache line size register.
        !           318:                 * Solaris anytime sets this register to the value 0x10.
        !           319:                 */
        !           320:                bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !           321:                ic = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
        !           322:
        !           323:                lt = min(PCI_MIN_GNT(ic) * bus_frequency / 4, 255);
        !           324:                if (lt == 0 || lt < PCI_LATTIMER(bhlc))
        !           325:                        lt = PCI_LATTIMER(bhlc);
        !           326:
        !           327:                cl = PCI_CACHELINE(bhlc);
        !           328:                if (cl == 0)
        !           329:                        cl = cacheline;
        !           330:
        !           331:                bhlc &= ~((PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT) |
        !           332:                          (PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT));
        !           333:                bhlc |= (lt << PCI_LATTIMER_SHIFT) |
        !           334:                        (cl << PCI_CACHELINE_SHIFT);
        !           335:                pci_conf_write(pc, tag, PCI_BHLC_REG, bhlc);
        !           336:
        !           337:                ret = pci_probe_device(sc, tag, match, pap);
        !           338:                if (match != NULL && ret != 0)
        !           339:                        return (ret);
        !           340:        }
        !           341:
        !           342:        return (0);
        !           343: }
        !           344:
        !           345: /* assume we are mapped little-endian/side-effect */
        !           346: pcireg_t
        !           347: pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
        !           348: {
        !           349:         pcireg_t val = (pcireg_t)~0;
        !           350:
        !           351:         DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ",
        !           352:                 (long)PCITAG_OFFSET(tag), reg));
        !           353:         if (PCITAG_NODE(tag) != -1) {
        !           354:                 val = bus_space_read_4(pc->bustag, pc->bushandle,
        !           355:                         (PCITAG_OFFSET(tag) << pc->tagshift) + reg);
        !           356:         } else
        !           357:                DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n",
        !           358:                    (int)PCITAG_OFFSET(tag)));
        !           359:         DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val));
        !           360:
        !           361:         return (val);
        !           362: }
        !           363:
        !           364: void
        !           365: pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
        !           366: {
        !           367:         DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ",
        !           368:                 (long)PCITAG_OFFSET(tag), reg, (int)data));
        !           369:
        !           370:         /* If we don't know it, just punt. */
        !           371:         if (PCITAG_NODE(tag) == -1) {
        !           372:                 DPRINTF(SPDB_CONF, ("pci_config_write: bad addr"));
        !           373:                 return;
        !           374:         }
        !           375:
        !           376:         bus_space_write_4(pc->bustag, pc->bushandle,
        !           377:                 (PCITAG_OFFSET(tag) << pc->tagshift) + reg, data);
        !           378: }
        !           379:
        !           380: /*
        !           381:  * interrupt mapping foo.
        !           382:  * XXX: how does this deal with multiple interrupts for a device?
        !           383:  */
        !           384: int
        !           385: pci_intr_map(pa, ihp)
        !           386:        struct pci_attach_args *pa;
        !           387:        pci_intr_handle_t *ihp;
        !           388: {
        !           389:        pcitag_t tag = pa->pa_tag;
        !           390:        int interrupts;
        !           391:        int len, node = PCITAG_NODE(tag);
        !           392:        char devtype[30];
        !           393:
        !           394:        len = OF_getproplen(node, "interrupts");
        !           395:        if (len < 0 || len < sizeof(interrupts)) {
        !           396:                DPRINTF(SPDB_INTMAP,
        !           397:                        ("pci_intr_map: interrupts len %d too small\n", len));
        !           398:                return (ENODEV);
        !           399:        }
        !           400:        if (OF_getprop(node, "interrupts", (void *)&interrupts,
        !           401:                sizeof(interrupts)) != len) {
        !           402:                DPRINTF(SPDB_INTMAP,
        !           403:                        ("pci_intr_map: could not read interrupts\n"));
        !           404:                return (ENODEV);
        !           405:        }
        !           406:
        !           407:        if (OF_mapintr(node, &interrupts, sizeof(interrupts),
        !           408:                sizeof(interrupts)) < 0) {
        !           409:                interrupts = -1;
        !           410:        }
        !           411:        /* Try to find an IPL for this type of device. */
        !           412:        if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) {
        !           413:                for (len = 0;  intrmap[len].in_class; len++)
        !           414:                        if (strcmp(intrmap[len].in_class, devtype) == 0) {
        !           415:                                interrupts |= INTLEVENCODE(intrmap[len].in_lev);
        !           416:                                break;
        !           417:                        }
        !           418:        }
        !           419:
        !           420:        /* XXXX -- we use the ino.  What if there is a valid IGN? */
        !           421:        *ihp = interrupts;
        !           422:
        !           423:        if (pa->pa_pc->intr_map)
        !           424:                return ((*pa->pa_pc->intr_map)(pa, ihp));
        !           425:        else
        !           426:                return (0);
        !           427: }
        !           428:
        !           429: int
        !           430: pci_intr_line(pci_intr_handle_t ih)
        !           431: {
        !           432:        return (ih);
        !           433: }
        !           434:
        !           435: const char *
        !           436: pci_intr_string(pc, ih)
        !           437:        pci_chipset_tag_t pc;
        !           438:        pci_intr_handle_t ih;
        !           439: {
        !           440:        static char str[16];
        !           441:
        !           442:        DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih));
        !           443:        snprintf(str, sizeof str, "ivec 0x%x", INTVEC(ih));
        !           444:        DPRINTF(SPDB_INTR, ("; returning %s\n", str));
        !           445:
        !           446:        return (str);
        !           447: }
        !           448:
        !           449: void *
        !           450: pci_intr_establish(pc, ih, level, func, arg, what)
        !           451:        pci_chipset_tag_t pc;
        !           452:        pci_intr_handle_t ih;
        !           453:        int level;
        !           454:        int (*func)(void *);
        !           455:        void *arg;
        !           456:        char *what;
        !           457: {
        !           458:        void *cookie;
        !           459:        struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie;
        !           460:
        !           461:        DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d",
        !           462:            (u_long)ih, level));
        !           463:        cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg, what);
        !           464:
        !           465:        DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie));
        !           466:        return (cookie);
        !           467: }
        !           468:
        !           469: void
        !           470: pci_intr_disestablish(pc, cookie)
        !           471:        pci_chipset_tag_t pc;
        !           472:        void *cookie;
        !           473: {
        !           474:
        !           475:        DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie));
        !           476:
        !           477:        /* XXX */
        !           478:        printf("can't disestablish PCI interrupts yet\n");
        !           479: }

CVSweb