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 2397d5408fSPeter Maydell #include "qemu/osdep.h" 2483c9f4caSPaolo Bonzini #include "hw/pci/pci_ids.h" 2583c9f4caSPaolo Bonzini #include "hw/pci/msi.h" 2683c9f4caSPaolo Bonzini #include "hw/pci/pcie.h" 2747b43a1fSPaolo Bonzini #include "ioh3420.h" 288135aeedSIsaku Yamahata 298135aeedSIsaku Yamahata #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ 308135aeedSIsaku Yamahata #define PCI_DEVICE_ID_IOH_REV 0x2 318135aeedSIsaku Yamahata #define IOH_EP_SSVID_OFFSET 0x40 328135aeedSIsaku Yamahata #define IOH_EP_SSVID_SVID PCI_VENDOR_ID_INTEL 338135aeedSIsaku Yamahata #define IOH_EP_SSVID_SSID 0 348135aeedSIsaku Yamahata #define IOH_EP_MSI_OFFSET 0x60 358135aeedSIsaku Yamahata #define IOH_EP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT 368135aeedSIsaku Yamahata #define IOH_EP_MSI_NR_VECTOR 2 378135aeedSIsaku Yamahata #define IOH_EP_EXP_OFFSET 0x90 388135aeedSIsaku Yamahata #define IOH_EP_AER_OFFSET 0x100 398135aeedSIsaku Yamahata 4061620c2fSIsaku Yamahata /* 4161620c2fSIsaku Yamahata * If two MSI vector are allocated, Advanced Error Interrupt Message Number 4261620c2fSIsaku Yamahata * is 1. otherwise 0. 4361620c2fSIsaku Yamahata * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number. 4461620c2fSIsaku Yamahata */ 4561620c2fSIsaku Yamahata static uint8_t ioh3420_aer_vector(const PCIDevice *d) 4661620c2fSIsaku Yamahata { 4761620c2fSIsaku Yamahata switch (msi_nr_vectors_allocated(d)) { 4861620c2fSIsaku Yamahata case 1: 4961620c2fSIsaku Yamahata return 0; 5061620c2fSIsaku Yamahata case 2: 5161620c2fSIsaku Yamahata return 1; 5261620c2fSIsaku Yamahata case 4: 5361620c2fSIsaku Yamahata case 8: 5461620c2fSIsaku Yamahata case 16: 5561620c2fSIsaku Yamahata case 32: 5661620c2fSIsaku Yamahata default: 5761620c2fSIsaku Yamahata break; 5861620c2fSIsaku Yamahata } 5961620c2fSIsaku Yamahata abort(); 6061620c2fSIsaku Yamahata return 0; 6161620c2fSIsaku Yamahata } 6261620c2fSIsaku Yamahata 6361620c2fSIsaku Yamahata static void ioh3420_aer_vector_update(PCIDevice *d) 6461620c2fSIsaku Yamahata { 6561620c2fSIsaku Yamahata pcie_aer_root_set_vector(d, ioh3420_aer_vector(d)); 6661620c2fSIsaku Yamahata } 6761620c2fSIsaku Yamahata 688135aeedSIsaku Yamahata static void ioh3420_write_config(PCIDevice *d, 698135aeedSIsaku Yamahata uint32_t address, uint32_t val, int len) 708135aeedSIsaku Yamahata { 7161620c2fSIsaku Yamahata uint32_t root_cmd = 7261620c2fSIsaku Yamahata pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND); 7361620c2fSIsaku Yamahata 748135aeedSIsaku Yamahata pci_bridge_write_config(d, address, val, len); 7561620c2fSIsaku Yamahata ioh3420_aer_vector_update(d); 766bde6aaaSMichael S. Tsirkin pcie_cap_slot_write_config(d, address, val, len); 7761620c2fSIsaku Yamahata pcie_aer_write_config(d, address, val, len); 7861620c2fSIsaku Yamahata pcie_aer_root_write_config(d, address, val, len, root_cmd); 798135aeedSIsaku Yamahata } 808135aeedSIsaku Yamahata 818135aeedSIsaku Yamahata static void ioh3420_reset(DeviceState *qdev) 828135aeedSIsaku Yamahata { 8340021f08SAnthony Liguori PCIDevice *d = PCI_DEVICE(qdev); 84cbd2d434SJan Kiszka 8561620c2fSIsaku Yamahata ioh3420_aer_vector_update(d); 868135aeedSIsaku Yamahata pcie_cap_root_reset(d); 878135aeedSIsaku Yamahata pcie_cap_deverr_reset(d); 888135aeedSIsaku Yamahata pcie_cap_slot_reset(d); 89a74b8702SKnut Omang pcie_cap_arifwd_reset(d); 9061620c2fSIsaku Yamahata pcie_aer_root_reset(d); 918135aeedSIsaku Yamahata pci_bridge_reset(qdev); 928135aeedSIsaku Yamahata pci_bridge_disable_base_limit(d); 938135aeedSIsaku Yamahata } 948135aeedSIsaku Yamahata 958135aeedSIsaku Yamahata static int ioh3420_initfn(PCIDevice *d) 968135aeedSIsaku Yamahata { 97bcb75750SAndreas Färber PCIEPort *p = PCIE_PORT(d); 98bcb75750SAndreas Färber PCIESlot *s = PCIE_SLOT(d); 998135aeedSIsaku Yamahata int rc; 1008135aeedSIsaku Yamahata 1019cfaa007SCao jin pci_bridge_initfn(d, TYPE_PCIE_BUS); 1028135aeedSIsaku Yamahata pcie_port_init_reg(d); 1038135aeedSIsaku Yamahata 1048135aeedSIsaku Yamahata rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET, 1058135aeedSIsaku Yamahata IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID); 1068135aeedSIsaku Yamahata if (rc < 0) { 10761620c2fSIsaku Yamahata goto err_bridge; 1088135aeedSIsaku Yamahata } 109*52ea63deSCao jin 1108135aeedSIsaku Yamahata rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR, 1118135aeedSIsaku Yamahata IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, 1128135aeedSIsaku Yamahata IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); 1138135aeedSIsaku Yamahata if (rc < 0) { 11461620c2fSIsaku Yamahata goto err_bridge; 1158135aeedSIsaku Yamahata } 116*52ea63deSCao jin 1178135aeedSIsaku Yamahata rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port); 1188135aeedSIsaku Yamahata if (rc < 0) { 11961620c2fSIsaku Yamahata goto err_msi; 1208135aeedSIsaku Yamahata } 121821be9dbSKnut Omang 122a74b8702SKnut Omang pcie_cap_arifwd_init(d); 1238135aeedSIsaku Yamahata pcie_cap_deverr_init(d); 1248135aeedSIsaku Yamahata pcie_cap_slot_init(d, s->slot); 125*52ea63deSCao jin pcie_cap_root_init(d); 126*52ea63deSCao jin 1278135aeedSIsaku Yamahata pcie_chassis_create(s->chassis); 1288135aeedSIsaku Yamahata rc = pcie_chassis_add_slot(s); 1298135aeedSIsaku Yamahata if (rc < 0) { 13061620c2fSIsaku Yamahata goto err_pcie_cap; 1318135aeedSIsaku Yamahata } 132*52ea63deSCao jin 1338d86ada2SChen Fan rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF); 13461620c2fSIsaku Yamahata if (rc < 0) { 13561620c2fSIsaku Yamahata goto err; 13661620c2fSIsaku Yamahata } 13761620c2fSIsaku Yamahata pcie_aer_root_init(d); 13861620c2fSIsaku Yamahata ioh3420_aer_vector_update(d); 139*52ea63deSCao jin 1408135aeedSIsaku Yamahata return 0; 14161620c2fSIsaku Yamahata 14261620c2fSIsaku Yamahata err: 14361620c2fSIsaku Yamahata pcie_chassis_del_slot(s); 14461620c2fSIsaku Yamahata err_pcie_cap: 14561620c2fSIsaku Yamahata pcie_cap_exit(d); 14661620c2fSIsaku Yamahata err_msi: 14761620c2fSIsaku Yamahata msi_uninit(d); 14861620c2fSIsaku Yamahata err_bridge: 149f90c2bcdSAlex Williamson pci_bridge_exitfn(d); 15061620c2fSIsaku Yamahata return rc; 1518135aeedSIsaku Yamahata } 1528135aeedSIsaku Yamahata 153f90c2bcdSAlex Williamson static void ioh3420_exitfn(PCIDevice *d) 1548135aeedSIsaku Yamahata { 155bcb75750SAndreas Färber PCIESlot *s = PCIE_SLOT(d); 15661620c2fSIsaku Yamahata 15761620c2fSIsaku Yamahata pcie_aer_exit(d); 15861620c2fSIsaku Yamahata pcie_chassis_del_slot(s); 1598135aeedSIsaku Yamahata pcie_cap_exit(d); 16061620c2fSIsaku Yamahata msi_uninit(d); 161f90c2bcdSAlex Williamson pci_bridge_exitfn(d); 1628135aeedSIsaku Yamahata } 1638135aeedSIsaku Yamahata 164f23b6bdcSMarcel Apfelbaum static Property ioh3420_props[] = { 165f23b6bdcSMarcel Apfelbaum DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present, 166f23b6bdcSMarcel Apfelbaum QEMU_PCIE_SLTCAP_PCP_BITNR, true), 167f23b6bdcSMarcel Apfelbaum DEFINE_PROP_END_OF_LIST() 168f23b6bdcSMarcel Apfelbaum }; 169f23b6bdcSMarcel Apfelbaum 1708135aeedSIsaku Yamahata static const VMStateDescription vmstate_ioh3420 = { 1718135aeedSIsaku Yamahata .name = "ioh-3240-express-root-port", 1728135aeedSIsaku Yamahata .version_id = 1, 1738135aeedSIsaku Yamahata .minimum_version_id = 1, 1746bde6aaaSMichael S. Tsirkin .post_load = pcie_cap_slot_post_load, 1758135aeedSIsaku Yamahata .fields = (VMStateField[]) { 176bcb75750SAndreas Färber VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), 177bcb75750SAndreas Färber VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, 178bcb75750SAndreas Färber PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), 1798135aeedSIsaku Yamahata VMSTATE_END_OF_LIST() 1808135aeedSIsaku Yamahata } 1818135aeedSIsaku Yamahata }; 1828135aeedSIsaku Yamahata 18340021f08SAnthony Liguori static void ioh3420_class_init(ObjectClass *klass, void *data) 18440021f08SAnthony Liguori { 18539bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 18640021f08SAnthony Liguori PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 18740021f08SAnthony Liguori 18840021f08SAnthony Liguori k->is_express = 1; 18940021f08SAnthony Liguori k->is_bridge = 1; 19040021f08SAnthony Liguori k->config_write = ioh3420_write_config; 19140021f08SAnthony Liguori k->init = ioh3420_initfn; 19240021f08SAnthony Liguori k->exit = ioh3420_exitfn; 19340021f08SAnthony Liguori k->vendor_id = PCI_VENDOR_ID_INTEL; 19440021f08SAnthony Liguori k->device_id = PCI_DEVICE_ID_IOH_EPORT; 19540021f08SAnthony Liguori k->revision = PCI_DEVICE_ID_IOH_REV; 196125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 19739bffca2SAnthony Liguori dc->desc = "Intel IOH device id 3420 PCIE Root Port"; 19839bffca2SAnthony Liguori dc->reset = ioh3420_reset; 19939bffca2SAnthony Liguori dc->vmsd = &vmstate_ioh3420; 200f23b6bdcSMarcel Apfelbaum dc->props = ioh3420_props; 2018135aeedSIsaku Yamahata } 20240021f08SAnthony Liguori 2038c43a6f0SAndreas Färber static const TypeInfo ioh3420_info = { 20440021f08SAnthony Liguori .name = "ioh3420", 205bcb75750SAndreas Färber .parent = TYPE_PCIE_SLOT, 20640021f08SAnthony Liguori .class_init = ioh3420_class_init, 2078135aeedSIsaku Yamahata }; 2088135aeedSIsaku Yamahata 20983f7d43aSAndreas Färber static void ioh3420_register_types(void) 2108135aeedSIsaku Yamahata { 21139bffca2SAnthony Liguori type_register_static(&ioh3420_info); 2128135aeedSIsaku Yamahata } 2138135aeedSIsaku Yamahata 21483f7d43aSAndreas Färber type_init(ioh3420_register_types) 2158135aeedSIsaku Yamahata 2168135aeedSIsaku Yamahata /* 2178135aeedSIsaku Yamahata * Local variables: 2188135aeedSIsaku Yamahata * c-indent-level: 4 2198135aeedSIsaku Yamahata * c-basic-offset: 4 2208135aeedSIsaku Yamahata * tab-width: 8 2218135aeedSIsaku Yamahata * indent-tab-mode: nil 2228135aeedSIsaku Yamahata * End: 2238135aeedSIsaku Yamahata */ 224