Statistics
| Branch: | Revision:

root / hw / pci_bridge.c @ 51a92333

History | View | Annotate | Download (6.2 kB)

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

    
35
PCIDevice *pci_bridge_get_device(PCIBus *bus)
36
{
37
    return bus->parent_dev;
38
}
39

    
40
static uint32_t pci_config_get_io_base(PCIDevice *d,
41
                                       uint32_t base, uint32_t base_upper16)
42
{
43
    uint32_t val;
44

    
45
    val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
46
    if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
47
        val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
48
    }
49
    return val;
50
}
51

    
52
static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
53
{
54
    return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
55
        << 16;
56
}
57

    
58
static pcibus_t pci_config_get_pref_base(PCIDevice *d,
59
                                         uint32_t base, uint32_t upper)
60
{
61
    pcibus_t tmp;
62
    pcibus_t val;
63

    
64
    tmp = (pcibus_t)pci_get_word(d->config + base);
65
    val = (tmp & PCI_PREF_RANGE_MASK) << 16;
66
    if (tmp & PCI_PREF_RANGE_TYPE_64) {
67
        val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
68
    }
69
    return val;
70
}
71

    
72
pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
73
{
74
    pcibus_t base;
75
    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
76
        base = pci_config_get_io_base(bridge,
77
                                      PCI_IO_BASE, PCI_IO_BASE_UPPER16);
78
    } else {
79
        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
80
            base = pci_config_get_pref_base(
81
                bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
82
        } else {
83
            base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
84
        }
85
    }
86

    
87
    return base;
88
}
89

    
90
pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
91
{
92
    pcibus_t limit;
93
    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
94
        limit = pci_config_get_io_base(bridge,
95
                                      PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
96
        limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
97
    } else {
98
        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
99
            limit = pci_config_get_pref_base(
100
                bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
101
        } else {
102
            limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
103
        }
104
        limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
105
    }
106
    return limit;
107
}
108

    
109
static void pci_bridge_write_config(PCIDevice *d,
110
                             uint32_t address, uint32_t val, int len)
111
{
112
    pci_default_write_config(d, address, val, len);
113

    
114
    if (/* io base/limit */
115
        ranges_overlap(address, len, PCI_IO_BASE, 2) ||
116

    
117
        /* memory base/limit, prefetchable base/limit and
118
           io base/limit upper 16 */
119
        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
120
        PCIBridge *s = container_of(d, PCIBridge, dev);
121
        pci_bridge_update_mappings(&s->sec_bus);
122
    }
123
}
124

    
125
static int pci_bridge_initfn(PCIDevice *dev)
126
{
127
    PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
128

    
129
    pci_config_set_vendor_id(s->dev.config, s->vid);
130
    pci_config_set_device_id(s->dev.config, s->did);
131

    
132
    pci_set_word(dev->config + PCI_STATUS,
133
                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
134
    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
135
    dev->config[PCI_HEADER_TYPE] =
136
        (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
137
        PCI_HEADER_TYPE_BRIDGE;
138
    pci_set_word(dev->config + PCI_SEC_STATUS,
139
                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
140
    return 0;
141
}
142

    
143
static int pci_bridge_exitfn(PCIDevice *pci_dev)
144
{
145
    PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
146
    assert(QLIST_EMPTY(&s->sec_bus.child));
147
    QLIST_REMOVE(&s->sec_bus, sibling);
148
    return 0;
149
}
150

    
151
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
152
                        uint16_t vid, uint16_t did,
153
                        pci_map_irq_fn map_irq, const char *name)
154
{
155
    PCIDevice *dev;
156
    PCIBridge *s;
157
    PCIBus *sec_bus;
158

    
159
    dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
160
    qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
161
    qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
162
    qdev_init_nofail(&dev->qdev);
163

    
164
    s = DO_UPCAST(PCIBridge, dev, dev);
165
    sec_bus = &s->sec_bus;
166
    qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev, name);
167
    sec_bus->parent_dev = dev;
168
    sec_bus->map_irq = map_irq;
169

    
170
    QLIST_INIT(&sec_bus->child);
171
    QLIST_INSERT_HEAD(&bus->child, sec_bus, sibling);
172
    return &s->sec_bus;
173
}
174

    
175
static PCIDeviceInfo bridge_info = {
176
    .qdev.name    = "pci-bridge",
177
    .qdev.size    = sizeof(PCIBridge),
178
    .init         = pci_bridge_initfn,
179
    .exit         = pci_bridge_exitfn,
180
    .config_write = pci_bridge_write_config,
181
    .is_bridge    = 1,
182
    .qdev.props   = (Property[]) {
183
        DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
184
        DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
185
        DEFINE_PROP_END_OF_LIST(),
186
    }
187
};
188

    
189
static void pci_register_devices(void)
190
{
191
    pci_qdev_register(&bridge_info);
192
}
193

    
194
device_init(pci_register_devices)