[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

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