pci.c revision 2ec695af7284adbedcdbc08a22d818b6bdd8990c
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 */ 242ec695af7284adbedcdbc08a22d818b6bdd8990cDavid 'Digit' Turner#include "hw/hw.h" 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "pci.h" 266af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h" 27cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "net/net.h" 2834c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h" 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_PCI 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct PCIBus { 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BusState qbus; 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int bus_num; 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int devfn_min; 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_set_irq_fn set_irq; 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_map_irq_fn map_irq; 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t config_reg; /* XXX: suppress */ 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* low level pic */ 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SetIRQFunc *low_set_irq; 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_irq *irq_opaque; 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice *devices[256]; 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice *parent_dev; 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *next; 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The bus IRQ state is the logical OR of the connected devices. 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project Keep a count of the number of devices with raised IRQs. */ 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int nirq; 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int irq_count[]; 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_update_mappings(PCIDevice *d); 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_set_irq(void *opaque, int irq_num, int level); 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttarget_phys_addr_t pci_mem_base; 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic PCIBus *first_bus; 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pcibus_save(QEMUFile *f, void *opaque) 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus = (PCIBus *)opaque; 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, bus->nirq); 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < bus->nirq; i++) 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, bus->irq_count[i]); 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int pcibus_load(QEMUFile *f, void *opaque, int version_id) 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus = (PCIBus *)opaque; 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i, nirq; 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (version_id != 1) 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -EINVAL; 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nirq = qemu_get_be32(f); 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bus->nirq != nirq) { 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n", 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nirq, bus->nirq); 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -EINVAL; 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < nirq; i++) 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->irq_count[i] = qemu_get_be32(f); 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIBus *pci_register_bus(DeviceState *parent, const char *name, 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_irq *pic, int devfn_min, int nirq) 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus; 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project static int nbus = 0; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI, 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sizeof(PCIBus) + (nirq * sizeof(int)), 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner parent, name)); 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->set_irq = set_irq; 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->map_irq = map_irq; 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->irq_opaque = pic; 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->devfn_min = devfn_min; 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->nirq = nirq; 1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bus->next = first_bus; 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project first_bus = bus; 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus); 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return bus; 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq) 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus; 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus = qemu_mallocz(sizeof(PCIBus)); 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->map_irq = map_irq; 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->parent_dev = dev; 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->next = dev->bus->next; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dev->bus->next = bus; 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return bus; 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint pci_bus_num(PCIBus *s) 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->bus_num; 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_device_save(PCIDevice *s, QEMUFile *f) 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, 2); /* PCI device version */ 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_buffer(f, s->config, 256); 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 4; i++) 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_be32(f, s->irq_state[i]); 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint pci_device_load(PCIDevice *s, QEMUFile *f) 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t version_id; 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project version_id = qemu_get_be32(f); 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (version_id > 2) 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -EINVAL; 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_get_buffer(f, s->config, 256); 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_update_mappings(s); 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (version_id >= 2) 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < 4; i ++) 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->irq_state[i] = qemu_get_be32(f); 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pci_set_default_subsystem_id(PCIDevice *pci_dev) 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t *id; 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner id = (void*)(&pci_dev->config[PCI_SUBVENDOR_ID]); 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner id[0] = cpu_to_le16(pci_default_sub_vendor_id); 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner id[1] = cpu_to_le16(pci_default_sub_device_id); 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Parse [[<domain>:]<bus>:]<slot>, return -1 on error 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp) 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *p; 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char *e; 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned long val; 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned long dom = 0, bus = 0; 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned slot = 0; 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p = addr; 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner val = strtoul(p, &e, 16); 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (e == p) 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (*e == ':') { 1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bus = val; 1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p = e + 1; 1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner val = strtoul(p, &e, 16); 1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (e == p) 1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (*e == ':') { 1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dom = bus; 1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bus = val; 1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p = e + 1; 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner val = strtoul(p, &e, 16); 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (e == p) 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (dom > 0xffff || bus > 0xff || val > 0x1f) 1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner slot = val; 2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (*e) 2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Note: QEMU doesn't implement domains other than 0 */ 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (dom != 0 || pci_find_bus(bus) == NULL) 2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *domp = dom; 2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *busp = bus; 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *slotp = slot; 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint pci_read_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp) 2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char devaddr[32]; 2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!get_param_value(devaddr, sizeof(devaddr), "pci_addr", addr)) 2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return pci_parse_devaddr(devaddr, domp, busp, slotp); 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp) 2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char devaddr[32]; 2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!get_param_value(devaddr, sizeof(devaddr), "pci_addr", addr)) 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(devaddr, "auto")) { 2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *domp = *busp = 0; 2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *slotp = -1; 2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* want to support dom/bus auto-assign at some point */ 2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return pci_parse_devaddr(devaddr, domp, busp, slotp); 2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* -1 for devfn means auto assign */ 2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, 2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *name, int devfn, 2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIConfigReadFunc *config_read, 2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIConfigWriteFunc *config_write) 2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (devfn < 0) { 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!bus->devices[devfn]) 2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto found; 2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project found: ; 2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->bus = bus; 2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->devfn = devfn; 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); 2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); 2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_set_default_subsystem_id(pci_dev); 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!config_read) 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_read = pci_default_read_config; 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!config_write) 2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_write = pci_default_write_config; 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->config_read = config_read; 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->config_write = config_write; 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->devices[devfn] = pci_dev; 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4); 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return pci_dev; 2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_register_device(PCIBus *bus, const char *name, 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_size, int devfn, 2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIConfigReadFunc *config_read, 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIConfigWriteFunc *config_write) 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIDevice *pci_dev; 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_dev = qemu_mallocz(instance_size); 2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, 2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner config_read, config_write); 2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return pci_dev; 2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) 2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return addr + pci_mem_base; 2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pci_unregister_io_regions(PCIDevice *pci_dev) 2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIIORegion *r; 2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < PCI_NUM_REGIONS; i++) { 2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r = &pci_dev->io_regions[i]; 2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!r->size || r->addr == -1) 2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r->type == PCI_ADDRESS_SPACE_IO) { 2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner isa_unassign_ioport(r->addr, r->size); 3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cpu_register_physical_memory(pci_to_cpu_addr(r->addr), 3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->size, 3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IO_MEM_UNASSIGNED); 3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint pci_unregister_device(PCIDevice *pci_dev) 3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 0; 3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (pci_dev->unregister) 3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = pci_dev->unregister(pci_dev); 3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret) 3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_unregister_io_regions(pci_dev); 3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_irqs(pci_dev->irq); 3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_dev->bus->devices[pci_dev->devfn] = NULL; 3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_free(&pci_dev->qdev); 3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid pci_register_bar(PCIDevice *pci_dev, int region_num, 3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t size, int type, 3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIMapIORegionFunc *map_func) 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIIORegion *r; 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t addr; 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ((unsigned int)region_num >= PCI_NUM_REGIONS) 3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (size & (size-1)) { 3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "ERROR: PCI region size must be pow2 " 3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "type=0x%x, size=0x%x\n", type, size); 3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = &pci_dev->io_regions[region_num]; 3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->addr = -1; 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->size = size; 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->type = type; 3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->map_func = map_func; 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (region_num == PCI_ROM_SLOT) { 3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr = 0x30; 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr = 0x10 + region_num * 4; 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); 3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_update_mappings(PCIDevice *d) 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIIORegion *r; 3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cmd, i; 3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t last_addr, new_addr, config_ofs; 3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(i = 0; i < PCI_NUM_REGIONS; i++) { 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = &d->io_regions[i]; 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (i == PCI_ROM_SLOT) { 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_ofs = 0x30; 3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_ofs = 0x10 + i * 4; 3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->size != 0) { 3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->type & PCI_ADDRESS_SPACE_IO) { 3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (cmd & PCI_COMMAND_IO) { 3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_addr = le32_to_cpu(*(uint32_t *)(d->config + 3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 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) { 3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_addr = le32_to_cpu(*(uint32_t *)(d->config + 3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_ofs)); 3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* the ROM slot has a specific enable bit */ 3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (i == PCI_ROM_SLOT && !(new_addr & 1)) 3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto no_mem_map; 3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_addr = new_addr & ~(r->size - 1); 3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last_addr = new_addr + r->size - 1; 3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* NOTE: we do not support wrapping */ 3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* XXX: as we cannot support really dynamic 3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mappings, we handle specific values as invalid 3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mappings. */ 3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (last_addr <= new_addr || new_addr == 0 || 3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last_addr == -1) { 3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_addr = -1; 3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project no_mem_map: 4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_addr = -1; 4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* now do the real mapping */ 4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (new_addr != r->addr) { 4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->addr != -1) { 4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->type & PCI_ADDRESS_SPACE_IO) { 4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int class; 4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* NOTE: specific hack for IDE in PC case: 4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project only one byte must be mapped. */ 4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project class = d->config[0x0a] | (d->config[0x0b] << 8); 4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (class == 0x0101 && r->size == 4) { 4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project isa_unassign_ioport(r->addr + 2, 1); 4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project isa_unassign_ioport(r->addr, r->size); 4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_register_physical_memory(pci_to_cpu_addr(r->addr), 4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->size, 4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project IO_MEM_UNASSIGNED); 4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_unregister_coalesced_mmio(r->addr, r->size); 4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->addr = new_addr; 4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->addr != -1) { 4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->map_func(d, i, r->addr, r->size, r->type); 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 Project 4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectuint32_t pci_default_read_config(PCIDevice *d, 4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t address, int len) 4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t val; 4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(len) { 4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 4: 4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (address <= 0xfc) { 4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = le32_to_cpu(*(uint32_t *)(d->config + address)); 4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fall through */ 4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (address <= 0xfe) { 4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = le16_to_cpu(*(uint16_t *)(d->config + address)); 4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fall through */ 4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = d->config[address]; 4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return val; 4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_default_write_config(PCIDevice *d, 4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t address, uint32_t val, int len) 4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int can_write, i; 4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t end, addr; 4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || 4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (address >= 0x30 && address < 0x34))) { 4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIIORegion *r; 4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int reg; 4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ( address >= 0x30 ) { 4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project reg = PCI_ROM_SLOT; 4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project }else{ 4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project reg = (address - 0x10) >> 2; 4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = &d->io_regions[reg]; 4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->size == 0) 4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto default_config; 4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* compute the stored value */ 4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (reg == PCI_ROM_SLOT) { 4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* keep ROM enable bit */ 4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val &= (~(r->size - 1)) | 1; 4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val &= ~(r->size - 1); 4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val |= r->type; 4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *(uint32_t *)(d->config + address) = cpu_to_le32(val); 4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_update_mappings(d); 4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default_config: 4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* not efficient, but simple */ 4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr = address; 4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(i = 0; i < len; i++) { 4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* default read/write accesses */ 4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(d->config[0x0e]) { 4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: 4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x80: 4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(addr) { 5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: 5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x01: 5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x02: 5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x03: 5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x06: 5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x07: 5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x08: 5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x09: 5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0a: 5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0b: 5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0e: 5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x10 ... 0x27: /* base */ 5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ 5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x30 ... 0x33: /* rom */ 5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x3d: 5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project can_write = 0; 5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project can_write = 1; 5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x01: 5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(addr) { 5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: 5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x01: 5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x02: 5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x03: 5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x06: 5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x07: 5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x08: 5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x09: 5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0a: 5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0b: 5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0e: 5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ 5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x38 ... 0x3b: /* rom */ 5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x3d: 5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project can_write = 0; 5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project can_write = 1; 5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (can_write) { 5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Mask out writes to reserved bits in registers */ 5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (addr) { 5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x05: 5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner val &= ~PCI_COMMAND_RESERVED_MASK_HI; 5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x06: 5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner val &= ~PCI_STATUS_RESERVED_MASK_LO; 5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x07: 5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner val &= ~PCI_STATUS_RESERVED_MASK_HI; 5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->config[addr] = val; 5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (++addr > 0xff) 5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val >>= 8; 5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project end = address + len; 5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) { 5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* if the command register is modified, we must modify the mappings */ 5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_update_mappings(d); 5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) 5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *s = opaque; 5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice *pci_dev; 5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int config_addr, bus_num; 5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) && 0 5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf("pci_data_write: addr=%08x val=%08x len=%d\n", 5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr, val, len); 5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus_num = (addr >> 16) & 0xff; 5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (s && s->bus_num != bus_num) 5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s = s->next; 5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!s) 5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev = s->devices[(addr >> 8) & 0xff]; 5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!pci_dev) 5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_addr = addr & 0xff; 5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) 5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", 5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->name, config_addr, val, len); 5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->config_write(pci_dev, config_addr, val, len); 5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectuint32_t pci_data_read(void *opaque, uint32_t addr, int len) 6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *s = opaque; 6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice *pci_dev; 6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int config_addr, bus_num; 6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t val; 6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus_num = (addr >> 16) & 0xff; 6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (s && s->bus_num != bus_num) 6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s= s->next; 6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!s) 6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev = s->devices[(addr >> 8) & 0xff]; 6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!pci_dev) { 6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail: 6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(len) { 6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = 0xff; 6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = 0xffff; 6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 4: 6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = 0xffffffff; 6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto the_end; 6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project config_addr = addr & 0xff; 6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val = pci_dev->config_read(pci_dev, config_addr, len); 6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) 6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", 6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->name, config_addr, val, len); 6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project the_end: 6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) && 0 6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf("pci_data_read: addr=%08x val=%08x len=%d\n", 6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr, val, len); 6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return val; 6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/***********************************************************/ 6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* generic PCI irq support */ 6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 0 <= irq_num <= 3. level must be 0 or 1 */ 6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_set_irq(void *opaque, int irq_num, int level) 6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice *pci_dev = (PCIDevice *)opaque; 6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus; 6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int change; 6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project change = level - pci_dev->irq_state[irq_num]; 6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!change) 6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev->irq_state[irq_num] = level; 6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (;;) { 6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus = pci_dev->bus; 6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project irq_num = bus->map_irq(pci_dev, irq_num); 6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bus->set_irq) 6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_dev = bus->parent_dev; 6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->irq_count[irq_num] += change; 6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); 6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/***********************************************************/ 6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* monitor info on PCI */ 6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct { 6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint16_t class; 6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char *desc; 6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} pci_class_desc; 6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const pci_class_desc pci_class_descriptions[] = 6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0100, "SCSI controller"}, 6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0101, "IDE controller"}, 6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0102, "Floppy controller"}, 6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0103, "IPI controller"}, 6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0104, "RAID controller"}, 6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0106, "SATA controller"}, 6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0107, "SAS controller"}, 6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0180, "Storage controller"}, 6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0200, "Ethernet controller"}, 6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0201, "Token Ring controller"}, 6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0202, "FDDI controller"}, 6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0203, "ATM controller"}, 6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0280, "Network controller"}, 6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0300, "VGA controller"}, 6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0301, "XGA controller"}, 6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0302, "3D controller"}, 6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0380, "Display controller"}, 6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0400, "Video controller"}, 6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0401, "Audio controller"}, 6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0402, "Phone"}, 6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0480, "Multimedia controller"}, 7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0500, "RAM controller"}, 7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0501, "Flash controller"}, 7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0580, "Memory controller"}, 7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0600, "Host bridge"}, 7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0601, "ISA bridge"}, 7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0602, "EISA bridge"}, 7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0603, "MC bridge"}, 7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0604, "PCI bridge"}, 7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0605, "PCMCIA bridge"}, 7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0606, "NUBUS bridge"}, 7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0607, "CARDBUS bridge"}, 7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0608, "RACEWAY bridge"}, 7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0680, "Bridge"}, 7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0x0c03, "USB controller"}, 7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 0, NULL} 7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_info_device(PCIDevice *d) 7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner Monitor *mon = cur_mon; 7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i, class; 7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIIORegion *r; 7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const pci_class_desc *desc; 7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, " Bus %2d, device %3d, function %d:\n", 7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner d->bus->bus_num, d->devfn >> 3, d->devfn & 7); 7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); 7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, " "); 7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project desc = pci_class_descriptions; 7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (desc->desc && class != desc->class) 7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project desc++; 7318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (desc->desc) { 7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "%s", desc->desc); 7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Class %04x", class); 7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, ": PCI device %04x:%04x\n", 7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), 7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); 7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (d->config[PCI_INTERRUPT_PIN] != 0) { 7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, " IRQ %d.\n", 7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner d->config[PCI_INTERRUPT_LINE]); 7438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (class == 0x0604) { 7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, " BUS %d.\n", d->config[0x19]); 7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(i = 0;i < PCI_NUM_REGIONS; i++) { 7488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = &d->io_regions[i]; 7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->size != 0) { 7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, " BAR%d: ", i); 7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->type & PCI_ADDRESS_SPACE_IO) { 7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "I/O at 0x%04x [0x%04x].\n", 7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->addr, r->addr + r->size - 1); 7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "32 bit memory at 0x%08x [0x%08x].\n", 7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->addr, r->addr + r->size - 1); 7578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (class == 0x0604 && d->config[0x19] != 0) { 7618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_for_each_device(d->config[0x19], pci_info_device); 7628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)) 7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus = first_bus; 7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice *d; 7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int devfn; 7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (bus && bus->bus_num != bus_num) 7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bus = bus->next; 7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bus) { 7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(devfn = 0; devfn < 256; devfn++) { 7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d = bus->devices[devfn]; 7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (d) 7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fn(d); 7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid pci_info(Monitor *mon) 7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_for_each_device(0, pci_info_device); 7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char * const pci_nic_models[] = { 7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "ne2k_pci", 7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "i82551", 7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "i82557b", 7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "i82559er", 7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "rtl8139", 7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "e1000", 7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "pcnet", 7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "virtio", 7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL 7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char * const pci_nic_names[] = { 8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "ne2k_pci", 8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "i82551", 8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "i82557b", 8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "i82559er", 8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "rtl8139", 8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "e1000", 8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "pcnet", 8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "virtio-net-pci", 8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL 8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Initialize a PCI NIC. */ 8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn, 8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *default_model) 8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DeviceState *dev; 8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_check_nic_model_list(nd, pci_nic_models, default_model); 8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; pci_nic_models[i]; i++) { 8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (strcmp(nd->model, pci_nic_models[i]) == 0) { 8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev = qdev_create(&bus->qbus, pci_nic_names[i]); 8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_set_prop_int(dev, "devfn", devfn); 8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_set_netdev(dev, nd); 8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_init(dev); 8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nd->private = dev; 8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return (PCIDevice *)dev; 8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 8328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 8338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct { 8358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIDevice dev; 8368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBus *bus; 8378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} PCIBridge; 8388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pci_bridge_write_config(PCIDevice *d, 8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t address, uint32_t val, int len) 8418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBridge *s = (PCIBridge *)d; 8438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (address == 0x19 || (address == 0x18 && len > 1)) { 8458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (address == 0x19) 8468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->bus->bus_num = val & 0xff; 8478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 8488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->bus->bus_num = (val >> 8) & 0xff; 8498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if defined(DEBUG_PCI) 8508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num); 8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 8528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_default_write_config(d, address, val, len); 8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 8558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIBus *pci_find_bus(int bus_num) 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIBus *bus = first_bus; 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (bus && bus->bus_num != bus_num) 8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bus = bus->next; 8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bus; 8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_find_device(int bus_num, int slot, int function) 8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIBus *bus = pci_find_bus(bus_num); 8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bus) 8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bus->devices[PCI_DEVFN(slot, function)]; 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, 8778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project pci_map_irq_fn map_irq, const char *name) 8788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 8798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PCIBridge *s; 8808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), 8818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project devfn, NULL, pci_bridge_write_config); 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_config_set_vendor_id(s->dev.config, vid); 8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_config_set_device_id(s->dev.config, did); 8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x04] = 0x06; // command = bus master, pci mem 8878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x05] = 0x00; 8888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error 8898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x07] = 0x00; // status = fast devsel 8908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x08] = 0x00; // revision 8918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x09] = 0x00; // programming i/f 8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_config_set_class(s->dev.config, PCI_CLASS_BRIDGE_PCI); 8938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x0D] = 0x10; // latency_timer 8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->dev.config[PCI_HEADER_TYPE] = 8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type 8968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->dev.config[0x1E] = 0xa0; // secondary status 8978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->bus = pci_register_secondary_bus(&s->dev, map_irq); 8998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return s->bus; 9008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct { 9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DeviceInfo qdev; 9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_qdev_initfn init; 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} PCIDeviceInfo; 9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pci_qdev_init(DeviceState *qdev, DeviceInfo *base) 9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIDevice *pci_dev = (PCIDevice *)qdev; 9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev); 9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIBus *bus; 9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int devfn; 9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); 9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner devfn = qdev_get_prop_int(qdev, "devfn", -1); 9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn, 9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL, NULL);//FIXME:config_read, config_write); 9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner assert(pci_dev); 9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->init(pci_dev); 9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid pci_qdev_register(const char *name, int size, pci_qdev_initfn init) 9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PCIDeviceInfo *info; 9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info = qemu_mallocz(sizeof(*info)); 9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.name = qemu_strdup(name); 9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.size = size; 9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->init = init; 9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.init = pci_qdev_init; 9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner info->qdev.bus_type = BUS_TYPE_PCI; 9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_register(&info->qdev); 9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerPCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) 9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DeviceState *dev; 9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dev = qdev_create(&bus->qbus, name); 9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_set_prop_int(dev, "devfn", devfn); 9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qdev_init(dev); 9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return (PCIDevice *)dev; 9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 946