xref: /qemu/hw/pci-bridge/ioh3420.c (revision 821be9dbb220389eaa6857705e1df9e64888138f)
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 {
95bcb75750SAndreas Färber     PCIEPort *p = PCIE_PORT(d);
96bcb75750SAndreas Färber     PCIESlot *s = PCIE_SLOT(d);
978135aeedSIsaku Yamahata     int rc;
988135aeedSIsaku Yamahata 
99afb661ebSAlex Williamson     rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
1008135aeedSIsaku Yamahata     if (rc < 0) {
1018135aeedSIsaku Yamahata         return rc;
1028135aeedSIsaku Yamahata     }
1038135aeedSIsaku Yamahata 
1048135aeedSIsaku Yamahata     pcie_port_init_reg(d);
1058135aeedSIsaku Yamahata 
1068135aeedSIsaku Yamahata     rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
1078135aeedSIsaku Yamahata                                IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
1088135aeedSIsaku Yamahata     if (rc < 0) {
10961620c2fSIsaku Yamahata         goto err_bridge;
1108135aeedSIsaku Yamahata     }
1118135aeedSIsaku Yamahata     rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
1128135aeedSIsaku Yamahata                   IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
1138135aeedSIsaku Yamahata                   IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
1148135aeedSIsaku Yamahata     if (rc < 0) {
11561620c2fSIsaku Yamahata         goto err_bridge;
1168135aeedSIsaku Yamahata     }
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     }
121*821be9dbSKnut Omang 
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 {
151bcb75750SAndreas Färber     PCIESlot *s = PCIE_SLOT(d);
15261620c2fSIsaku Yamahata 
15361620c2fSIsaku Yamahata     pcie_aer_exit(d);
15461620c2fSIsaku Yamahata     pcie_chassis_del_slot(s);
1558135aeedSIsaku Yamahata     pcie_cap_exit(d);
15661620c2fSIsaku Yamahata     msi_uninit(d);
157f90c2bcdSAlex Williamson     pci_bridge_exitfn(d);
1588135aeedSIsaku Yamahata }
1598135aeedSIsaku Yamahata 
1608135aeedSIsaku Yamahata PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
1618135aeedSIsaku Yamahata                          const char *bus_name, pci_map_irq_fn map_irq,
1628135aeedSIsaku Yamahata                          uint8_t port, uint8_t chassis, uint16_t slot)
1638135aeedSIsaku Yamahata {
1648135aeedSIsaku Yamahata     PCIDevice *d;
1658135aeedSIsaku Yamahata     PCIBridge *br;
1668135aeedSIsaku Yamahata     DeviceState *qdev;
1678135aeedSIsaku Yamahata 
1688135aeedSIsaku Yamahata     d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
1698135aeedSIsaku Yamahata     if (!d) {
1708135aeedSIsaku Yamahata         return NULL;
1718135aeedSIsaku Yamahata     }
172f055e96bSAndreas Färber     br = PCI_BRIDGE(d);
1738135aeedSIsaku Yamahata 
174f055e96bSAndreas Färber     qdev = DEVICE(d);
1758135aeedSIsaku Yamahata     pci_bridge_map_irq(br, bus_name, map_irq);
1768135aeedSIsaku Yamahata     qdev_prop_set_uint8(qdev, "port", port);
1778135aeedSIsaku Yamahata     qdev_prop_set_uint8(qdev, "chassis", chassis);
1788135aeedSIsaku Yamahata     qdev_prop_set_uint16(qdev, "slot", slot);
1798135aeedSIsaku Yamahata     qdev_init_nofail(qdev);
1808135aeedSIsaku Yamahata 
181bcb75750SAndreas Färber     return PCIE_SLOT(d);
1828135aeedSIsaku Yamahata }
1838135aeedSIsaku Yamahata 
184f23b6bdcSMarcel Apfelbaum static Property ioh3420_props[] = {
185f23b6bdcSMarcel Apfelbaum     DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
186f23b6bdcSMarcel Apfelbaum                     QEMU_PCIE_SLTCAP_PCP_BITNR, true),
187f23b6bdcSMarcel Apfelbaum     DEFINE_PROP_END_OF_LIST()
188f23b6bdcSMarcel Apfelbaum };
189f23b6bdcSMarcel Apfelbaum 
1908135aeedSIsaku Yamahata static const VMStateDescription vmstate_ioh3420 = {
1918135aeedSIsaku Yamahata     .name = "ioh-3240-express-root-port",
1928135aeedSIsaku Yamahata     .version_id = 1,
1938135aeedSIsaku Yamahata     .minimum_version_id = 1,
1946bde6aaaSMichael S. Tsirkin     .post_load = pcie_cap_slot_post_load,
1958135aeedSIsaku Yamahata     .fields = (VMStateField[]) {
196bcb75750SAndreas Färber         VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
197bcb75750SAndreas Färber         VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
198bcb75750SAndreas Färber                        PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
1998135aeedSIsaku Yamahata         VMSTATE_END_OF_LIST()
2008135aeedSIsaku Yamahata     }
2018135aeedSIsaku Yamahata };
2028135aeedSIsaku Yamahata 
20340021f08SAnthony Liguori static void ioh3420_class_init(ObjectClass *klass, void *data)
20440021f08SAnthony Liguori {
20539bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
20640021f08SAnthony Liguori     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
20740021f08SAnthony Liguori 
20840021f08SAnthony Liguori     k->is_express = 1;
20940021f08SAnthony Liguori     k->is_bridge = 1;
21040021f08SAnthony Liguori     k->config_write = ioh3420_write_config;
21140021f08SAnthony Liguori     k->init = ioh3420_initfn;
21240021f08SAnthony Liguori     k->exit = ioh3420_exitfn;
21340021f08SAnthony Liguori     k->vendor_id = PCI_VENDOR_ID_INTEL;
21440021f08SAnthony Liguori     k->device_id = PCI_DEVICE_ID_IOH_EPORT;
21540021f08SAnthony Liguori     k->revision = PCI_DEVICE_ID_IOH_REV;
216125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
21739bffca2SAnthony Liguori     dc->desc = "Intel IOH device id 3420 PCIE Root Port";
21839bffca2SAnthony Liguori     dc->reset = ioh3420_reset;
21939bffca2SAnthony Liguori     dc->vmsd = &vmstate_ioh3420;
220f23b6bdcSMarcel Apfelbaum     dc->props = ioh3420_props;
2218135aeedSIsaku Yamahata }
22240021f08SAnthony Liguori 
2238c43a6f0SAndreas Färber static const TypeInfo ioh3420_info = {
22440021f08SAnthony Liguori     .name          = "ioh3420",
225bcb75750SAndreas Färber     .parent        = TYPE_PCIE_SLOT,
22640021f08SAnthony Liguori     .class_init    = ioh3420_class_init,
2278135aeedSIsaku Yamahata };
2288135aeedSIsaku Yamahata 
22983f7d43aSAndreas Färber static void ioh3420_register_types(void)
2308135aeedSIsaku Yamahata {
23139bffca2SAnthony Liguori     type_register_static(&ioh3420_info);
2328135aeedSIsaku Yamahata }
2338135aeedSIsaku Yamahata 
23483f7d43aSAndreas Färber type_init(ioh3420_register_types)
2358135aeedSIsaku Yamahata 
2368135aeedSIsaku Yamahata /*
2378135aeedSIsaku Yamahata  * Local variables:
2388135aeedSIsaku Yamahata  *  c-indent-level: 4
2398135aeedSIsaku Yamahata  *  c-basic-offset: 4
2408135aeedSIsaku Yamahata  *  tab-width: 8
2418135aeedSIsaku Yamahata  *  indent-tab-mode: nil
2428135aeedSIsaku Yamahata  * End:
2438135aeedSIsaku Yamahata  */
244