Annotation of qemu/hw/pci_bridge.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU PCI bus manager
        !             3:  *
        !             4:  * Copyright (c) 2004 Fabrice Bellard
        !             5:  *
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !             7:  * of this software and associated documentation files (the "Software"), to dea
        !             8: 
        !             9:  * in the Software without restriction, including without limitation the rights
        !            10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            11:  * copies of the Software, and to permit persons to whom the Software is
        !            12:  * furnished to do so, subject to the following conditions:
        !            13:  *
        !            14:  * The above copyright notice and this permission notice shall be included in
        !            15:  * all copies or substantial portions of the Software.
        !            16:  *
        !            17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
        !            22: 
        !            23:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            24:  * THE SOFTWARE.
        !            25:  */
        !            26: /*
        !            27:  * split out from pci.c
        !            28:  * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
        !            29:  *                    VA Linux Systems Japan K.K.
        !            30:  */
        !            31: 
        !            32: #include "pci_bridge.h"
        !            33: #include "pci_internals.h"
        !            34: #include "range.h"
        !            35: 
        !            36: /* PCI bridge subsystem vendor ID helper functions */
        !            37: #define PCI_SSVID_SIZEOF        8
        !            38: #define PCI_SSVID_SVID          4
        !            39: #define PCI_SSVID_SSID          6
        !            40: 
        !            41: int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
        !            42:                           uint16_t svid, uint16_t ssid)
        !            43: {
        !            44:     int pos;
        !            45:     pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF);
        !            46:     if (pos < 0) {
        !            47:         return pos;
        !            48:     }
        !            49: 
        !            50:     pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
        !            51:     pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
        !            52:     return pos;
        !            53: }
        !            54: 
        !            55: /* Accessor function to get parent bridge device from pci bus. */
        !            56: PCIDevice *pci_bridge_get_device(PCIBus *bus)
        !            57: {
        !            58:     return bus->parent_dev;
        !            59: }
        !            60: 
        !            61: /* Accessor function to get secondary bus from pci-to-pci bridge device */
        !            62: PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
        !            63: {
        !            64:     return &br->sec_bus;
        !            65: }
        !            66: 
        !            67: static uint32_t pci_config_get_io_base(const PCIDevice *d,
        !            68:                                        uint32_t base, uint32_t base_upper16)
        !            69: {
        !            70:     uint32_t val;
        !            71: 
        !            72:     val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
        !            73:     if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
        !            74:         val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
        !            75:     }
        !            76:     return val;
        !            77: }
        !            78: 
        !            79: static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
        !            80: {
        !            81:     return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
        !            82:         << 16;
        !            83: }
        !            84: 
        !            85: static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
        !            86:                                          uint32_t base, uint32_t upper)
        !            87: {
        !            88:     pcibus_t tmp;
        !            89:     pcibus_t val;
        !            90: 
        !            91:     tmp = (pcibus_t)pci_get_word(d->config + base);
        !            92:     val = (tmp & PCI_PREF_RANGE_MASK) << 16;
        !            93:     if (tmp & PCI_PREF_RANGE_TYPE_64) {
        !            94:         val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
        !            95:     }
        !            96:     return val;
        !            97: }
        !            98: 
        !            99: /* accessor function to get bridge filtering base address */
        !           100: pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
        !           101: {
        !           102:     pcibus_t base;
        !           103:     if (type & PCI_BASE_ADDRESS_SPACE_IO) {
        !           104:         base = pci_config_get_io_base(bridge,
        !           105:                                       PCI_IO_BASE, PCI_IO_BASE_UPPER16);
        !           106:     } else {
        !           107:         if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
        !           108:             base = pci_config_get_pref_base(
        !           109:                 bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
        !           110:         } else {
        !           111:             base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
        !           112:         }
        !           113:     }
        !           114: 
        !           115:     return base;
        !           116: }
        !           117: 
        !           118: /* accessor funciton to get bridge filtering limit */
        !           119: pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
        !           120: {
        !           121:     pcibus_t limit;
        !           122:     if (type & PCI_BASE_ADDRESS_SPACE_IO) {
        !           123:         limit = pci_config_get_io_base(bridge,
        !           124:                                       PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
        !           125:         limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
        !           126:     } else {
        !           127:         if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
        !           128:             limit = pci_config_get_pref_base(
        !           129:                 bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
        !           130:         } else {
        !           131:             limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
        !           132:         }
        !           133:         limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
        !           134:     }
        !           135:     return limit;
        !           136: }
        !           137: 
        !           138: /* default write_config function for PCI-to-PCI bridge */
        !           139: void pci_bridge_write_config(PCIDevice *d,
        !           140:                              uint32_t address, uint32_t val, int len)
        !           141: {
        !           142:     PCIBridge *s = container_of(d, PCIBridge, dev);
        !           143:     uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
        !           144:     uint16_t newctl;
        !           145: 
        !           146:     pci_default_write_config(d, address, val, len);
        !           147: 
        !           148:     if (/* io base/limit */
        !           149:         ranges_overlap(address, len, PCI_IO_BASE, 2) ||
        !           150: 
        !           151:         /* memory base/limit, prefetchable base/limit and
        !           152:            io base/limit upper 16 */
        !           153:         ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
        !           154:         pci_bridge_update_mappings(&s->sec_bus);
        !           155:     }
        !           156: 
        !           157:     newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
        !           158:     if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) {
        !           159:         /* Trigger hot reset on 0->1 transition. */
        !           160:         pci_bus_reset(&s->sec_bus);
        !           161:     }
        !           162: }
        !           163: 
        !           164: void pci_bridge_disable_base_limit(PCIDevice *dev)
        !           165: {
        !           166:     uint8_t *conf = dev->config;
        !           167: 
        !           168:     pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
        !           169:                                PCI_IO_RANGE_MASK & 0xff);
        !           170:     pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
        !           171:                                  PCI_IO_RANGE_MASK & 0xff);
        !           172:     pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
        !           173:                                PCI_MEMORY_RANGE_MASK & 0xffff);
        !           174:     pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
        !           175:                                  PCI_MEMORY_RANGE_MASK & 0xffff);
        !           176:     pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
        !           177:                                PCI_PREF_RANGE_MASK & 0xffff);
        !           178:     pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
        !           179:                                  PCI_PREF_RANGE_MASK & 0xffff);
        !           180:     pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
        !           181:     pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
        !           182: }
        !           183: 
        !           184: /* reset bridge specific configuration registers */
        !           185: void pci_bridge_reset_reg(PCIDevice *dev)
        !           186: {
        !           187:     uint8_t *conf = dev->config;
        !           188: 
        !           189:     conf[PCI_PRIMARY_BUS] = 0;
        !           190:     conf[PCI_SECONDARY_BUS] = 0;
        !           191:     conf[PCI_SUBORDINATE_BUS] = 0;
        !           192:     conf[PCI_SEC_LATENCY_TIMER] = 0;
        !           193: 
        !           194:     /*
        !           195:      * the default values for base/limit registers aren't specified
        !           196:      * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
        !           197:      * Each implementation can override it.
        !           198:      * typical implementation does
        !           199:      * zero base/limit registers or
        !           200:      * disable forwarding: pci_bridge_disable_base_limit()
        !           201:      * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
        !           202:      * after this function.
        !           203:      */
        !           204:     pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
        !           205:                                  PCI_IO_RANGE_MASK & 0xff);
        !           206:     pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
        !           207:                                  PCI_IO_RANGE_MASK & 0xff);
        !           208:     pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
        !           209:                                  PCI_MEMORY_RANGE_MASK & 0xffff);
        !           210:     pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
        !           211:                                  PCI_MEMORY_RANGE_MASK & 0xffff);
        !           212:     pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
        !           213:                                  PCI_PREF_RANGE_MASK & 0xffff);
        !           214:     pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
        !           215:                                  PCI_PREF_RANGE_MASK & 0xffff);
        !           216:     pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
        !           217:     pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
        !           218: 
        !           219:     pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
        !           220: }
        !           221: 
        !           222: /* default reset function for PCI-to-PCI bridge */
        !           223: void pci_bridge_reset(DeviceState *qdev)
        !           224: {
        !           225:     PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
        !           226:     pci_bridge_reset_reg(dev);
        !           227: }
        !           228: 
        !           229: /* default qdev initialization function for PCI-to-PCI bridge */
        !           230: int pci_bridge_initfn(PCIDevice *dev)
        !           231: {
        !           232:     PCIBus *parent = dev->bus;
        !           233:     PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
        !           234:     PCIBus *sec_bus = &br->sec_bus;
        !           235: 
        !           236:     pci_set_word(dev->config + PCI_STATUS,
        !           237:                  PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
        !           238:     pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
        !           239:     dev->config[PCI_HEADER_TYPE] =
        !           240:         (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
        !           241:         PCI_HEADER_TYPE_BRIDGE;
        !           242:     pci_set_word(dev->config + PCI_SEC_STATUS,
        !           243:                  PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
        !           244: 
        !           245:     qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
        !           246:                         br->bus_name);
        !           247:     sec_bus->parent_dev = dev;
        !           248:     sec_bus->map_irq = br->map_irq;
        !           249: 
        !           250:     QLIST_INIT(&sec_bus->child);
        !           251:     QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
        !           252:     return 0;
        !           253: }
        !           254: 
        !           255: /* default qdev clean up function for PCI-to-PCI bridge */
        !           256: int pci_bridge_exitfn(PCIDevice *pci_dev)
        !           257: {
        !           258:     PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
        !           259:     assert(QLIST_EMPTY(&s->sec_bus.child));
        !           260:     QLIST_REMOVE(&s->sec_bus, sibling);
        !           261:     /* qbus_free() is called automatically by qdev_free() */
        !           262:     return 0;
        !           263: }
        !           264: 
        !           265: /*
        !           266:  * before qdev initialization(qdev_init()), this function sets bus_name and
        !           267:  * map_irq callback which are necessry for pci_bridge_initfn() to
        !           268:  * initialize bus.
        !           269:  */
        !           270: void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
        !           271:                         pci_map_irq_fn map_irq)
        !           272: {
        !           273:     br->map_irq = map_irq;
        !           274:     br->bus_name = bus_name;
        !           275: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.