1c0907c9eSPaolo Bonzini /* 2c0907c9eSPaolo Bonzini * Standard PCI Bridge Device 3c0907c9eSPaolo Bonzini * 4c0907c9eSPaolo Bonzini * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com> 5c0907c9eSPaolo Bonzini * 6c0907c9eSPaolo Bonzini * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/ 7c0907c9eSPaolo Bonzini * 8c0907c9eSPaolo Bonzini * This program is free software; you can redistribute it and/or modify 9c0907c9eSPaolo Bonzini * it under the terms of the GNU General Public License as published by 10c0907c9eSPaolo Bonzini * the Free Software Foundation; either version 2 of the License, or 11c0907c9eSPaolo Bonzini * (at your option) any later version. 12c0907c9eSPaolo Bonzini * 13c0907c9eSPaolo Bonzini * This program is distributed in the hope that it will be useful, 14c0907c9eSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c0907c9eSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16c0907c9eSPaolo Bonzini * GNU General Public License for more details. 17c0907c9eSPaolo Bonzini * 18c0907c9eSPaolo Bonzini * You should have received a copy of the GNU General Public License along 19c0907c9eSPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>. 20c0907c9eSPaolo Bonzini */ 21c0907c9eSPaolo Bonzini 22c0907c9eSPaolo Bonzini #include "hw/pci/pci_bridge.h" 23c0907c9eSPaolo Bonzini #include "hw/pci/pci_ids.h" 24c0907c9eSPaolo Bonzini #include "hw/pci/msi.h" 25c0907c9eSPaolo Bonzini #include "hw/pci/shpc.h" 26c0907c9eSPaolo Bonzini #include "hw/pci/slotid_cap.h" 27c0907c9eSPaolo Bonzini #include "exec/memory.h" 28c0907c9eSPaolo Bonzini #include "hw/pci/pci_bus.h" 29c0907c9eSPaolo Bonzini 30c0907c9eSPaolo Bonzini struct PCIBridgeDev { 31c0907c9eSPaolo Bonzini PCIBridge bridge; 32c0907c9eSPaolo Bonzini MemoryRegion bar; 33c0907c9eSPaolo Bonzini uint8_t chassis_nr; 34c0907c9eSPaolo Bonzini #define PCI_BRIDGE_DEV_F_MSI_REQ 0 35c0907c9eSPaolo Bonzini uint32_t flags; 36c0907c9eSPaolo Bonzini }; 37c0907c9eSPaolo Bonzini typedef struct PCIBridgeDev PCIBridgeDev; 38c0907c9eSPaolo Bonzini 39c0907c9eSPaolo Bonzini static int pci_bridge_dev_initfn(PCIDevice *dev) 40c0907c9eSPaolo Bonzini { 41c0907c9eSPaolo Bonzini PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); 42c0907c9eSPaolo Bonzini PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); 43c0907c9eSPaolo Bonzini int err; 44c0907c9eSPaolo Bonzini 45c0907c9eSPaolo Bonzini err = pci_bridge_initfn(dev, TYPE_PCI_BUS); 46c0907c9eSPaolo Bonzini if (err) { 47c0907c9eSPaolo Bonzini goto bridge_error; 48c0907c9eSPaolo Bonzini } 4940c5dce9SPaolo Bonzini memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", shpc_bar_size(dev)); 50c0907c9eSPaolo Bonzini err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0); 51c0907c9eSPaolo Bonzini if (err) { 52c0907c9eSPaolo Bonzini goto shpc_error; 53c0907c9eSPaolo Bonzini } 54c0907c9eSPaolo Bonzini err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0); 55c0907c9eSPaolo Bonzini if (err) { 56c0907c9eSPaolo Bonzini goto slotid_error; 57c0907c9eSPaolo Bonzini } 58c0907c9eSPaolo Bonzini if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) && 59c0907c9eSPaolo Bonzini msi_supported) { 60c0907c9eSPaolo Bonzini err = msi_init(dev, 0, 1, true, true); 61c0907c9eSPaolo Bonzini if (err < 0) { 62c0907c9eSPaolo Bonzini goto msi_error; 63c0907c9eSPaolo Bonzini } 64c0907c9eSPaolo Bonzini } 65c0907c9eSPaolo Bonzini /* TODO: spec recommends using 64 bit prefetcheable BAR. 66c0907c9eSPaolo Bonzini * Check whether that works well. */ 67c0907c9eSPaolo Bonzini pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | 68c0907c9eSPaolo Bonzini PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar); 69c0907c9eSPaolo Bonzini dev->config[PCI_INTERRUPT_PIN] = 0x1; 70c0907c9eSPaolo Bonzini return 0; 71c0907c9eSPaolo Bonzini msi_error: 72c0907c9eSPaolo Bonzini slotid_cap_cleanup(dev); 73c0907c9eSPaolo Bonzini slotid_error: 74c0907c9eSPaolo Bonzini shpc_cleanup(dev, &bridge_dev->bar); 75c0907c9eSPaolo Bonzini shpc_error: 76c0907c9eSPaolo Bonzini memory_region_destroy(&bridge_dev->bar); 77c0907c9eSPaolo Bonzini pci_bridge_exitfn(dev); 78c0907c9eSPaolo Bonzini bridge_error: 79c0907c9eSPaolo Bonzini return err; 80c0907c9eSPaolo Bonzini } 81c0907c9eSPaolo Bonzini 82c0907c9eSPaolo Bonzini static void pci_bridge_dev_exitfn(PCIDevice *dev) 83c0907c9eSPaolo Bonzini { 84c0907c9eSPaolo Bonzini PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); 85c0907c9eSPaolo Bonzini PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); 86c0907c9eSPaolo Bonzini if (msi_present(dev)) { 87c0907c9eSPaolo Bonzini msi_uninit(dev); 88c0907c9eSPaolo Bonzini } 89c0907c9eSPaolo Bonzini slotid_cap_cleanup(dev); 90c0907c9eSPaolo Bonzini shpc_cleanup(dev, &bridge_dev->bar); 91c0907c9eSPaolo Bonzini memory_region_destroy(&bridge_dev->bar); 92c0907c9eSPaolo Bonzini pci_bridge_exitfn(dev); 93c0907c9eSPaolo Bonzini } 94c0907c9eSPaolo Bonzini 95c0907c9eSPaolo Bonzini static void pci_bridge_dev_write_config(PCIDevice *d, 96c0907c9eSPaolo Bonzini uint32_t address, uint32_t val, int len) 97c0907c9eSPaolo Bonzini { 98c0907c9eSPaolo Bonzini pci_bridge_write_config(d, address, val, len); 99c0907c9eSPaolo Bonzini if (msi_present(d)) { 100c0907c9eSPaolo Bonzini msi_write_config(d, address, val, len); 101c0907c9eSPaolo Bonzini } 102c0907c9eSPaolo Bonzini shpc_cap_write_config(d, address, val, len); 103c0907c9eSPaolo Bonzini } 104c0907c9eSPaolo Bonzini 105c0907c9eSPaolo Bonzini static void qdev_pci_bridge_dev_reset(DeviceState *qdev) 106c0907c9eSPaolo Bonzini { 107c0907c9eSPaolo Bonzini PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); 108c0907c9eSPaolo Bonzini 109c0907c9eSPaolo Bonzini pci_bridge_reset(qdev); 110c0907c9eSPaolo Bonzini shpc_reset(dev); 111c0907c9eSPaolo Bonzini } 112c0907c9eSPaolo Bonzini 113c0907c9eSPaolo Bonzini static Property pci_bridge_dev_properties[] = { 114c0907c9eSPaolo Bonzini /* Note: 0 is not a legal chassis number. */ 115c0907c9eSPaolo Bonzini DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0), 116c0907c9eSPaolo Bonzini DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true), 117c0907c9eSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 118c0907c9eSPaolo Bonzini }; 119c0907c9eSPaolo Bonzini 120c0907c9eSPaolo Bonzini static const VMStateDescription pci_bridge_dev_vmstate = { 121c0907c9eSPaolo Bonzini .name = "pci_bridge", 122c0907c9eSPaolo Bonzini .fields = (VMStateField[]) { 123c0907c9eSPaolo Bonzini VMSTATE_PCI_DEVICE(bridge.dev, PCIBridgeDev), 124c0907c9eSPaolo Bonzini SHPC_VMSTATE(bridge.dev.shpc, PCIBridgeDev), 125c0907c9eSPaolo Bonzini VMSTATE_END_OF_LIST() 126c0907c9eSPaolo Bonzini } 127c0907c9eSPaolo Bonzini }; 128c0907c9eSPaolo Bonzini 129c0907c9eSPaolo Bonzini static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) 130c0907c9eSPaolo Bonzini { 131c0907c9eSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 132c0907c9eSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 133c0907c9eSPaolo Bonzini k->init = pci_bridge_dev_initfn; 134c0907c9eSPaolo Bonzini k->exit = pci_bridge_dev_exitfn; 135c0907c9eSPaolo Bonzini k->config_write = pci_bridge_dev_write_config; 136c0907c9eSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_REDHAT; 137c0907c9eSPaolo Bonzini k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; 138c0907c9eSPaolo Bonzini k->class_id = PCI_CLASS_BRIDGE_PCI; 139c0907c9eSPaolo Bonzini k->is_bridge = 1, 140c0907c9eSPaolo Bonzini dc->desc = "Standard PCI Bridge"; 141c0907c9eSPaolo Bonzini dc->reset = qdev_pci_bridge_dev_reset; 142c0907c9eSPaolo Bonzini dc->props = pci_bridge_dev_properties; 143c0907c9eSPaolo Bonzini dc->vmsd = &pci_bridge_dev_vmstate; 144*125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 145c0907c9eSPaolo Bonzini } 146c0907c9eSPaolo Bonzini 147c0907c9eSPaolo Bonzini static const TypeInfo pci_bridge_dev_info = { 148c0907c9eSPaolo Bonzini .name = "pci-bridge", 149c0907c9eSPaolo Bonzini .parent = TYPE_PCI_DEVICE, 150c0907c9eSPaolo Bonzini .instance_size = sizeof(PCIBridgeDev), 151c0907c9eSPaolo Bonzini .class_init = pci_bridge_dev_class_init, 152c0907c9eSPaolo Bonzini }; 153c0907c9eSPaolo Bonzini 154c0907c9eSPaolo Bonzini static void pci_bridge_dev_register(void) 155c0907c9eSPaolo Bonzini { 156c0907c9eSPaolo Bonzini type_register_static(&pci_bridge_dev_info); 157c0907c9eSPaolo Bonzini } 158c0907c9eSPaolo Bonzini 159c0907c9eSPaolo Bonzini type_init(pci_bridge_dev_register); 160