|
|
1.1 ! root 1: /* ! 2: * ioh3420.c ! 3: * Intel X58 north bridge IOH ! 4: * PCI Express root port device id 3420 ! 5: * ! 6: * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> ! 7: * VA Linux Systems Japan K.K. ! 8: * ! 9: * This program is free software; you can redistribute it and/or modify ! 10: * it under the terms of the GNU General Public License as published by ! 11: * the Free Software Foundation; either version 2 of the License, or ! 12: * (at your option) any later version. ! 13: * ! 14: * This program is distributed in the hope that it will be useful, ! 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 17: * GNU General Public License for more details. ! 18: * ! 19: * You should have received a copy of the GNU General Public License along ! 20: * with this program; if not, see <http://www.gnu.org/licenses/>. ! 21: */ ! 22: ! 23: #include "pci_ids.h" ! 24: #include "msi.h" ! 25: #include "pcie.h" ! 26: #include "ioh3420.h" ! 27: ! 28: #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ ! 29: #define PCI_DEVICE_ID_IOH_REV 0x2 ! 30: #define IOH_EP_SSVID_OFFSET 0x40 ! 31: #define IOH_EP_SSVID_SVID PCI_VENDOR_ID_INTEL ! 32: #define IOH_EP_SSVID_SSID 0 ! 33: #define IOH_EP_MSI_OFFSET 0x60 ! 34: #define IOH_EP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT ! 35: #define IOH_EP_MSI_NR_VECTOR 2 ! 36: #define IOH_EP_EXP_OFFSET 0x90 ! 37: #define IOH_EP_AER_OFFSET 0x100 ! 38: ! 39: /* ! 40: * If two MSI vector are allocated, Advanced Error Interrupt Message Number ! 41: * is 1. otherwise 0. ! 42: * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number. ! 43: */ ! 44: static uint8_t ioh3420_aer_vector(const PCIDevice *d) ! 45: { ! 46: switch (msi_nr_vectors_allocated(d)) { ! 47: case 1: ! 48: return 0; ! 49: case 2: ! 50: return 1; ! 51: case 4: ! 52: case 8: ! 53: case 16: ! 54: case 32: ! 55: default: ! 56: break; ! 57: } ! 58: abort(); ! 59: return 0; ! 60: } ! 61: ! 62: static void ioh3420_aer_vector_update(PCIDevice *d) ! 63: { ! 64: pcie_aer_root_set_vector(d, ioh3420_aer_vector(d)); ! 65: } ! 66: ! 67: static void ioh3420_write_config(PCIDevice *d, ! 68: uint32_t address, uint32_t val, int len) ! 69: { ! 70: uint32_t root_cmd = ! 71: pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND); ! 72: ! 73: pci_bridge_write_config(d, address, val, len); ! 74: msi_write_config(d, address, val, len); ! 75: ioh3420_aer_vector_update(d); ! 76: pcie_cap_slot_write_config(d, address, val, len); ! 77: pcie_aer_write_config(d, address, val, len); ! 78: pcie_aer_root_write_config(d, address, val, len, root_cmd); ! 79: } ! 80: ! 81: static void ioh3420_reset(DeviceState *qdev) ! 82: { ! 83: PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); ! 84: msi_reset(d); ! 85: ioh3420_aer_vector_update(d); ! 86: pcie_cap_root_reset(d); ! 87: pcie_cap_deverr_reset(d); ! 88: pcie_cap_slot_reset(d); ! 89: pcie_aer_root_reset(d); ! 90: pci_bridge_reset(qdev); ! 91: pci_bridge_disable_base_limit(d); ! 92: } ! 93: ! 94: static int ioh3420_initfn(PCIDevice *d) ! 95: { ! 96: PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); ! 97: PCIEPort *p = DO_UPCAST(PCIEPort, br, br); ! 98: PCIESlot *s = DO_UPCAST(PCIESlot, port, p); ! 99: int rc; ! 100: int tmp; ! 101: ! 102: rc = pci_bridge_initfn(d); ! 103: if (rc < 0) { ! 104: return rc; ! 105: } ! 106: ! 107: d->config[PCI_REVISION_ID] = PCI_DEVICE_ID_IOH_REV; ! 108: pcie_port_init_reg(d); ! 109: ! 110: pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL); ! 111: pci_config_set_device_id(d->config, PCI_DEVICE_ID_IOH_EPORT); ! 112: ! 113: rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET, ! 114: IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID); ! 115: if (rc < 0) { ! 116: goto err_bridge; ! 117: } ! 118: rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR, ! 119: IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, ! 120: IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); ! 121: if (rc < 0) { ! 122: goto err_bridge; ! 123: } ! 124: rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port); ! 125: if (rc < 0) { ! 126: goto err_msi; ! 127: } ! 128: pcie_cap_deverr_init(d); ! 129: pcie_cap_slot_init(d, s->slot); ! 130: pcie_chassis_create(s->chassis); ! 131: rc = pcie_chassis_add_slot(s); ! 132: if (rc < 0) { ! 133: goto err_pcie_cap; ! 134: return rc; ! 135: } ! 136: pcie_cap_root_init(d); ! 137: rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); ! 138: if (rc < 0) { ! 139: goto err; ! 140: } ! 141: pcie_aer_root_init(d); ! 142: ioh3420_aer_vector_update(d); ! 143: return 0; ! 144: ! 145: err: ! 146: pcie_chassis_del_slot(s); ! 147: err_pcie_cap: ! 148: pcie_cap_exit(d); ! 149: err_msi: ! 150: msi_uninit(d); ! 151: err_bridge: ! 152: tmp = pci_bridge_exitfn(d); ! 153: assert(!tmp); ! 154: return rc; ! 155: } ! 156: ! 157: static int ioh3420_exitfn(PCIDevice *d) ! 158: { ! 159: PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); ! 160: PCIEPort *p = DO_UPCAST(PCIEPort, br, br); ! 161: PCIESlot *s = DO_UPCAST(PCIESlot, port, p); ! 162: ! 163: pcie_aer_exit(d); ! 164: pcie_chassis_del_slot(s); ! 165: pcie_cap_exit(d); ! 166: msi_uninit(d); ! 167: return pci_bridge_exitfn(d); ! 168: } ! 169: ! 170: PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, ! 171: const char *bus_name, pci_map_irq_fn map_irq, ! 172: uint8_t port, uint8_t chassis, uint16_t slot) ! 173: { ! 174: PCIDevice *d; ! 175: PCIBridge *br; ! 176: DeviceState *qdev; ! 177: ! 178: d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420"); ! 179: if (!d) { ! 180: return NULL; ! 181: } ! 182: br = DO_UPCAST(PCIBridge, dev, d); ! 183: ! 184: qdev = &br->dev.qdev; ! 185: pci_bridge_map_irq(br, bus_name, map_irq); ! 186: qdev_prop_set_uint8(qdev, "port", port); ! 187: qdev_prop_set_uint8(qdev, "chassis", chassis); ! 188: qdev_prop_set_uint16(qdev, "slot", slot); ! 189: qdev_init_nofail(qdev); ! 190: ! 191: return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br)); ! 192: } ! 193: ! 194: static const VMStateDescription vmstate_ioh3420 = { ! 195: .name = "ioh-3240-express-root-port", ! 196: .version_id = 1, ! 197: .minimum_version_id = 1, ! 198: .minimum_version_id_old = 1, ! 199: .post_load = pcie_cap_slot_post_load, ! 200: .fields = (VMStateField[]) { ! 201: VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot), ! 202: VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0, ! 203: vmstate_pcie_aer_log, PCIEAERLog), ! 204: VMSTATE_END_OF_LIST() ! 205: } ! 206: }; ! 207: ! 208: static PCIDeviceInfo ioh3420_info = { ! 209: .qdev.name = "ioh3420", ! 210: .qdev.desc = "Intel IOH device id 3420 PCIE Root Port", ! 211: .qdev.size = sizeof(PCIESlot), ! 212: .qdev.reset = ioh3420_reset, ! 213: .qdev.vmsd = &vmstate_ioh3420, ! 214: ! 215: .is_express = 1, ! 216: .is_bridge = 1, ! 217: .config_write = ioh3420_write_config, ! 218: .init = ioh3420_initfn, ! 219: .exit = ioh3420_exitfn, ! 220: ! 221: .qdev.props = (Property[]) { ! 222: DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), ! 223: DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), ! 224: DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), ! 225: DEFINE_PROP_UINT16("aer_log_max", PCIESlot, ! 226: port.br.dev.exp.aer_log.log_max, ! 227: PCIE_AER_LOG_MAX_DEFAULT), ! 228: DEFINE_PROP_END_OF_LIST(), ! 229: } ! 230: }; ! 231: ! 232: static void ioh3420_register(void) ! 233: { ! 234: pci_qdev_register(&ioh3420_info); ! 235: } ! 236: ! 237: device_init(ioh3420_register); ! 238: ! 239: /* ! 240: * Local variables: ! 241: * c-indent-level: 4 ! 242: * c-basic-offset: 4 ! 243: * tab-width: 8 ! 244: * indent-tab-mode: nil ! 245: * End: ! 246: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.