18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU PCI bus manager
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2004 Fabrice Bellard
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions:
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software.
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE.
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
249b3a4b03315af9bcdf282243059e8fd1ce1c5c70David 'Digit' Turner#include "cpu.h"
252ec695af7284adbedcdbc08a22d818b6bdd8990cDavid 'Digit' Turner#include "hw/hw.h"
261df27bbd7f76c5c6ea0dfbbe9eaf1add8e374257David 'Digit' Turner#include "hw/pci/pci.h"
276af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h"
28cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "net/net.h"
2934c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h"
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_PCI
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct PCIBus {
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BusState qbus;
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int bus_num;
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int devfn_min;
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_set_irq_fn set_irq;
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_map_irq_fn map_irq;
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t config_reg; /* XXX: suppress */
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* low level pic */
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    SetIRQFunc *low_set_irq;
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_irq *irq_opaque;
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice *devices[256];
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice *parent_dev;
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *next;
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* The bus IRQ state is the logical OR of the connected devices.
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       Keep a count of the number of devices with raised IRQs.  */
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int nirq;
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int irq_count[];
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_update_mappings(PCIDevice *d);
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_set_irq(void *opaque, int irq_num, int level);
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
55bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerhwaddr pci_mem_base;
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic PCIBus *first_bus;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pcibus_save(QEMUFile *f, void *opaque)
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus = (PCIBus *)opaque;
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_be32(f, bus->nirq);
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < bus->nirq; i++)
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, bus->irq_count[i]);
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int  pcibus_load(QEMUFile *f, void *opaque, int version_id)
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus = (PCIBus *)opaque;
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, nirq;
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id != 1)
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -EINVAL;
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nirq = qemu_get_be32(f);
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (bus->nirq != nirq) {
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n",
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                nirq, bus->nirq);
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -EINVAL;
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < nirq; i++)
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bus->irq_count[i] = qemu_get_be32(f);
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIBus *pci_register_bus(DeviceState *parent, const char *name,
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                         qemu_irq *pic, int devfn_min, int nirq)
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus;
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    static int nbus = 0;
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI,
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                        sizeof(PCIBus) + (nirq * sizeof(int)),
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                        parent, name));
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->set_irq = set_irq;
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->map_irq = map_irq;
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->irq_opaque = pic;
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->devfn_min = devfn_min;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->nirq = nirq;
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bus->next = first_bus;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    first_bus = bus;
1085cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner    register_savevm(NULL, "PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return bus;
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq)
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus;
115aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    bus = g_malloc0(sizeof(PCIBus));
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->map_irq = map_irq;
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->parent_dev = dev;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->next = dev->bus->next;
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->bus->next = bus;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return bus;
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint pci_bus_num(PCIBus *s)
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return s->bus_num;
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_device_save(PCIDevice *s, QEMUFile *f)
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_be32(f, 2); /* PCI device version */
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_buffer(f, s->config, 256);
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 4; i++)
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->irq_state[i]);
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint pci_device_load(PCIDevice *s, QEMUFile *f)
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t version_id;
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    version_id = qemu_get_be32(f);
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id > 2)
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -EINVAL;
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_buffer(f, s->config, 256);
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_update_mappings(s);
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id >= 2)
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 4; i ++)
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->irq_state[i] = qemu_get_be32(f);
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pci_set_default_subsystem_id(PCIDevice *pci_dev)
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint16_t *id;
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    id = (void*)(&pci_dev->config[PCI_SUBVENDOR_ID]);
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    id[0] = cpu_to_le16(pci_default_sub_vendor_id);
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    id[1] = cpu_to_le16(pci_default_sub_device_id);
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p;
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *e;
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned long val;
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned long dom = 0, bus = 0;
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned slot = 0;
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = addr;
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    val = strtoul(p, &e, 16);
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (e == p)
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*e == ':') {
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	bus = val;
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	p = e + 1;
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	val = strtoul(p, &e, 16);
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (e == p)
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    return -1;
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (*e == ':') {
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    dom = bus;
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    bus = val;
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    p = e + 1;
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    val = strtoul(p, &e, 16);
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (e == p)
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return -1;
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dom > 0xffff || bus > 0xff || val > 0x1f)
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slot = val;
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*e)
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Note: QEMU doesn't implement domains other than 0 */
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dom != 0 || pci_find_bus(bus) == NULL)
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *domp = dom;
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *busp = bus;
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *slotp = slot;
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint pci_read_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char devaddr[32];
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!get_param_value(devaddr, sizeof(devaddr), "pci_addr", addr))
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return pci_parse_devaddr(devaddr, domp, busp, slotp);
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char devaddr[32];
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!get_param_value(devaddr, sizeof(devaddr), "pci_addr", addr))
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(devaddr, "auto")) {
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *domp = *busp = 0;
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *slotp = -1;
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* want to support dom/bus auto-assign at some point */
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return pci_parse_devaddr(devaddr, domp, busp, slotp);
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* -1 for devfn means auto assign */
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                         const char *name, int devfn,
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                         PCIConfigReadFunc *config_read,
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                         PCIConfigWriteFunc *config_write)
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (devfn < 0) {
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (!bus->devices[devfn])
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                goto found;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    found: ;
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->bus = bus;
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->devfn = devfn;
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_set_default_subsystem_id(pci_dev);
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!config_read)
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        config_read = pci_default_read_config;
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!config_write)
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        config_write = pci_default_write_config;
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->config_read = config_read;
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->config_write = config_write;
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->devices[devfn] = pci_dev;
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return pci_dev;
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_register_device(PCIBus *bus, const char *name,
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               int instance_size, int devfn,
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               PCIConfigReadFunc *config_read,
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               PCIConfigWriteFunc *config_write)
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIDevice *pci_dev;
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
280aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    pci_dev = g_malloc0(instance_size);
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     config_read, config_write);
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return pci_dev;
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
285bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic hwaddr pci_to_cpu_addr(hwaddr addr)
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return addr + pci_mem_base;
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pci_unregister_io_regions(PCIDevice *pci_dev)
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIIORegion *r;
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < PCI_NUM_REGIONS; i++) {
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        r = &pci_dev->io_regions[i];
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!r->size || r->addr == -1)
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (r->type == PCI_ADDRESS_SPACE_IO) {
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            isa_unassign_ioport(r->addr, r->size);
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                     r->size,
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                     IO_MEM_UNASSIGNED);
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint pci_unregister_device(PCIDevice *pci_dev)
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret = 0;
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (pci_dev->unregister)
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = pci_dev->unregister(pci_dev);
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret)
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return ret;
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_unregister_io_regions(pci_dev);
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free_irqs(pci_dev->irq);
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_dev->bus->devices[pci_dev->devfn] = NULL;
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qdev_free(&pci_dev->qdev);
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid pci_register_bar(PCIDevice *pci_dev, int region_num,
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            uint32_t size, int type,
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            PCIMapIORegionFunc *map_func)
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIIORegion *r;
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr;
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((unsigned int)region_num >= PCI_NUM_REGIONS)
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size & (size-1)) {
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "ERROR: PCI region size must be pow2 "
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    "type=0x%x, size=0x%x\n", type, size);
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(1);
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = &pci_dev->io_regions[region_num];
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->addr = -1;
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->size = size;
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->type = type;
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->map_func = map_func;
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (region_num == PCI_ROM_SLOT) {
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        addr = 0x30;
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        addr = 0x10 + region_num * 4;
3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
35252ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner    pci_set_long(pci_dev->config + addr, type);
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_update_mappings(PCIDevice *d)
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIIORegion *r;
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cmd, i;
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t last_addr, new_addr, config_ofs;
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
36152ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner    cmd = pci_get_word(d->config + PCI_COMMAND);
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < PCI_NUM_REGIONS; i++) {
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r = &d->io_regions[i];
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (i == PCI_ROM_SLOT) {
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            config_ofs = 0x30;
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            config_ofs = 0x10 + i * 4;
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (r->size != 0) {
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (r->type & PCI_ADDRESS_SPACE_IO) {
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (cmd & PCI_COMMAND_IO) {
37252ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner                    new_addr = pci_get_long(d->config + config_ofs);
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    new_addr = new_addr & ~(r->size - 1);
3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    last_addr = new_addr + r->size - 1;
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    /* NOTE: we have only 64K ioports on PC */
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    if (last_addr <= new_addr || new_addr == 0 ||
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        last_addr >= 0x10000) {
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        new_addr = -1;
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    }
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                } else {
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    new_addr = -1;
3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (cmd & PCI_COMMAND_MEMORY) {
38552ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner                    new_addr = pci_get_long(d->config + config_ofs);
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    /* the ROM slot has a specific enable bit */
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    if (i == PCI_ROM_SLOT && !(new_addr & 1))
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        goto no_mem_map;
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    new_addr = new_addr & ~(r->size - 1);
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    last_addr = new_addr + r->size - 1;
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    /* NOTE: we do not support wrapping */
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    /* XXX: as we cannot support really dynamic
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                       mappings, we handle specific values as invalid
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                       mappings. */
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    if (last_addr <= new_addr || new_addr == 0 ||
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        last_addr == -1) {
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        new_addr = -1;
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    }
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                } else {
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                no_mem_map:
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    new_addr = -1;
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* now do the real mapping */
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (new_addr != r->addr) {
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (r->addr != -1) {
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    if (r->type & PCI_ADDRESS_SPACE_IO) {
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        int class;
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        /* NOTE: specific hack for IDE in PC case:
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           only one byte must be mapped. */
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        class = d->config[0x0a] | (d->config[0x0b] << 8);
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        if (class == 0x0101 && r->size == 4) {
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            isa_unassign_ioport(r->addr + 2, 1);
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        } else {
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            isa_unassign_ioport(r->addr, r->size);
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        }
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    } else {
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                                     r->size,
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                                     IO_MEM_UNASSIGNED);
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        qemu_unregister_coalesced_mmio(r->addr, r->size);
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    }
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                r->addr = new_addr;
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (r->addr != -1) {
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    r->map_func(d, i, r->addr, r->size, r->type);
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectuint32_t pci_default_read_config(PCIDevice *d,
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                 uint32_t address, int len)
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t val;
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch(len) {
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 4:
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (address <= 0xfc) {
44252ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner	    val = pci_get_long(d->config + address);
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    break;
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* fall through */
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 2:
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (address <= 0xfe) {
44852ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner	    val = pci_get_word(d->config + address);
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    break;
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* fall through */
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 1:
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = d->config[address];
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return val;
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_default_write_config(PCIDevice *d,
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              uint32_t address, uint32_t val, int len)
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int can_write, i;
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t end, addr;
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                     (address >= 0x30 && address < 0x34))) {
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        PCIIORegion *r;
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int reg;
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ( address >= 0x30 ) {
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            reg = PCI_ROM_SLOT;
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }else{
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            reg = (address - 0x10) >> 2;
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r = &d->io_regions[reg];
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (r->size == 0)
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto default_config;
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* compute the stored value */
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (reg == PCI_ROM_SLOT) {
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* keep ROM enable bit */
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val &= (~(r->size - 1)) | 1;
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val &= ~(r->size - 1);
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val |= r->type;
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
48652ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner        pci_set_long(d->config + address, val);
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pci_update_mappings(d);
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default_config:
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* not efficient, but simple */
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    addr = address;
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < len; i++) {
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* default read/write accesses */
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        switch(d->config[0x0e]) {
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 0x00:
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 0x80:
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch(addr) {
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x00:
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x01:
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x02:
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x03:
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x06:
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x07:
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x08:
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x09:
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x0a:
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x0b:
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x0e:
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x10 ... 0x27: /* base */
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x30 ... 0x33: /* rom */
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x3d:
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                can_write = 0;
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            default:
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                can_write = 1;
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 0x01:
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch(addr) {
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x00:
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x01:
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x02:
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x03:
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x06:
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x07:
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x08:
5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x09:
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x0a:
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x0b:
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x0e:
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x38 ... 0x3b: /* rom */
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x3d:
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                can_write = 0;
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            default:
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                can_write = 1;
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (can_write) {
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Mask out writes to reserved bits in registers */
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            switch (addr) {
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    case 0x05:
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                val &= ~PCI_COMMAND_RESERVED_MASK_HI;
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x06:
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                val &= ~PCI_STATUS_RESERVED_MASK_LO;
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x07:
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                val &= ~PCI_STATUS_RESERVED_MASK_HI;
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->config[addr] = val;
5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (++addr > 0xff)
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        	break;
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val >>= 8;
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    end = address + len;
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* if the command register is modified, we must modify the mappings */
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pci_update_mappings(d);
5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *s = opaque;
5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice *pci_dev;
5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int config_addr, bus_num;
5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) && 0
5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    printf("pci_data_write: addr=%08x val=%08x len=%d\n",
5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           addr, val, len);
5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus_num = (addr >> 16) & 0xff;
5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (s && s->bus_num != bus_num)
5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s = s->next;
5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!s)
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev = s->devices[(addr >> 8) & 0xff];
5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!pci_dev)
5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    config_addr = addr & 0xff;
5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI)
5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           pci_dev->name, config_addr, val, len);
5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->config_write(pci_dev, config_addr, val, len);
5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectuint32_t pci_data_read(void *opaque, uint32_t addr, int len)
6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *s = opaque;
6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice *pci_dev;
6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int config_addr, bus_num;
6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t val;
6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus_num = (addr >> 16) & 0xff;
6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (s && s->bus_num != bus_num)
6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s= s->next;
6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!s)
6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev = s->devices[(addr >> 8) & 0xff];
6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!pci_dev) {
6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fail:
6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        switch(len) {
6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 1:
6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val = 0xff;
6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 2:
6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val = 0xffff;
6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 4:
6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val = 0xffffffff;
6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto the_end;
6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    config_addr = addr & 0xff;
6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val = pci_dev->config_read(pci_dev, config_addr, len);
6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI)
6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           pci_dev->name, config_addr, val, len);
6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project the_end:
6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) && 0
6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    printf("pci_data_read: addr=%08x val=%08x len=%d\n",
6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           addr, val, len);
6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return val;
6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/***********************************************************/
6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* generic PCI irq support */
6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 0 <= irq_num <= 3. level must be 0 or 1 */
6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_set_irq(void *opaque, int irq_num, int level)
6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice *pci_dev = (PCIDevice *)opaque;
6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus;
6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int change;
6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    change = level - pci_dev->irq_state[irq_num];
6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!change)
6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_dev->irq_state[irq_num] = level;
6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (;;) {
6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bus = pci_dev->bus;
6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq_num = bus->map_irq(pci_dev, irq_num);
6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (bus->set_irq)
6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pci_dev = bus->parent_dev;
6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->irq_count[irq_num] += change;
6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/***********************************************************/
6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* monitor info on PCI */
6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t class;
6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *desc;
6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} pci_class_desc;
6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const pci_class_desc pci_class_descriptions[] =
6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0100, "SCSI controller"},
6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0101, "IDE controller"},
6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0102, "Floppy controller"},
6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0103, "IPI controller"},
6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0104, "RAID controller"},
6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0106, "SATA controller"},
6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0107, "SAS controller"},
6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0180, "Storage controller"},
6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0200, "Ethernet controller"},
6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0201, "Token Ring controller"},
6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0202, "FDDI controller"},
6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0203, "ATM controller"},
6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0280, "Network controller"},
6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0300, "VGA controller"},
6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0301, "XGA controller"},
6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0302, "3D controller"},
6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0380, "Display controller"},
6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0400, "Video controller"},
6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0401, "Audio controller"},
6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0402, "Phone"},
6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0480, "Multimedia controller"},
6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0500, "RAM controller"},
7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0501, "Flash controller"},
7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0580, "Memory controller"},
7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0600, "Host bridge"},
7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0601, "ISA bridge"},
7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0602, "EISA bridge"},
7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0603, "MC bridge"},
7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0604, "PCI bridge"},
7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0605, "PCMCIA bridge"},
7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0606, "NUBUS bridge"},
7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0607, "CARDBUS bridge"},
7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0608, "RACEWAY bridge"},
7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0680, "Bridge"},
7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0x0c03, "USB controller"},
7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { 0, NULL}
7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_info_device(PCIDevice *d)
7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    Monitor *mon = cur_mon;
7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, class;
7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIIORegion *r;
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const pci_class_desc *desc;
7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
723a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner    typedef union {
724a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner        uint16_t* ptr16;
725a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner        void* ptr;
726a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner    } u16;
727a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "  Bus %2d, device %3d, function %d:\n",
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
73052ffef3ab8acdde157f1bf2a2933eca62a883ab5David 'Digit' Turner    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "    ");
7328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    desc = pci_class_descriptions;
7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (desc->desc && class != desc->class)
7348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        desc++;
7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (desc->desc) {
7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "%s", desc->desc);
7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "Class %04x", class);
7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
740a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner    u16 vendor_id = { .ptr = d->config + PCI_VENDOR_ID };
741a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner    u16 device_id = { .ptr = d->config + PCI_DEVICE_ID };
742a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner
7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, ": PCI device %04x:%04x\n",
744a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner           le16_to_cpu(*vendor_id.ptr16),
745a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner           le16_to_cpu(*device_id.ptr16));
7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (d->config[PCI_INTERRUPT_PIN] != 0) {
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "      IRQ %d.\n",
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                       d->config[PCI_INTERRUPT_LINE]);
7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (class == 0x0604) {
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "      BUS %d.\n", d->config[0x19]);
7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0;i < PCI_NUM_REGIONS; i++) {
7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r = &d->io_regions[i];
7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (r->size != 0) {
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            monitor_printf(mon, "      BAR%d: ", i);
7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (r->type & PCI_ADDRESS_SPACE_IO) {
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                monitor_printf(mon, "I/O at 0x%04x [0x%04x].\n",
7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               r->addr, r->addr + r->size - 1);
7618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                monitor_printf(mon, "32 bit memory at 0x%08x [0x%08x].\n",
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               r->addr, r->addr + r->size - 1);
7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (class == 0x0604 && d->config[0x19] != 0) {
7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pci_for_each_device(d->config[0x19], pci_info_device);
7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d))
7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus = first_bus;
7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice *d;
7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int devfn;
7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (bus && bus->bus_num != bus_num)
7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bus = bus->next;
7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (bus) {
7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for(devfn = 0; devfn < 256; devfn++) {
7828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d = bus->devices[devfn];
7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (d)
7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                fn(d);
7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid pci_info(Monitor *mon)
7908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
7918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_for_each_device(0, pci_info_device);
7928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char * const pci_nic_models[] = {
7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "ne2k_pci",
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "i82551",
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "i82557b",
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "i82559er",
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "rtl8139",
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "e1000",
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "pcnet",
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "virtio",
8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NULL
8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char * const pci_nic_names[] = {
8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "ne2k_pci",
8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "i82551",
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "i82557b",
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "i82559er",
8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "rtl8139",
8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "e1000",
8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "pcnet",
8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "virtio-net-pci",
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NULL
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Initialize a PCI NIC.  */
8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  const char *default_model)
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DeviceState *dev;
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_check_nic_model_list(nd, pci_nic_models, default_model);
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; pci_nic_models[i]; i++) {
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (strcmp(nd->model, pci_nic_models[i]) == 0) {
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            dev = qdev_create(&bus->qbus, pci_nic_names[i]);
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qdev_set_prop_int(dev, "devfn", devfn);
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qdev_set_netdev(dev, nd);
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qdev_init(dev);
8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            nd->private = dev;
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return (PCIDevice *)dev;
8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
8368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8411befd3440439e8181a31140674e847f2d3e1481eDavid 'Digit' Turnerstruct PCIBridge {
8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice dev;
8438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBus *bus;
8441befd3440439e8181a31140674e847f2d3e1481eDavid 'Digit' Turner};
8458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_bridge_write_config(PCIDevice *d,
8478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                             uint32_t address, uint32_t val, int len)
8488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBridge *s = (PCIBridge *)d;
8508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (address == 0x19 || (address == 0x18 && len > 1)) {
8528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (address == 0x19)
8538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->bus->bus_num = val & 0xff;
8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
8558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->bus->bus_num = (val >> 8) & 0xff;
8568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI)
8578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num);
8588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
8598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pci_default_write_config(d, address, val, len);
8618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIBus *pci_find_bus(int bus_num)
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIBus *bus = first_bus;
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (bus && bus->bus_num != bus_num)
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        bus = bus->next;
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return bus;
8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_find_device(int bus_num, int slot, int function)
8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIBus *bus = pci_find_bus(bus_num);
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!bus)
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return bus->devices[PCI_DEVFN(slot, function)];
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
8848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        pci_map_irq_fn map_irq, const char *name)
8858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIBridge *s;
8878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
8888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                         devfn, NULL, pci_bridge_write_config);
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_config_set_vendor_id(s->dev.config, vid);
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_config_set_device_id(s->dev.config, did);
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x04] = 0x06; // command = bus master, pci mem
8948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x05] = 0x00;
8958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
8968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x07] = 0x00; // status = fast devsel
8978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x08] = 0x00; // revision
8988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x09] = 0x00; // programming i/f
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_config_set_class(s->dev.config, PCI_CLASS_BRIDGE_PCI);
9008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x0D] = 0x10; // latency_timer
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->dev.config[PCI_HEADER_TYPE] =
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type
9038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.config[0x1E] = 0xa0; // secondary status
9048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->bus = pci_register_secondary_bus(&s->dev, map_irq);
9068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return s->bus;
9078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DeviceInfo qdev;
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_qdev_initfn init;
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} PCIDeviceInfo;
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIDevice *pci_dev = (PCIDevice *)qdev;
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIBus *bus;
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int devfn;
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    devfn = qdev_get_prop_int(qdev, "devfn", -1);
9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn,
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     NULL, NULL);//FIXME:config_read, config_write);
9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    assert(pci_dev);
9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    info->init(pci_dev);
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid pci_qdev_register(const char *name, int size, pci_qdev_initfn init)
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PCIDeviceInfo *info;
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
933aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    info = g_malloc0(sizeof(*info));
934aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    info->qdev.name = g_strdup(name);
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    info->qdev.size = size;
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    info->init = init;
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    info->qdev.init = pci_qdev_init;
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    info->qdev.bus_type = BUS_TYPE_PCI;
9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qdev_register(&info->qdev);
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DeviceState *dev;
9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dev = qdev_create(&bus->qbus, name);
9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qdev_set_prop_int(dev, "devfn", devfn);
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qdev_init(dev);
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return (PCIDevice *)dev;
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
953