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

Annotation of sys/arch/sparc64/sparc64/ofw_machdep.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ofw_machdep.c,v 1.19 2007/07/28 13:22:22 kettenis Exp $       */
                      2: /*     $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $     */
                      3:
                      4: /*
                      5:  * Copyright (C) 1996 Wolfgang Solfrank.
                      6:  * Copyright (C) 1996 TooLs GmbH.
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This product includes software developed by TooLs GmbH.
                     20:  * 4. The name of TooLs GmbH may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     26:  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     27:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34: #include <sys/param.h>
                     35: #include <sys/buf.h>
                     36: #include <sys/conf.h>
                     37: #include <sys/device.h>
                     38: #include <sys/disk.h>
                     39: #include <sys/disklabel.h>
                     40: #include <sys/fcntl.h>
                     41: #include <sys/ioctl.h>
                     42: #include <sys/malloc.h>
                     43: #include <sys/stat.h>
                     44: #include <sys/systm.h>
                     45:
                     46: #include <machine/openfirm.h>
                     47:
                     48: #include <dev/ofw/ofw_pci.h>
                     49:
                     50: #if defined(FFS) && defined(CD9660)
                     51: #include <ufs/ffs/fs.h>
                     52: #endif
                     53:
                     54: /*
                     55:  * Note that stdarg.h and the ANSI style va_start macro is used for both
                     56:  * ANSI and traditional C compilers.
                     57:  */
                     58: #include <sys/stdarg.h>
                     59:
                     60: #include <machine/sparc64.h>
                     61:
                     62: int vsprintf(char *, const char *, va_list);
                     63:
                     64: void dk_cleanup(void);
                     65:
                     66: static u_int mmuh = -1, memh = -1;
                     67:
                     68: static u_int get_mmu_handle(void);
                     69: static u_int get_memory_handle(void);
                     70:
                     71: static u_int
                     72: get_mmu_handle()
                     73: {
                     74:        u_int chosen;
                     75:
                     76:        if ((chosen = OF_finddevice("/chosen")) == -1) {
                     77:                prom_printf("get_mmu_handle: cannot get /chosen\r\n");
                     78:                return -1;
                     79:        }
                     80:        if (OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) == -1) {
                     81:                prom_printf("get_mmu_handle: cannot get mmuh\r\n");
                     82:                return -1;
                     83:        }
                     84:        return mmuh;
                     85: }
                     86:
                     87: static u_int
                     88: get_memory_handle()
                     89: {
                     90:        u_int chosen;
                     91:
                     92:        if ((chosen = OF_finddevice("/chosen")) == -1) {
                     93:                prom_printf("get_memory_handle: cannot get /chosen\r\n");
                     94:                return -1;
                     95:        }
                     96:        if (OF_getprop(chosen, "memory", &memh, sizeof(memh)) == -1) {
                     97:                prom_printf("get_memory_handle: cannot get memh\r\n");
                     98:                return -1;
                     99:        }
                    100:        return memh;
                    101: }
                    102:
                    103:
                    104: /*
                    105:  * Point prom to our trap table.  This stops the prom from mapping us.
                    106:  */
                    107: int
                    108: prom_set_trap_table(tba)
                    109:        vaddr_t tba;
                    110: {
                    111:        struct {
                    112:                cell_t name;
                    113:                cell_t nargs;
                    114:                cell_t nreturns;
                    115:                cell_t tba;
                    116:        } args;
                    117:
                    118:        args.name = ADR2CELL("SUNW,set-trap-table");
                    119:        args.nargs = 1;
                    120:        args.nreturns = 0;
                    121:        args.tba = ADR2CELL(tba);
                    122:        return openfirmware(&args);
                    123: }
                    124:
                    125: /*
                    126:  * Have the prom convert from virtual to physical addresses.
                    127:  *
                    128:  * Only works while the prom is actively mapping us.
                    129:  */
                    130: paddr_t
                    131: prom_vtop(vaddr)
                    132:        vaddr_t vaddr;
                    133: {
                    134:        struct {
                    135:                cell_t name;
                    136:                cell_t nargs;
                    137:                cell_t nreturns;
                    138:                cell_t method;
                    139:                cell_t ihandle;
                    140:                cell_t vaddr;
                    141:                cell_t status;
                    142:                cell_t retaddr;
                    143:                cell_t mode;
                    144:                cell_t phys_hi;
                    145:                cell_t phys_lo;
                    146:        } args;
                    147:
                    148:        if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
                    149:                prom_printf("prom_vtop: cannot get mmuh\r\n");
                    150:                return 0;
                    151:        }
                    152:        args.name = ADR2CELL("call-method");
                    153:        args.nargs = 3;
                    154:        args.nreturns = 5;
                    155:        args.method = ADR2CELL("translate");
                    156:        args.ihandle = HDL2CELL(mmuh);
                    157:        args.vaddr = ADR2CELL(vaddr);
                    158:        if(openfirmware(&args) == -1)
                    159:                return -1;
                    160: #if 0
                    161:        prom_printf("Called \"translate\", mmuh=%x, vaddr=%x, "
                    162:                    "status=%x %x,\r\n "
                    163:                    "retaddr=%x %x, "
                    164:                    "mode=%x %x, "
                    165:                    "phys_hi=%x %x, "
                    166:                    "phys_lo=%x %x\r\n",
                    167:                    mmuh, vaddr,
                    168:                    (int)(args.status>>32), (int)args.status,
                    169:                    (int)(args.retaddr>>32), (int)args.retaddr,
                    170:                    (int)(args.mode>>32), (int)args.mode,
                    171:                    (int)(args.phys_hi>>32), (int)args.phys_hi,
                    172:                    (int)(args.phys_lo>>32), (int)args.phys_lo);
                    173: #endif
                    174:        return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
                    175: }
                    176:
                    177: /*
                    178:  * Grab some address space from the prom
                    179:  *
                    180:  * Only works while the prom is actively mapping us.
                    181:  */
                    182: vaddr_t
                    183: prom_claim_virt(vaddr, len)
                    184:        vaddr_t vaddr;
                    185:        int len;
                    186: {
                    187:        struct {
                    188:                cell_t name;
                    189:                cell_t nargs;
                    190:                cell_t nreturns;
                    191:                cell_t method;
                    192:                cell_t ihandle;
                    193:                cell_t align;
                    194:                cell_t len;
                    195:                cell_t vaddr;
                    196:                cell_t status;
                    197:                cell_t retaddr;
                    198:        } args;
                    199:
                    200:        if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
                    201:                prom_printf("prom_claim_virt: cannot get mmuh\r\n");
                    202:                return 0;
                    203:        }
                    204:        args.name = ADR2CELL("call-method");
                    205:        args.nargs = 5;
                    206:        args.nreturns = 2;
                    207:        args.method = ADR2CELL("claim");
                    208:        args.ihandle = HDL2CELL(mmuh);
                    209:        args.align = 0;
                    210:        args.len = len;
                    211:        args.vaddr = ADR2CELL(vaddr);
                    212:        if (openfirmware(&args) == -1)
                    213:                return -1;
                    214:        return (paddr_t)args.retaddr;
                    215: }
                    216:
                    217: /*
                    218:  * Request some address space from the prom
                    219:  *
                    220:  * Only works while the prom is actively mapping us.
                    221:  */
                    222: vaddr_t
                    223: prom_alloc_virt(len, align)
                    224:        int len;
                    225:        int align;
                    226: {
                    227:        struct {
                    228:                cell_t name;
                    229:                cell_t nargs;
                    230:                cell_t nreturns;
                    231:                cell_t method;
                    232:                cell_t ihandle;
                    233:                cell_t align;
                    234:                cell_t len;
                    235:                cell_t status;
                    236:                cell_t retaddr;
                    237:        } args;
                    238:
                    239:        if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
                    240:                prom_printf("prom_alloc_virt: cannot get mmuh\r\n");
                    241:                return -1LL;
                    242:        }
                    243:        args.name = ADR2CELL("call-method");
                    244:        args.nargs = 4;
                    245:        args.nreturns = 2;
                    246:        args.method = ADR2CELL("claim");
                    247:        args.ihandle = HDL2CELL(mmuh);
                    248:        args.align = align;
                    249:        args.len = len;
                    250:        if (openfirmware(&args) != 0)
                    251:                return -1;
                    252:        return (vaddr_t)args.retaddr;
                    253: }
                    254:
                    255: /*
                    256:  * Release some address space to the prom
                    257:  *
                    258:  * Only works while the prom is actively mapping us.
                    259:  */
                    260: int
                    261: prom_free_virt(vaddr, len)
                    262:        vaddr_t vaddr;
                    263:        int len;
                    264: {
                    265:        struct {
                    266:                cell_t name;
                    267:                cell_t nargs;
                    268:                cell_t nreturns;
                    269:                cell_t method;
                    270:                cell_t ihandle;
                    271:                cell_t len;
                    272:                cell_t vaddr;
                    273:        } args;
                    274:
                    275:        if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
                    276:                prom_printf("prom_free_virt: cannot get mmuh\r\n");
                    277:                return -1;
                    278:        }
                    279:        args.name = ADR2CELL("call-method");
                    280:        args.nargs = 4;
                    281:        args.nreturns = 0;
                    282:        args.method = ADR2CELL("release");
                    283:        args.ihandle = HDL2CELL(mmuh);
                    284:        args.vaddr = ADR2CELL(vaddr);
                    285:        args.len = len;
                    286:        return openfirmware(&args);
                    287: }
                    288:
                    289:
                    290: /*
                    291:  * Unmap some address space
                    292:  *
                    293:  * Only works while the prom is actively mapping us.
                    294:  */
                    295: int
                    296: prom_unmap_virt(vaddr, len)
                    297:        vaddr_t vaddr;
                    298:        int len;
                    299: {
                    300:        struct {
                    301:                cell_t name;
                    302:                cell_t nargs;
                    303:                cell_t nreturns;
                    304:                cell_t method;
                    305:                cell_t ihandle;
                    306:                cell_t len;
                    307:                cell_t vaddr;
                    308:        } args;
                    309:
                    310:        if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
                    311:                prom_printf("prom_unmap_virt: cannot get mmuh\r\n");
                    312:                return -1;
                    313:        }
                    314:        args.name = ADR2CELL("call-method");
                    315:        args.nargs = 4;
                    316:        args.nreturns = 0;
                    317:        args.method = ADR2CELL("unmap");
                    318:        args.ihandle = HDL2CELL(mmuh);
                    319:        args.vaddr = ADR2CELL(vaddr);
                    320:        args.len = len;
                    321:        return openfirmware(&args);
                    322: }
                    323:
                    324: /*
                    325:  * Have prom map in some memory
                    326:  *
                    327:  * Only works while the prom is actively mapping us.
                    328:  */
                    329: int
                    330: prom_map_phys(paddr, size, vaddr, mode)
                    331:        paddr_t paddr;
                    332:        off_t size;
                    333:        vaddr_t vaddr;
                    334:        int mode;
                    335: {
                    336:        struct {
                    337:                cell_t name;
                    338:                cell_t nargs;
                    339:                cell_t nreturns;
                    340:                cell_t method;
                    341:                cell_t ihandle;
                    342:                cell_t mode;
                    343:                cell_t size;
                    344:                cell_t vaddr;
                    345:                cell_t phys_hi;
                    346:                cell_t phys_lo;
                    347:                cell_t status;
                    348:                cell_t retaddr;
                    349:        } args;
                    350:
                    351:        if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
                    352:                prom_printf("prom_map_phys: cannot get mmuh\r\n");
                    353:                return 0;
                    354:        }
                    355:        args.name = ADR2CELL("call-method");
                    356:        args.nargs = 7;
                    357:        args.nreturns = 1;
                    358:        args.method = ADR2CELL("map");
                    359:        args.ihandle = HDL2CELL(mmuh);
                    360:        args.mode = mode;
                    361:        args.size = size;
                    362:        args.vaddr = ADR2CELL(vaddr);
                    363:        args.phys_hi = HDQ2CELL_HI(paddr);
                    364:        args.phys_lo = HDQ2CELL_LO(paddr);
                    365:
                    366:        if (openfirmware(&args) == -1)
                    367:                return -1;
                    368:        if (args.status)
                    369:                return -1;
                    370:        return (int)args.retaddr;
                    371: }
                    372:
                    373:
                    374: /*
                    375:  * Request some RAM from the prom
                    376:  *
                    377:  * Only works while the prom is actively mapping us.
                    378:  */
                    379: paddr_t
                    380: prom_alloc_phys(len, align)
                    381:        int len;
                    382:        int align;
                    383: {
                    384:        struct {
                    385:                cell_t name;
                    386:                cell_t nargs;
                    387:                cell_t nreturns;
                    388:                cell_t method;
                    389:                cell_t ihandle;
                    390:                cell_t align;
                    391:                cell_t len;
                    392:                cell_t status;
                    393:                cell_t phys_hi;
                    394:                cell_t phys_lo;
                    395:        } args;
                    396:
                    397:        if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
                    398:                prom_printf("prom_alloc_phys: cannot get memh\r\n");
                    399:                return -1;
                    400:        }
                    401:        args.name = ADR2CELL("call-method");
                    402:        args.nargs = 4;
                    403:        args.nreturns = 3;
                    404:        args.method = ADR2CELL("claim");
                    405:        args.ihandle = HDL2CELL(memh);
                    406:        args.align = align;
                    407:        args.len = len;
                    408:        if (openfirmware(&args) != 0)
                    409:                return -1;
                    410:        return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
                    411: }
                    412:
                    413: /*
                    414:  * Request some specific RAM from the prom
                    415:  *
                    416:  * Only works while the prom is actively mapping us.
                    417:  */
                    418: paddr_t
                    419: prom_claim_phys(phys, len)
                    420:        paddr_t phys;
                    421:        int len;
                    422: {
                    423:        struct {
                    424:                cell_t name;
                    425:                cell_t nargs;
                    426:                cell_t nreturns;
                    427:                cell_t method;
                    428:                cell_t ihandle;
                    429:                cell_t align;
                    430:                cell_t len;
                    431:                cell_t phys_hi;
                    432:                cell_t phys_lo;
                    433:                cell_t status;
                    434:                cell_t rphys_hi;
                    435:                cell_t rphys_lo;
                    436:        } args;
                    437:
                    438:        if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
                    439:                prom_printf("prom_claim_phys: cannot get memh\r\n");
                    440:                return -1;
                    441:        }
                    442:        args.name = ADR2CELL("call-method");
                    443:        args.nargs = 6;
                    444:        args.nreturns = 3;
                    445:        args.method = ADR2CELL("claim");
                    446:        args.ihandle = HDL2CELL(memh);
                    447:        args.align = 0;
                    448:        args.len = len;
                    449:        args.phys_hi = HDQ2CELL_HI(phys);
                    450:        args.phys_lo = HDQ2CELL_LO(phys);
                    451:        if (openfirmware(&args) != 0)
                    452:                return -1;
                    453:        return (paddr_t)CELL2HDQ(args.rphys_hi, args.rphys_lo);
                    454: }
                    455:
                    456: /*
                    457:  * Free some RAM to prom
                    458:  *
                    459:  * Only works while the prom is actively mapping us.
                    460:  */
                    461: int
                    462: prom_free_phys(phys, len)
                    463:        paddr_t phys;
                    464:        int len;
                    465: {
                    466:        struct {
                    467:                cell_t name;
                    468:                cell_t nargs;
                    469:                cell_t nreturns;
                    470:                cell_t method;
                    471:                cell_t ihandle;
                    472:                cell_t len;
                    473:                cell_t phys_hi;
                    474:                cell_t phys_lo;
                    475:        } args;
                    476:
                    477:        if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
                    478:                prom_printf("prom_free_phys: cannot get memh\r\n");
                    479:                return -1;
                    480:        }
                    481:        args.name = ADR2CELL("call-method");
                    482:        args.nargs = 5;
                    483:        args.nreturns = 0;
                    484:        args.method = ADR2CELL("release");
                    485:        args.ihandle = HDL2CELL(memh);
                    486:        args.len = len;
                    487:        args.phys_hi = HDQ2CELL_HI(phys);
                    488:        args.phys_lo = HDQ2CELL_LO(phys);
                    489:        return openfirmware(&args);
                    490: }
                    491:
                    492: /*
                    493:  * Get the msgbuf from the prom.  Only works once.
                    494:  *
                    495:  * Only works while the prom is actively mapping us.
                    496:  */
                    497: paddr_t
                    498: prom_get_msgbuf(len, align)
                    499:        int len;
                    500:        int align;
                    501: {
                    502:        struct {
                    503:                cell_t name;
                    504:                cell_t nargs;
                    505:                cell_t nreturns;
                    506:                cell_t method;
                    507:                cell_t ihandle;
                    508:                cell_t align;
                    509:                cell_t len;
                    510:                cell_t id;
                    511:                cell_t status;
                    512:                cell_t phys_hi;
                    513:                cell_t phys_lo;
                    514:        } args;
                    515:        paddr_t addr;
                    516:        int rooth;
                    517:        int is_e250 = 1;
                    518:
                    519:        /* E250s tend to have buggy PROMs that break on test-method */
                    520:        if ((rooth = OF_finddevice("/")) != -1) {
                    521:                char name[80];
                    522:
                    523:                if ((OF_getprop(rooth, "name", &name, sizeof(name))) != -1) {
                    524:                        if (strcmp(name, "SUNW,Ultra-250") && strcmp(name, "SUNW,Ultra-4"))
                    525:                                is_e250 = 0;
                    526:                } else prom_printf("prom_get_msgbuf: cannot get \"name\"\r\n");
                    527:        } else prom_printf("prom_get_msgbuf: cannot open root device \r\n");
                    528:
                    529:        if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
                    530:                prom_printf("prom_get_msgbuf: cannot get memh\r\n");
                    531:                return -1;
                    532:        }
                    533:        if (is_e250) {
                    534:                prom_printf("prom_get_msgbuf: Cannot recover msgbuf on E250/450\r\n");
                    535:        } else if (OF_test("test-method") == 0) {
                    536:                if (OF_test_method(memh, "SUNW,retain") != 0) {
                    537:                        args.name = ADR2CELL("call-method");
                    538:                        args.nargs = 5;
                    539:                        args.nreturns = 3;
                    540:                        args.method = ADR2CELL("SUNW,retain");
                    541:                        args.id = ADR2CELL("msgbuf");
                    542:                        args.ihandle = HDL2CELL(memh);
                    543:                        args.len = len;
                    544:                        args.align = align;
                    545:                        args.status = -1;
                    546:                        if (openfirmware(&args) == 0 && args.status == 0)
                    547:                                return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
                    548:                        prom_printf("prom_get_msgbuf: SUNW,retain failed\r\n");
                    549:                } else prom_printf("prom_get_msgbuf: test-method failed\r\n");
                    550:        } else prom_printf("prom_get_msgbuf: test failed\r\n");
                    551:        /* Allocate random memory -- page zero avail?*/
                    552:        addr = prom_claim_phys(0x000, len);
                    553:        prom_printf("prom_get_msgbuf: allocated new buf at %08x\r\n", (int)addr);
                    554:        if (addr == -1) {
                    555:                prom_printf("prom_get_msgbuf: cannot get allocate physmem\r\n");
                    556:                return -1;
                    557:        }
                    558:        prom_printf("prom_get_msgbuf: claiming new buf at %08x\r\n", (int)addr);
                    559:        { int i; for (i=0; i<200000000; i++); }
                    560:        return addr; /* Kluge till we go 64-bit */
                    561: }
                    562:
                    563: /*
                    564:  * Low-level prom I/O routines.
                    565:  */
                    566:
                    567: static u_int stdin = 0;
                    568: static u_int stdout = 0;
                    569:
                    570: int
                    571: OF_stdin()
                    572: {
                    573:        u_int chosen;
                    574:
                    575:        if (stdin != 0)
                    576:                return stdin;
                    577:
                    578:        chosen = OF_finddevice("/chosen");
                    579:        OF_getprop(chosen, "stdin", &stdin, sizeof(stdin));
                    580:        return stdin;
                    581: }
                    582:
                    583: int
                    584: OF_stdout()
                    585: {
                    586:        u_int chosen;
                    587:
                    588:        if (stdout != 0)
                    589:                return stdout;
                    590:
                    591:        chosen = OF_finddevice("/chosen");
                    592:        OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
                    593:        return stdout;
                    594: }
                    595:
                    596:
                    597: /*
                    598:  * print debug info to prom.
                    599:  * This is not safe, but then what do you expect?
                    600:  */
                    601: void
                    602: prom_printf(const char *fmt, ...)
                    603: {
                    604:        int len;
                    605:        static char buf[256];
                    606:        va_list ap;
                    607:
                    608:        va_start(ap, fmt);
                    609:        len = vsnprintf(buf, sizeof buf, fmt, ap);
                    610:        if (len == -1)
                    611:                len = 0;
                    612:        else if (len >= sizeof buf)
                    613:                len = sizeof buf - 1;
                    614:        va_end(ap);
                    615:
                    616:        OF_write(OF_stdout(), buf, len);
                    617: }
                    618:
                    619: #ifdef DEBUG
                    620: int ofmapintrdebug = 0;
                    621: #define        DPRINTF(x)      if (ofmapintrdebug) printf x
                    622: #else
                    623: #define DPRINTF(x)
                    624: #endif
                    625:
                    626:
                    627: /*
                    628:  * Recursively hunt for a property.
                    629:  */
                    630: int
                    631: OF_searchprop(int node, char *prop, void *buf, int buflen)
                    632: {
                    633:        int len;
                    634:
                    635:        for( ; node; node = OF_parent(node)) {
                    636:                len = OF_getprop(node, prop, buf, buflen);
                    637:                if (len >= 0)
                    638:                        return (len);
                    639:        }
                    640:        /* Error -- not found */
                    641:        return (-1);
                    642: }
                    643:
                    644:
                    645: /*
                    646:  * Compare a sequence of cells with a mask,
                    647:  *  return 1 if they match and 0 if they don't.
                    648:  */
                    649: static int compare_cells (int *cell1, int *cell2, int *mask, int ncells);
                    650: static int
                    651: compare_cells(int *cell1, int *cell2, int *mask, int ncells)
                    652: {
                    653:        int i;
                    654:
                    655:        for (i=0; i<ncells; i++) {
                    656:                DPRINTF(("src %x ^ dest %x -> %x & mask %x -> %x\n",
                    657:                        cell1[i], cell2[i], (cell1[i] ^ cell2[i]),
                    658:                        mask[i], ((cell1[i] ^ cell2[i]) & mask[i])));
                    659:                if (((cell1[i] ^ cell2[i]) & mask[i]) != 0)
                    660:                        return (0);
                    661:        }
                    662:        return (1);
                    663: }
                    664:
                    665: /*
                    666:  * Find top pci bus host controller for a node.
                    667:  */
                    668: static int
                    669: find_pci_host_node(int node)
                    670: {
                    671:        char dev_type[16];
                    672:        int pch = 0;
                    673:        int len;
                    674:
                    675:        for (; node; node = OF_parent(node)) {
                    676:                len = OF_getprop(node, "device_type",
                    677:                                 &dev_type, sizeof(dev_type));
                    678:                if (len <= 0)
                    679:                        continue;
                    680:                if (strcmp(dev_type, "pci") == 0 ||
                    681:                    strcmp(dev_type, "pciex") == 0)
                    682:                        pch = node;
                    683:        }
                    684:        return pch;
                    685: }
                    686:
                    687: /*
                    688:  * Follow the OFW algorithm and return an interrupt specifier.
                    689:  *
                    690:  * Pass in the interrupt specifier you want mapped and the node
                    691:  * you want it mapped from.  validlen is the number of cells in
                    692:  * the interrupt specifier, and buflen is the number of cells in
                    693:  * the buffer.
                    694:  */
                    695: int
                    696: OF_mapintr(int node, int *interrupt, int validlen, int buflen)
                    697: {
                    698:        int i, len;
                    699:        int address_cells, size_cells, interrupt_cells, interrupt_map_len;
                    700:        int interrupt_map[256];
                    701:        int interrupt_map_mask[10];
                    702:        int reg[10];
                    703:        char dev_type[32];
                    704:        int phc_node;
                    705:        int rc = -1;
                    706:
                    707:        /*
                    708:         * Don't try to map interrupts for onboard devices, or if the
                    709:         * interrupt is already fully specified.
                    710:         */
                    711:        if (*interrupt & 0x20 || *interrupt & 0x7c0)
                    712:                return validlen;
                    713:
                    714:        /*
                    715:         * If there is no interrupt map in the bus node, we
                    716:         * need to convert the slot address to its parent
                    717:         * bus format, and hunt up the parent bus to see if
                    718:         * we need to remap.
                    719:         *
                    720:         * The specification for interrupt mapping is borken.
                    721:         * You are supposed to query the interrupt parent in
                    722:         * the interrupt-map specification to determine the
                    723:         * number of address and interrupt cells, but we need
                    724:         * to know how many address and interrupt cells to skip
                    725:         * to find the phandle...
                    726:         *
                    727:         */
                    728:        if ((len = OF_getprop(node, "reg", &reg, sizeof(reg))) <= 0) {
                    729:                printf("OF_mapintr: no reg property?\n");
                    730:                return (-1);
                    731:        }
                    732:
                    733:        phc_node = find_pci_host_node(node);
                    734:        while (node) {
                    735: #ifdef DEBUG
                    736:                char name[40];
                    737:
                    738:                if (ofmapintrdebug) {
                    739:                        OF_getprop(node, "name", &name, sizeof(name));
                    740:                        printf("Node %s (%x), host %x\n", name,
                    741:                               node, phc_node);
                    742:                }
                    743: #endif
                    744:
                    745:                if ((interrupt_map_len = OF_getprop(node,
                    746:                        "interrupt-map", &interrupt_map,
                    747:                        sizeof(interrupt_map))) <= 0) {
                    748:
                    749:                        /* Swizzle interrupt if this is a PCI bridge. */
                    750:                        if (((len = OF_getprop(node, "device_type", &dev_type,
                    751:                                              sizeof(dev_type))) > 0) &&
                    752:                            (strcmp(dev_type, "pci") == 0 ||
                    753:                             strcmp(dev_type, "pciex") == 0) &&
                    754:                            (node != phc_node)) {
                    755:                                *interrupt = ((*interrupt +
                    756:                                    OFW_PCI_PHYS_HI_DEVICE(reg[0]) - 1) & 3) + 1;
                    757:                                DPRINTF(("OF_mapintr: interrupt %x, reg[0] %x\n",
                    758:                                         *interrupt, reg[0]));
                    759:                        }
                    760:
                    761:                        /* Get reg for next level compare. */
                    762:                        reg[0] = 0;
                    763:                        OF_getprop(node, "reg", &reg, sizeof(reg));
                    764:
                    765:                        node = OF_parent(node);
                    766:                        continue;
                    767:                }
                    768:                /* Convert from bytes to cells. */
                    769:                interrupt_map_len = interrupt_map_len/sizeof(int);
                    770:                if ((len = (OF_searchprop(node, "#address-cells", &address_cells,
                    771:                        sizeof(address_cells)))) <= 0) {
                    772:                        /* How should I know. */
                    773:                        address_cells = 2;
                    774:                }
                    775:                DPRINTF(("#address-cells = %d len %d", address_cells, len));
                    776:                if ((len = OF_searchprop(node, "#size-cells", &size_cells,
                    777:                        sizeof(size_cells))) <= 0) {
                    778:                        /* How should I know. */
                    779:                        size_cells = 2;
                    780:                }
                    781:                DPRINTF(("#size-cells = %d len %d", size_cells, len));
                    782:                if ((len = OF_getprop(node, "#interrupt-cells", &interrupt_cells,
                    783:                        sizeof(interrupt_cells))) <= 0) {
                    784:                        /* How should I know. */
                    785:                        interrupt_cells = 1;
                    786:                }
                    787:                DPRINTF(("#interrupt-cells = %d, len %d\n", interrupt_cells,
                    788:                        len));
                    789:                if ((len = OF_getprop(node, "interrupt-map-mask", &interrupt_map_mask,
                    790:                        sizeof(interrupt_map_mask))) <= 0) {
                    791:                        /* Create a mask that masks nothing. */
                    792:                        for (i = 0; i<(address_cells + interrupt_cells); i++)
                    793:                                interrupt_map_mask[i] = -1;
                    794:                }
                    795: #ifdef DEBUG
                    796:                DPRINTF(("interrupt-map-mask len %d = ", len));
                    797:                for (i=0; i<(address_cells + interrupt_cells); i++)
                    798:                        DPRINTF(("%x.", interrupt_map_mask[i]));
                    799:                DPRINTF(("reg = "));
                    800:                for (i=0; i<(address_cells); i++)
                    801:                        DPRINTF(("%x.", reg[i]));
                    802:                DPRINTF(("interrupts = "));
                    803:                for (i=0; i<(interrupt_cells); i++)
                    804:                        DPRINTF(("%x.", interrupt[i]));
                    805:
                    806: #endif
                    807:
                    808:                /* Finally we can attempt the compare. */
                    809:                i = 0;
                    810:                while (i < interrupt_map_len + address_cells + interrupt_cells) {
                    811:                        int pintr_cells;
                    812:                        int *imap = &interrupt_map[i];
                    813:                        int *parent = &imap[address_cells + interrupt_cells];
                    814:
                    815: #ifdef DEBUG
                    816:                        DPRINTF(("\ninterrupt-map addr (a %d, i %d p %p) ", address_cells, interrupt_cells, parent));
                    817:                        for (len=0; len<address_cells; len++)
                    818:                                DPRINTF(("%x.", imap[len]));
                    819:                        DPRINTF((" intr "));
                    820:                        for (; len<(address_cells+interrupt_cells); len++)
                    821:                                DPRINTF(("%x.", imap[len]));
                    822:                        DPRINTF(("\nnode %x vs parent %x\n",
                    823:                                imap[len], *parent));
                    824: #endif
                    825:
                    826:                        /* Find out how many cells we'll need to skip. */
                    827:                        if ((len = OF_searchprop(*parent, "#interrupt-cells",
                    828:                                &pintr_cells, sizeof(pintr_cells))) < 0) {
                    829:                                pintr_cells = interrupt_cells;
                    830:                        }
                    831:                        DPRINTF(("pintr_cells = %d len %d\n", pintr_cells, len));
                    832:
                    833:                        if (compare_cells(imap, reg,
                    834:                                interrupt_map_mask, address_cells) &&
                    835:                                compare_cells(&imap[address_cells],
                    836:                                        interrupt,
                    837:                                        &interrupt_map_mask[address_cells],
                    838:                                        interrupt_cells))
                    839:                        {
                    840:                                /* Bingo! */
                    841:                                if (buflen < pintr_cells) {
                    842:                                        /* Error -- ran out of storage. */
                    843:                                        return (-1);
                    844:                                }
                    845:                                node = *parent;
                    846:                                parent++;
                    847: #ifdef DEBUG
                    848:                                DPRINTF(("Match! using "));
                    849:                                for (len=0; len<pintr_cells; len++)
                    850:                                        DPRINTF(("%x.", parent[len]));
                    851: #endif
                    852:                                for (i=0; i<pintr_cells; i++)
                    853:                                        interrupt[i] = parent[i];
                    854:                                rc = validlen = pintr_cells;
                    855:                                if (node == phc_node)
                    856:                                        return (rc);
                    857:                                break;
                    858:                        }
                    859:                        /* Move on to the next interrupt_map entry. */
                    860: #ifdef DEBUG
                    861:                        DPRINTF(("skip %d cells:",
                    862:                                address_cells + interrupt_cells +
                    863:                                pintr_cells + 1));
                    864:                        for (len=0; len<(address_cells +
                    865:                                interrupt_cells + pintr_cells + 1); len++)
                    866:                                DPRINTF(("%x.", imap[len]));
                    867: #endif
                    868:                        i += address_cells + interrupt_cells + pintr_cells + 1;
                    869:                }
                    870:
                    871:                /* Get reg for the next level search. */
                    872:                if ((len = OF_getprop(node, "reg", &reg, sizeof(reg))) <= 0)
                    873:                        DPRINTF(("OF_mapintr: no reg property?\n"));
                    874:                else
                    875:                        DPRINTF(("reg len %d\n", len));
                    876:
                    877:                node = OF_parent(node);
                    878:        }
                    879:        return (rc);
                    880: }

CVSweb