18135aeedSIsaku Yamahata /* 28135aeedSIsaku Yamahata * ioh3420.c 38135aeedSIsaku Yamahata * Intel X58 north bridge IOH 48135aeedSIsaku Yamahata * PCI Express root port device id 3420 58135aeedSIsaku Yamahata * 68135aeedSIsaku Yamahata * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> 78135aeedSIsaku Yamahata * VA Linux Systems Japan K.K. 88135aeedSIsaku Yamahata * 98135aeedSIsaku Yamahata * This program is free software; you can redistribute it and/or modify 108135aeedSIsaku Yamahata * it under the terms of the GNU General Public License as published by 118135aeedSIsaku Yamahata * the Free Software Foundation; either version 2 of the License, or 128135aeedSIsaku Yamahata * (at your option) any later version. 138135aeedSIsaku Yamahata * 148135aeedSIsaku Yamahata * This program is distributed in the hope that it will be useful, 158135aeedSIsaku Yamahata * but WITHOUT ANY WARRANTY; without even the implied warranty of 168135aeedSIsaku Yamahata * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178135aeedSIsaku Yamahata * GNU General Public License for more details. 188135aeedSIsaku Yamahata * 198135aeedSIsaku Yamahata * You should have received a copy of the GNU General Public License along 208135aeedSIsaku Yamahata * with this program; if not, see <http://www.gnu.org/licenses/>. 218135aeedSIsaku Yamahata */ 228135aeedSIsaku Yamahata 2383c9f4caSPaolo Bonzini #include "hw/pci/pci_ids.h" 2483c9f4caSPaolo Bonzini #include "hw/pci/msi.h" 2583c9f4caSPaolo Bonzini #include "hw/pci/pcie.h" 2647b43a1fSPaolo Bonzini #include "ioh3420.h" 278135aeedSIsaku Yamahata 288135aeedSIsaku Yamahata #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ 298135aeedSIsaku Yamahata #define PCI_DEVICE_ID_IOH_REV 0x2 308135aeedSIsaku Yamahata #define IOH_EP_SSVID_OFFSET 0x40 318135aeedSIsaku Yamahata #define IOH_EP_SSVID_SVID PCI_VENDOR_ID_INTEL 328135aeedSIsaku Yamahata #define IOH_EP_SSVID_SSID 0 338135aeedSIsaku Yamahata #define IOH_EP_MSI_OFFSET 0x60 348135aeedSIsaku Yamahata #define IOH_EP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT 358135aeedSIsaku Yamahata #define IOH_EP_MSI_NR_VECTOR 2 368135aeedSIsaku Yamahata #define IOH_EP_EXP_OFFSET 0x90 378135aeedSIsaku Yamahata #define IOH_EP_AER_OFFSET 0x100 388135aeedSIsaku Yamahata 3961620c2fSIsaku Yamahata /* 4061620c2fSIsaku Yamahata * If two MSI vector are allocated, Advanced Error Interrupt Message Number 4161620c2fSIsaku Yamahata * is 1. otherwise 0. 4261620c2fSIsaku Yamahata * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number. 4361620c2fSIsaku Yamahata */ 4461620c2fSIsaku Yamahata static uint8_t ioh3420_aer_vector(const PCIDevice *d) 4561620c2fSIsaku Yamahata { 4661620c2fSIsaku Yamahata switch (msi_nr_vectors_allocated(d)) { 4761620c2fSIsaku Yamahata case 1: 4861620c2fSIsaku Yamahata return 0; 4961620c2fSIsaku Yamahata case 2: 5061620c2fSIsaku Yamahata return 1; 5161620c2fSIsaku Yamahata case 4: 5261620c2fSIsaku Yamahata case 8: 5361620c2fSIsaku Yamahata case 16: 5461620c2fSIsaku Yamahata case 32: 5561620c2fSIsaku Yamahata default: 5661620c2fSIsaku Yamahata break; 5761620c2fSIsaku Yamahata } 5861620c2fSIsaku Yamahata abort(); 5961620c2fSIsaku Yamahata return 0; 6061620c2fSIsaku Yamahata } 6161620c2fSIsaku Yamahata 6261620c2fSIsaku Yamahata static void ioh3420_aer_vector_update(PCIDevice *d) 6361620c2fSIsaku Yamahata { 6461620c2fSIsaku Yamahata pcie_aer_root_set_vector(d, ioh3420_aer_vector(d)); 6561620c2fSIsaku Yamahata } 6661620c2fSIsaku Yamahata 678135aeedSIsaku Yamahata static void ioh3420_write_config(PCIDevice *d, 688135aeedSIsaku Yamahata uint32_t address, uint32_t val, int len) 698135aeedSIsaku Yamahata { 7061620c2fSIsaku Yamahata uint32_t root_cmd = 7161620c2fSIsaku Yamahata pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND); 7261620c2fSIsaku Yamahata 738135aeedSIsaku Yamahata pci_bridge_write_config(d, address, val, len); 7461620c2fSIsaku Yamahata ioh3420_aer_vector_update(d); 756bde6aaaSMichael S. Tsirkin pcie_cap_slot_write_config(d, address, val, len); 7661620c2fSIsaku Yamahata pcie_aer_write_config(d, address, val, len); 7761620c2fSIsaku Yamahata pcie_aer_root_write_config(d, address, val, len, root_cmd); 788135aeedSIsaku Yamahata } 798135aeedSIsaku Yamahata 808135aeedSIsaku Yamahata static void ioh3420_reset(DeviceState *qdev) 818135aeedSIsaku Yamahata { 8240021f08SAnthony Liguori PCIDevice *d = PCI_DEVICE(qdev); 83cbd2d434SJan Kiszka 8461620c2fSIsaku Yamahata ioh3420_aer_vector_update(d); 858135aeedSIsaku Yamahata pcie_cap_root_reset(d); 868135aeedSIsaku Yamahata pcie_cap_deverr_reset(d); 878135aeedSIsaku Yamahata pcie_cap_slot_reset(d); 8861620c2fSIsaku Yamahata pcie_aer_root_reset(d); 898135aeedSIsaku Yamahata pci_bridge_reset(qdev); 908135aeedSIsaku Yamahata pci_bridge_disable_base_limit(d); 918135aeedSIsaku Yamahata } 928135aeedSIsaku Yamahata 938135aeedSIsaku Yamahata static int ioh3420_initfn(PCIDevice *d) 948135aeedSIsaku Yamahata { 95*f055e96bSAndreas Färber PCIBridge *br = PCI_BRIDGE(d); 968135aeedSIsaku Yamahata PCIEPort *p = DO_UPCAST(PCIEPort, br, br); 978135aeedSIsaku Yamahata PCIESlot *s = DO_UPCAST(PCIESlot, port, p); 988135aeedSIsaku Yamahata int rc; 998135aeedSIsaku Yamahata 100afb661ebSAlex Williamson rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); 1018135aeedSIsaku Yamahata if (rc < 0) { 1028135aeedSIsaku Yamahata return rc; 1038135aeedSIsaku Yamahata } 1048135aeedSIsaku Yamahata 1058135aeedSIsaku Yamahata pcie_port_init_reg(d); 1068135aeedSIsaku Yamahata 1078135aeedSIsaku Yamahata rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET, 1088135aeedSIsaku Yamahata IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID); 1098135aeedSIsaku Yamahata if (rc < 0) { 11061620c2fSIsaku Yamahata goto err_bridge; 1118135aeedSIsaku Yamahata } 1128135aeedSIsaku Yamahata rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR, 1138135aeedSIsaku Yamahata IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, 1148135aeedSIsaku Yamahata IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); 1158135aeedSIsaku Yamahata if (rc < 0) { 11661620c2fSIsaku Yamahata goto err_bridge; 1178135aeedSIsaku Yamahata } 1188135aeedSIsaku Yamahata rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port); 1198135aeedSIsaku Yamahata if (rc < 0) { 12061620c2fSIsaku Yamahata goto err_msi; 1218135aeedSIsaku Yamahata } 1228135aeedSIsaku Yamahata pcie_cap_deverr_init(d); 1238135aeedSIsaku Yamahata pcie_cap_slot_init(d, s->slot); 1248135aeedSIsaku Yamahata pcie_chassis_create(s->chassis); 1258135aeedSIsaku Yamahata rc = pcie_chassis_add_slot(s); 1268135aeedSIsaku Yamahata if (rc < 0) { 12761620c2fSIsaku Yamahata goto err_pcie_cap; 1288135aeedSIsaku Yamahata } 1298135aeedSIsaku Yamahata pcie_cap_root_init(d); 13061620c2fSIsaku Yamahata rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); 13161620c2fSIsaku Yamahata if (rc < 0) { 13261620c2fSIsaku Yamahata goto err; 13361620c2fSIsaku Yamahata } 13461620c2fSIsaku Yamahata pcie_aer_root_init(d); 13561620c2fSIsaku Yamahata ioh3420_aer_vector_update(d); 1368135aeedSIsaku Yamahata return 0; 13761620c2fSIsaku Yamahata 13861620c2fSIsaku Yamahata err: 13961620c2fSIsaku Yamahata pcie_chassis_del_slot(s); 14061620c2fSIsaku Yamahata err_pcie_cap: 14161620c2fSIsaku Yamahata pcie_cap_exit(d); 14261620c2fSIsaku Yamahata err_msi: 14361620c2fSIsaku Yamahata msi_uninit(d); 14461620c2fSIsaku Yamahata err_bridge: 145f90c2bcdSAlex Williamson pci_bridge_exitfn(d); 14661620c2fSIsaku Yamahata return rc; 1478135aeedSIsaku Yamahata } 1488135aeedSIsaku Yamahata 149f90c2bcdSAlex Williamson static void ioh3420_exitfn(PCIDevice *d) 1508135aeedSIsaku Yamahata { 151*f055e96bSAndreas Färber PCIBridge *br = PCI_BRIDGE(d); 15261620c2fSIsaku Yamahata PCIEPort *p = DO_UPCAST(PCIEPort, br, br); 15361620c2fSIsaku Yamahata PCIESlot *s = DO_UPCAST(PCIESlot, port, p); 15461620c2fSIsaku Yamahata 15561620c2fSIsaku Yamahata pcie_aer_exit(d); 15661620c2fSIsaku Yamahata pcie_chassis_del_slot(s); 1578135aeedSIsaku Yamahata pcie_cap_exit(d); 15861620c2fSIsaku Yamahata msi_uninit(d); 159f90c2bcdSAlex Williamson pci_bridge_exitfn(d); 1608135aeedSIsaku Yamahata } 1618135aeedSIsaku Yamahata 1628135aeedSIsaku Yamahata PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, 1638135aeedSIsaku Yamahata const char *bus_name, pci_map_irq_fn map_irq, 1648135aeedSIsaku Yamahata uint8_t port, uint8_t chassis, uint16_t slot) 1658135aeedSIsaku Yamahata { 1668135aeedSIsaku Yamahata PCIDevice *d; 1678135aeedSIsaku Yamahata PCIBridge *br; 1688135aeedSIsaku Yamahata DeviceState *qdev; 1698135aeedSIsaku Yamahata 1708135aeedSIsaku Yamahata d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420"); 1718135aeedSIsaku Yamahata if (!d) { 1728135aeedSIsaku Yamahata return NULL; 1738135aeedSIsaku Yamahata } 174*f055e96bSAndreas Färber br = PCI_BRIDGE(d); 1758135aeedSIsaku Yamahata 176*f055e96bSAndreas Färber qdev = DEVICE(d); 1778135aeedSIsaku Yamahata pci_bridge_map_irq(br, bus_name, map_irq); 1788135aeedSIsaku Yamahata qdev_prop_set_uint8(qdev, "port", port); 1798135aeedSIsaku Yamahata qdev_prop_set_uint8(qdev, "chassis", chassis); 1808135aeedSIsaku Yamahata qdev_prop_set_uint16(qdev, "slot", slot); 1818135aeedSIsaku Yamahata qdev_init_nofail(qdev); 1828135aeedSIsaku Yamahata 1838135aeedSIsaku Yamahata return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br)); 1848135aeedSIsaku Yamahata } 1858135aeedSIsaku Yamahata 1868135aeedSIsaku Yamahata static const VMStateDescription vmstate_ioh3420 = { 1878135aeedSIsaku Yamahata .name = "ioh-3240-express-root-port", 1888135aeedSIsaku Yamahata .version_id = 1, 1898135aeedSIsaku Yamahata .minimum_version_id = 1, 1908135aeedSIsaku Yamahata .minimum_version_id_old = 1, 1916bde6aaaSMichael S. Tsirkin .post_load = pcie_cap_slot_post_load, 1928135aeedSIsaku Yamahata .fields = (VMStateField[]) { 193*f055e96bSAndreas Färber VMSTATE_PCIE_DEVICE(port.br.parent_obj, PCIESlot), 194*f055e96bSAndreas Färber VMSTATE_STRUCT(port.br.parent_obj.exp.aer_log, PCIESlot, 0, 19561620c2fSIsaku Yamahata vmstate_pcie_aer_log, PCIEAERLog), 1968135aeedSIsaku Yamahata VMSTATE_END_OF_LIST() 1978135aeedSIsaku Yamahata } 1988135aeedSIsaku Yamahata }; 1998135aeedSIsaku Yamahata 20040021f08SAnthony Liguori static Property ioh3420_properties[] = { 2018135aeedSIsaku Yamahata DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), 2028135aeedSIsaku Yamahata DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), 2038135aeedSIsaku Yamahata DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), 20461620c2fSIsaku Yamahata DEFINE_PROP_UINT16("aer_log_max", PCIESlot, 205*f055e96bSAndreas Färber port.br.parent_obj.exp.aer_log.log_max, 20661620c2fSIsaku Yamahata PCIE_AER_LOG_MAX_DEFAULT), 2078135aeedSIsaku Yamahata DEFINE_PROP_END_OF_LIST(), 20840021f08SAnthony Liguori }; 20940021f08SAnthony Liguori 21040021f08SAnthony Liguori static void ioh3420_class_init(ObjectClass *klass, void *data) 21140021f08SAnthony Liguori { 21239bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 21340021f08SAnthony Liguori PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 21440021f08SAnthony Liguori 21540021f08SAnthony Liguori k->is_express = 1; 21640021f08SAnthony Liguori k->is_bridge = 1; 21740021f08SAnthony Liguori k->config_write = ioh3420_write_config; 21840021f08SAnthony Liguori k->init = ioh3420_initfn; 21940021f08SAnthony Liguori k->exit = ioh3420_exitfn; 22040021f08SAnthony Liguori k->vendor_id = PCI_VENDOR_ID_INTEL; 22140021f08SAnthony Liguori k->device_id = PCI_DEVICE_ID_IOH_EPORT; 22240021f08SAnthony Liguori k->revision = PCI_DEVICE_ID_IOH_REV; 223125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 22439bffca2SAnthony Liguori dc->desc = "Intel IOH device id 3420 PCIE Root Port"; 22539bffca2SAnthony Liguori dc->reset = ioh3420_reset; 22639bffca2SAnthony Liguori dc->vmsd = &vmstate_ioh3420; 22739bffca2SAnthony Liguori dc->props = ioh3420_properties; 2288135aeedSIsaku Yamahata } 22940021f08SAnthony Liguori 2308c43a6f0SAndreas Färber static const TypeInfo ioh3420_info = { 23140021f08SAnthony Liguori .name = "ioh3420", 232*f055e96bSAndreas Färber .parent = TYPE_PCI_BRIDGE, 23339bffca2SAnthony Liguori .instance_size = sizeof(PCIESlot), 23440021f08SAnthony Liguori .class_init = ioh3420_class_init, 2358135aeedSIsaku Yamahata }; 2368135aeedSIsaku Yamahata 23783f7d43aSAndreas Färber static void ioh3420_register_types(void) 2388135aeedSIsaku Yamahata { 23939bffca2SAnthony Liguori type_register_static(&ioh3420_info); 2408135aeedSIsaku Yamahata } 2418135aeedSIsaku Yamahata 24283f7d43aSAndreas Färber type_init(ioh3420_register_types) 2438135aeedSIsaku Yamahata 2448135aeedSIsaku Yamahata /* 2458135aeedSIsaku Yamahata * Local variables: 2468135aeedSIsaku Yamahata * c-indent-level: 4 2478135aeedSIsaku Yamahata * c-basic-offset: 4 2488135aeedSIsaku Yamahata * tab-width: 8 2498135aeedSIsaku Yamahata * indent-tab-mode: nil 2508135aeedSIsaku Yamahata * End: 2518135aeedSIsaku Yamahata */ 252