[BACK]Return to pci_map.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/pci_map.c, Revision 1.1

1.1     ! nbrk        1: /*      $OpenBSD: pci_map.c,v 1.20 2007/01/26 01:18:48 tsi Exp $     */
        !             2: /*     $NetBSD: pci_map.c,v 1.7 2000/05/10 16:58:42 thorpej Exp $      */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Charles M. Hannum; by William R. Studenmund; by Jason R. Thorpe.
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  * 3. All advertising materials mentioning features or use of this software
        !            20:  *    must display the following acknowledgement:
        !            21:  *        This product includes software developed by the NetBSD
        !            22:  *        Foundation, Inc. and its contributors.
        !            23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            24:  *    contributors may be used to endorse or promote products derived
        !            25:  *    from this software without specific prior written permission.
        !            26:  *
        !            27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            37:  * POSSIBILITY OF SUCH DAMAGE.
        !            38:  */
        !            39:
        !            40: /*
        !            41:  * PCI device mapping.
        !            42:  */
        !            43:
        !            44: #include <sys/param.h>
        !            45: #include <sys/systm.h>
        !            46: #include <sys/device.h>
        !            47:
        !            48: #include <dev/pci/pcireg.h>
        !            49: #include <dev/pci/pcivar.h>
        !            50:
        !            51:
        !            52: int obsd_pci_io_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
        !            53:     bus_addr_t *, bus_size_t *, int *);
        !            54: int obsd_pci_mem_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
        !            55:     bus_addr_t *, bus_size_t *, int *);
        !            56:
        !            57: int
        !            58: obsd_pci_io_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
        !            59:     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
        !            60: {
        !            61:        pcireg_t address, mask, csr;
        !            62:        int s;
        !            63:
        !            64:        if (reg < PCI_MAPREG_START ||
        !            65: #if 0
        !            66:            /*
        !            67:             * Can't do this check; some devices have mapping registers
        !            68:             * way out in left field.
        !            69:             */
        !            70:            reg >= PCI_MAPREG_END ||
        !            71: #endif
        !            72:            (reg & 3))
        !            73:                panic("pci_io_find: bad request");
        !            74:
        !            75:        /*
        !            76:         * Section 6.2.5.1, `Address Maps', tells us that:
        !            77:         *
        !            78:         * 1) The builtin software should have already mapped the device in a
        !            79:         * reasonable way.
        !            80:         *
        !            81:         * 2) A device which wants 2^n bytes of memory will hardwire the bottom
        !            82:         * n bits of the address to 0.  As recommended, we write all 1s while
        !            83:         * the device is disabled and see what we get back.
        !            84:         */
        !            85:        s = splhigh();
        !            86:        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        !            87:        if (csr & PCI_COMMAND_IO_ENABLE)
        !            88:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
        !            89:                    csr & ~PCI_COMMAND_IO_ENABLE);
        !            90:        address = pci_conf_read(pc, tag, reg);
        !            91:        pci_conf_write(pc, tag, reg, 0xffffffff);
        !            92:        mask = pci_conf_read(pc, tag, reg);
        !            93:        pci_conf_write(pc, tag, reg, address);
        !            94:        if (csr & PCI_COMMAND_IO_ENABLE)
        !            95:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
        !            96:        splx(s);
        !            97:
        !            98:        if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
        !            99: #ifdef DEBUG
        !           100:                printf("pci_io_find: expected type i/o, found mem\n");
        !           101: #endif
        !           102:                return (EINVAL);
        !           103:        }
        !           104:
        !           105:        if (PCI_MAPREG_IO_SIZE(mask) == 0) {
        !           106: #ifdef DEBUG
        !           107:                printf("pci_io_find: void region\n");
        !           108: #endif
        !           109:                return (ENOENT);
        !           110:        }
        !           111:
        !           112:        if (basep != 0)
        !           113:                *basep = PCI_MAPREG_IO_ADDR(address);
        !           114:        if (sizep != 0)
        !           115:                *sizep = PCI_MAPREG_IO_SIZE(mask);
        !           116:        if (flagsp != 0)
        !           117:                *flagsp = 0;
        !           118:
        !           119:        return (0);
        !           120: }
        !           121:
        !           122: int
        !           123: obsd_pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
        !           124:     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
        !           125: {
        !           126:        pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff, csr;
        !           127:        u_int64_t waddress, wmask;
        !           128:        int s, is64bit;
        !           129:
        !           130:        is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
        !           131:
        !           132:        if (reg < PCI_MAPREG_START ||
        !           133: #if 0
        !           134:            /*
        !           135:             * Can't do this check; some devices have mapping registers
        !           136:             * way out in left field.
        !           137:             */
        !           138:            reg >= PCI_MAPREG_END ||
        !           139: #endif
        !           140:            (reg & 3))
        !           141:                panic("pci_mem_find: bad request");
        !           142:
        !           143:        if (is64bit && (reg + 4) >= PCI_MAPREG_END)
        !           144:                panic("pci_mem_find: bad 64-bit request");
        !           145:
        !           146:        /*
        !           147:         * Section 6.2.5.1, `Address Maps', tells us that:
        !           148:         *
        !           149:         * 1) The builtin software should have already mapped the device in a
        !           150:         * reasonable way.
        !           151:         *
        !           152:         * 2) A device which wants 2^n bytes of memory will hardwire the bottom
        !           153:         * n bits of the address to 0.  As recommended, we write all 1s while
        !           154:         * the device is disabled and see what we get back.
        !           155:         */
        !           156:        s = splhigh();
        !           157:        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        !           158:        if (csr & PCI_COMMAND_MEM_ENABLE)
        !           159:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
        !           160:                    csr & ~PCI_COMMAND_MEM_ENABLE);
        !           161:        address = pci_conf_read(pc, tag, reg);
        !           162:        pci_conf_write(pc, tag, reg, 0xffffffff);
        !           163:        mask = pci_conf_read(pc, tag, reg);
        !           164:        pci_conf_write(pc, tag, reg, address);
        !           165:        if (is64bit) {
        !           166:                address1 = pci_conf_read(pc, tag, reg + 4);
        !           167:                pci_conf_write(pc, tag, reg + 4, 0xffffffff);
        !           168:                mask1 = pci_conf_read(pc, tag, reg + 4);
        !           169:                pci_conf_write(pc, tag, reg + 4, address1);
        !           170:        }
        !           171:        if (csr & PCI_COMMAND_MEM_ENABLE)
        !           172:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
        !           173:        splx(s);
        !           174:
        !           175:        if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
        !           176: #ifdef DEBUG
        !           177:                printf("pci_mem_find: expected type mem, found i/o\n");
        !           178: #endif
        !           179:                return (EINVAL);
        !           180:        }
        !           181:        if (type != -1 &&
        !           182:            PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
        !           183: #ifdef DEBUG
        !           184:                printf("pci_mem_find: expected mem type %08x, found %08x\n",
        !           185:                    PCI_MAPREG_MEM_TYPE(type),
        !           186:                    PCI_MAPREG_MEM_TYPE(address));
        !           187: #endif
        !           188:                return (EINVAL);
        !           189:        }
        !           190:
        !           191:        waddress = (u_int64_t)address1 << 32UL | address;
        !           192:        wmask = (u_int64_t)mask1 << 32UL | mask;
        !           193:
        !           194:        if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) ||
        !           195:            (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) {
        !           196: #ifdef DEBUG
        !           197:                printf("pci_mem_find: void region\n");
        !           198: #endif
        !           199:                return (ENOENT);
        !           200:        }
        !           201:
        !           202:        switch (PCI_MAPREG_MEM_TYPE(address)) {
        !           203:        case PCI_MAPREG_MEM_TYPE_32BIT:
        !           204:        case PCI_MAPREG_MEM_TYPE_32BIT_1M:
        !           205:                break;
        !           206:        case PCI_MAPREG_MEM_TYPE_64BIT:
        !           207:                /*
        !           208:                 * Handle the case of a 64-bit memory register on a
        !           209:                 * platform with 32-bit addressing.  Make sure that
        !           210:                 * the address assigned and the device's memory size
        !           211:                 * fit in 32 bits.  We implicitly assume that if
        !           212:                 * bus_addr_t is 64-bit, then so is bus_size_t.
        !           213:                 */
        !           214:                if (sizeof(u_int64_t) > sizeof(bus_addr_t) &&
        !           215:                    (address1 != 0 || mask1 != 0xffffffff)) {
        !           216: #ifdef DEBUG
        !           217:                        printf("pci_mem_find: 64-bit memory map which is "
        !           218:                            "inaccessible on a 32-bit platform\n");
        !           219: #endif
        !           220:                        return (EINVAL);
        !           221:                }
        !           222:                break;
        !           223:        default:
        !           224: #ifdef DEBUG
        !           225:                printf("pci_mem_find: reserved mapping register type\n");
        !           226: #endif
        !           227:                return (EINVAL);
        !           228:        }
        !           229:
        !           230:        if (sizeof(u_int64_t) > sizeof(bus_addr_t)) {
        !           231:                if (basep != 0)
        !           232:                        *basep = PCI_MAPREG_MEM_ADDR(address);
        !           233:                if (sizep != 0)
        !           234:                        *sizep = PCI_MAPREG_MEM_SIZE(mask);
        !           235:        } else {
        !           236:                if (basep != 0)
        !           237:                        *basep = PCI_MAPREG_MEM64_ADDR(waddress);
        !           238:                if (sizep != 0)
        !           239:                        *sizep = PCI_MAPREG_MEM64_SIZE(wmask);
        !           240:        }
        !           241:        if (flagsp != 0)
        !           242:                *flagsp =
        !           243: #ifdef BUS_SPACE_MAP_PREFETCHABLE
        !           244:                    PCI_MAPREG_MEM_PREFETCHABLE(address) ?
        !           245:                      BUS_SPACE_MAP_PREFETCHABLE :
        !           246: #endif
        !           247:                  0;
        !           248:
        !           249:        return (0);
        !           250: }
        !           251:
        !           252: int
        !           253: pci_io_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
        !           254:     bus_addr_t *iobasep, bus_size_t *iosizep)
        !           255: {
        !           256:        return (obsd_pci_io_find(pc, pcitag, reg, 0, iobasep, iosizep, 0));
        !           257: }
        !           258:
        !           259: int
        !           260: pci_mem_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
        !           261:     bus_addr_t *membasep, bus_size_t *memsizep, int *cacheablep)
        !           262: {
        !           263:        return (obsd_pci_mem_find(pc, pcitag, reg, -1, membasep, memsizep,
        !           264:                                  cacheablep));
        !           265: }
        !           266:
        !           267: pcireg_t
        !           268: pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg)
        !           269: {
        !           270:        return (_PCI_MAPREG_TYPEBITS(pci_conf_read(pc, tag, reg)));
        !           271: }
        !           272:
        !           273: int
        !           274: pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
        !           275: {
        !           276:        pcireg_t address, mask, csr;
        !           277:        int s;
        !           278:
        !           279:        s = splhigh();
        !           280:        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        !           281:        if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
        !           282:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
        !           283:                    ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));
        !           284:        address = pci_conf_read(pc, tag, reg);
        !           285:        pci_conf_write(pc, tag, reg, 0xffffffff);
        !           286:        mask = pci_conf_read(pc, tag, reg);
        !           287:        pci_conf_write(pc, tag, reg, address);
        !           288:        if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
        !           289:                pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
        !           290:        splx(s);
        !           291:
        !           292:        if (mask == 0) /* unimplemented mapping register */
        !           293:                return (0);
        !           294:
        !           295:        if (typep)
        !           296:                *typep = _PCI_MAPREG_TYPEBITS(address);
        !           297:        return (1);
        !           298: }
        !           299:
        !           300: int
        !           301: pci_mapreg_info(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
        !           302:     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
        !           303: {
        !           304:
        !           305:        if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
        !           306:                return (obsd_pci_io_find(pc, tag, reg, type, basep, sizep,
        !           307:                    flagsp));
        !           308:        else
        !           309:                return (obsd_pci_mem_find(pc, tag, reg, type, basep, sizep,
        !           310:                    flagsp));
        !           311: }
        !           312:
        !           313: int
        !           314: pci_mapreg_map(struct pci_attach_args *pa, int reg, pcireg_t type, int busflags,
        !           315:     bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep,
        !           316:     bus_size_t *sizep, bus_size_t maxsize)
        !           317: {
        !           318:        bus_space_tag_t tag;
        !           319:        bus_space_handle_t handle;
        !           320:        bus_addr_t base;
        !           321:        bus_size_t size;
        !           322:        pcireg_t csr;
        !           323:        int flags;
        !           324:        int rv;
        !           325:
        !           326:        if ((rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type,
        !           327:            &base, &size, &flags)) != 0)
        !           328:                return (rv);
        !           329:        if (base == 0)
        !           330:                return (EINVAL);        /* disabled because of invalid BAR */
        !           331:
        !           332:        csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
        !           333:        if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
        !           334:                csr |= PCI_COMMAND_IO_ENABLE;
        !           335:        else
        !           336:                csr |= PCI_COMMAND_MEM_ENABLE;
        !           337:        /* XXX Should this only be done for devices that do DMA?  */
        !           338:        csr |= PCI_COMMAND_MASTER_ENABLE;
        !           339:        pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
        !           340:
        !           341:        if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
        !           342:                if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0)
        !           343:                        return (EINVAL);
        !           344:                tag = pa->pa_iot;
        !           345:        } else {
        !           346:                if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) == 0)
        !           347:                        return (EINVAL);
        !           348:                tag = pa->pa_memt;
        !           349:        }
        !           350:
        !           351:        /* The caller can request limitation of the mapping's size. */
        !           352:        if (maxsize != 0 && size > maxsize) {
        !           353: #ifdef DEBUG
        !           354:                printf("pci_mapreg_map: limited PCI mapping from %lx to %lx\n",
        !           355:                    (u_long)size, (u_long)maxsize);
        !           356: #endif
        !           357:                size = maxsize;
        !           358:        }
        !           359:
        !           360:        if (bus_space_map(tag, base, size, busflags | flags, &handle))
        !           361:                return (1);
        !           362:
        !           363:        if (tagp != NULL)
        !           364:                *tagp = tag;
        !           365:        if (handlep != NULL)
        !           366:                *handlep = handle;
        !           367:        if (basep != NULL)
        !           368:                *basep = base;
        !           369:        if (sizep != NULL)
        !           370:                *sizep = size;
        !           371:
        !           372:        return (0);
        !           373: }

CVSweb