Statistics
| Branch: | Revision:

root / hw / pci_bridge.c @ 783753fd

History | View | Annotate | Download (6.6 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 void pci_register_secondary_bus(PCIBus *parent,
41
                                       PCIBus *bus,
42
                                       PCIDevice *dev,
43
                                       pci_map_irq_fn map_irq,
44
                                       const char *name)
45
{
46
    qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);
47
    bus->map_irq = map_irq;
48
    bus->parent_dev = dev;
49

    
50
    QLIST_INIT(&bus->child);
51
    QLIST_INSERT_HEAD(&parent->child, bus, sibling);
52
}
53

    
54
static void pci_unregister_secondary_bus(PCIBus *bus)
55
{
56
    assert(QLIST_EMPTY(&bus->child));
57
    QLIST_REMOVE(bus, sibling);
58
}
59

    
60
static uint32_t pci_config_get_io_base(PCIDevice *d,
61
                                       uint32_t base, uint32_t base_upper16)
62
{
63
    uint32_t val;
64

    
65
    val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
66
    if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
67
        val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
68
    }
69
    return val;
70
}
71

    
72
static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
73
{
74
    return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
75
        << 16;
76
}
77

    
78
static pcibus_t pci_config_get_pref_base(PCIDevice *d,
79
                                         uint32_t base, uint32_t upper)
80
{
81
    pcibus_t tmp;
82
    pcibus_t val;
83

    
84
    tmp = (pcibus_t)pci_get_word(d->config + base);
85
    val = (tmp & PCI_PREF_RANGE_MASK) << 16;
86
    if (tmp & PCI_PREF_RANGE_TYPE_64) {
87
        val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
88
    }
89
    return val;
90
}
91

    
92
pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
93
{
94
    pcibus_t base;
95
    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
96
        base = pci_config_get_io_base(bridge,
97
                                      PCI_IO_BASE, PCI_IO_BASE_UPPER16);
98
    } else {
99
        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
100
            base = pci_config_get_pref_base(
101
                bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
102
        } else {
103
            base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
104
        }
105
    }
106

    
107
    return base;
108
}
109

    
110
pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
111
{
112
    pcibus_t limit;
113
    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
114
        limit = pci_config_get_io_base(bridge,
115
                                      PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
116
        limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
117
    } else {
118
        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
119
            limit = pci_config_get_pref_base(
120
                bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
121
        } else {
122
            limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
123
        }
124
        limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
125
    }
126
    return limit;
127
}
128

    
129
static void pci_bridge_write_config(PCIDevice *d,
130
                             uint32_t address, uint32_t val, int len)
131
{
132
    pci_default_write_config(d, address, val, len);
133

    
134
    if (/* io base/limit */
135
        ranges_overlap(address, len, PCI_IO_BASE, 2) ||
136

    
137
        /* memory base/limit, prefetchable base/limit and
138
           io base/limit upper 16 */
139
        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
140
        PCIBridge *s = container_of(d, PCIBridge, dev);
141
        PCIBus *secondary_bus = &s->bus;
142
        pci_bridge_update_mappings(secondary_bus);
143
    }
144
}
145

    
146
static int pci_bridge_initfn(PCIDevice *dev)
147
{
148
    PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
149

    
150
    pci_config_set_vendor_id(s->dev.config, s->vid);
151
    pci_config_set_device_id(s->dev.config, s->did);
152

    
153
    pci_set_word(dev->config + PCI_STATUS,
154
                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
155
    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
156
    dev->config[PCI_HEADER_TYPE] =
157
        (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
158
        PCI_HEADER_TYPE_BRIDGE;
159
    pci_set_word(dev->config + PCI_SEC_STATUS,
160
                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
161
    return 0;
162
}
163

    
164
static int pci_bridge_exitfn(PCIDevice *pci_dev)
165
{
166
    PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
167
    PCIBus *bus = &s->bus;
168
    pci_unregister_secondary_bus(bus);
169
    return 0;
170
}
171

    
172
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
173
                        uint16_t vid, uint16_t did,
174
                        pci_map_irq_fn map_irq, const char *name)
175
{
176
    PCIDevice *dev;
177
    PCIBridge *s;
178

    
179
    dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
180
    qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
181
    qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
182
    qdev_init_nofail(&dev->qdev);
183

    
184
    s = DO_UPCAST(PCIBridge, dev, dev);
185
    pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);
186
    return &s->bus;
187
}
188

    
189
static PCIDeviceInfo bridge_info = {
190
    .qdev.name    = "pci-bridge",
191
    .qdev.size    = sizeof(PCIBridge),
192
    .init         = pci_bridge_initfn,
193
    .exit         = pci_bridge_exitfn,
194
    .config_write = pci_bridge_write_config,
195
    .is_bridge    = 1,
196
    .qdev.props   = (Property[]) {
197
        DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
198
        DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
199
        DEFINE_PROP_END_OF_LIST(),
200
    }
201
};
202

    
203
static void pci_register_devices(void)
204
{
205
    pci_qdev_register(&bridge_info);
206
}
207

    
208
device_init(pci_register_devices)