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"
27cd1f0ca2SPhilippe Mathieu-Daudé #include "hw/pci/pcie_port.h"
28d6454270SMarkus Armbruster #include "migration/vmstate.h"
290b8fa32fSMarkus Armbruster #include "qemu/module.h"
308135aeedSIsaku Yamahata
318135aeedSIsaku Yamahata #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */
328135aeedSIsaku Yamahata #define PCI_DEVICE_ID_IOH_REV 0x2
338135aeedSIsaku Yamahata #define IOH_EP_SSVID_OFFSET 0x40
348135aeedSIsaku Yamahata #define IOH_EP_SSVID_SVID PCI_VENDOR_ID_INTEL
358135aeedSIsaku Yamahata #define IOH_EP_SSVID_SSID 0
368135aeedSIsaku Yamahata #define IOH_EP_MSI_OFFSET 0x60
378135aeedSIsaku Yamahata #define IOH_EP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT
388135aeedSIsaku Yamahata #define IOH_EP_MSI_NR_VECTOR 2
398135aeedSIsaku Yamahata #define IOH_EP_EXP_OFFSET 0x90
408135aeedSIsaku Yamahata #define IOH_EP_AER_OFFSET 0x100
418135aeedSIsaku Yamahata
4261620c2fSIsaku Yamahata /*
4361620c2fSIsaku Yamahata * If two MSI vector are allocated, Advanced Error Interrupt Message Number
4461620c2fSIsaku Yamahata * is 1. otherwise 0.
4561620c2fSIsaku Yamahata * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number.
4661620c2fSIsaku Yamahata */
ioh3420_aer_vector(const PCIDevice * d)4761620c2fSIsaku Yamahata static uint8_t ioh3420_aer_vector(const PCIDevice *d)
4861620c2fSIsaku Yamahata {
4961620c2fSIsaku Yamahata switch (msi_nr_vectors_allocated(d)) {
5061620c2fSIsaku Yamahata case 1:
5161620c2fSIsaku Yamahata return 0;
5261620c2fSIsaku Yamahata case 2:
5361620c2fSIsaku Yamahata return 1;
5461620c2fSIsaku Yamahata case 4:
5561620c2fSIsaku Yamahata case 8:
5661620c2fSIsaku Yamahata case 16:
5761620c2fSIsaku Yamahata case 32:
5861620c2fSIsaku Yamahata default:
5961620c2fSIsaku Yamahata break;
6061620c2fSIsaku Yamahata }
6161620c2fSIsaku Yamahata abort();
6261620c2fSIsaku Yamahata return 0;
6361620c2fSIsaku Yamahata }
6461620c2fSIsaku Yamahata
ioh3420_interrupts_init(PCIDevice * d,Error ** errp)65fed23cb4SMarcel Apfelbaum static int ioh3420_interrupts_init(PCIDevice *d, Error **errp)
6661620c2fSIsaku Yamahata {
678135aeedSIsaku Yamahata int rc;
6852ea63deSCao jin
698135aeedSIsaku Yamahata rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
708135aeedSIsaku Yamahata IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
71fed23cb4SMarcel Apfelbaum IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
7206592d7eSMao Zhongyi errp);
738135aeedSIsaku Yamahata if (rc < 0) {
741108b2f8SCao jin assert(rc == -ENOTSUP);
758135aeedSIsaku Yamahata }
7652ea63deSCao jin
7761620c2fSIsaku Yamahata return rc;
788135aeedSIsaku Yamahata }
798135aeedSIsaku Yamahata
ioh3420_interrupts_uninit(PCIDevice * d)80fed23cb4SMarcel Apfelbaum static void ioh3420_interrupts_uninit(PCIDevice *d)
818135aeedSIsaku Yamahata {
8261620c2fSIsaku Yamahata msi_uninit(d);
838135aeedSIsaku Yamahata }
848135aeedSIsaku Yamahata
858135aeedSIsaku Yamahata static const VMStateDescription vmstate_ioh3420 = {
868135aeedSIsaku Yamahata .name = "ioh-3240-express-root-port",
879d6b9db1SPeter Xu .priority = MIG_PRI_PCI_BUS,
888135aeedSIsaku Yamahata .version_id = 1,
898135aeedSIsaku Yamahata .minimum_version_id = 1,
906bde6aaaSMichael S. Tsirkin .post_load = pcie_cap_slot_post_load,
91f026c578SRichard Henderson .fields = (const VMStateField[]) {
9220daa90aSDr. David Alan Gilbert VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
93bcb75750SAndreas Färber VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
94bcb75750SAndreas Färber PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
958135aeedSIsaku Yamahata VMSTATE_END_OF_LIST()
968135aeedSIsaku Yamahata }
978135aeedSIsaku Yamahata };
988135aeedSIsaku Yamahata
ioh3420_class_init(ObjectClass * klass,const void * data)99*12d1a768SPhilippe Mathieu-Daudé static void ioh3420_class_init(ObjectClass *klass, const void *data)
10040021f08SAnthony Liguori {
10139bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass);
10240021f08SAnthony Liguori PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
103fed23cb4SMarcel Apfelbaum PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
10440021f08SAnthony Liguori
10540021f08SAnthony Liguori k->vendor_id = PCI_VENDOR_ID_INTEL;
10640021f08SAnthony Liguori k->device_id = PCI_DEVICE_ID_IOH_EPORT;
10740021f08SAnthony Liguori k->revision = PCI_DEVICE_ID_IOH_REV;
10839bffca2SAnthony Liguori dc->desc = "Intel IOH device id 3420 PCIE Root Port";
10939bffca2SAnthony Liguori dc->vmsd = &vmstate_ioh3420;
110fed23cb4SMarcel Apfelbaum rpc->aer_vector = ioh3420_aer_vector;
111fed23cb4SMarcel Apfelbaum rpc->interrupts_init = ioh3420_interrupts_init;
112fed23cb4SMarcel Apfelbaum rpc->interrupts_uninit = ioh3420_interrupts_uninit;
113fed23cb4SMarcel Apfelbaum rpc->exp_offset = IOH_EP_EXP_OFFSET;
114fed23cb4SMarcel Apfelbaum rpc->aer_offset = IOH_EP_AER_OFFSET;
115fed23cb4SMarcel Apfelbaum rpc->ssvid_offset = IOH_EP_SSVID_OFFSET;
116fed23cb4SMarcel Apfelbaum rpc->ssid = IOH_EP_SSVID_SSID;
1178135aeedSIsaku Yamahata }
11840021f08SAnthony Liguori
1198c43a6f0SAndreas Färber static const TypeInfo ioh3420_info = {
12040021f08SAnthony Liguori .name = "ioh3420",
121fed23cb4SMarcel Apfelbaum .parent = TYPE_PCIE_ROOT_PORT,
12240021f08SAnthony Liguori .class_init = ioh3420_class_init,
1238135aeedSIsaku Yamahata };
1248135aeedSIsaku Yamahata
ioh3420_register_types(void)12583f7d43aSAndreas Färber static void ioh3420_register_types(void)
1268135aeedSIsaku Yamahata {
12739bffca2SAnthony Liguori type_register_static(&ioh3420_info);
1288135aeedSIsaku Yamahata }
1298135aeedSIsaku Yamahata
13083f7d43aSAndreas Färber type_init(ioh3420_register_types)
131