3d6a69b6eb
The CXL Early Discovery Table is defined in the CXL 2.0 specification as a way for the OS to get CXL specific information from the system firmware. CXL 2.0 specification adds an _HID, ACPI0016, for CXL capable host bridges, with a _CID of PNP0A08 (PCIe host bridge). CXL aware software is able to use this initiate the proper _OSC method, and get the _UID which is referenced by the CEDT. Therefore the existence of an ACPI0016 device allows a CXL aware driver perform the necessary actions. For a CXL capable OS, this works. For a CXL unaware OS, this works. CEDT awaremess requires more. The motivation for ACPI0017 is to provide the possibility of having a Linux CXL module that can work on a legacy Linux kernel. Linux core PCI/ACPI which won't be built as a module, will see the _CID of PNP0A08 and bind a driver to it. If we later loaded a driver for ACPI0016, Linux won't be able to bind it to the hardware because it has already bound the PNP0A08 driver. The ACPI0017 device is an opportunity to have an object to bind a driver will be used by a Linux driver to walk the CXL topology and do everything that we would have preferred to do with ACPI0016. There is another motivation for an ACPI0017 device which isn't implemented here. An operating system needs an attach point for a non-volatile region provider that understands cross-hostbridge interleaving. Since QEMU emulation doesn't support interleaving yet, this is more important on the OS side, for now. As of CXL 2.0 spec, only 1 sub structure is defined, the CXL Host Bridge Structure (CHBS) which is primarily useful for telling the OS exactly where the MMIO for the host bridge is. Link: https://lore.kernel.org/linux-cxl/20210115034911.nkgpzc756d6qmjpl@intel.com/T/#t Signed-off-by: Ben Widawsky <ben.widawsky@intel.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20220429144110.25167-26-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
187 lines
6.5 KiB
C
187 lines
6.5 KiB
C
/*
|
|
* QEMU PCI bridge
|
|
*
|
|
* Copyright (c) 2004 Fabrice Bellard
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
|
|
* Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
|
|
* VA Linux Systems Japan K.K.
|
|
*
|
|
*/
|
|
|
|
#ifndef QEMU_PCI_BRIDGE_H
|
|
#define QEMU_PCI_BRIDGE_H
|
|
|
|
#include "hw/pci/pci.h"
|
|
#include "hw/pci/pci_bus.h"
|
|
#include "hw/cxl/cxl.h"
|
|
#include "qom/object.h"
|
|
|
|
typedef struct PCIBridgeWindows PCIBridgeWindows;
|
|
|
|
/*
|
|
* Aliases for each of the address space windows that the bridge
|
|
* can forward. Mapped into the bridge's parent's address space,
|
|
* as subregions.
|
|
*/
|
|
struct PCIBridgeWindows {
|
|
MemoryRegion alias_pref_mem;
|
|
MemoryRegion alias_mem;
|
|
MemoryRegion alias_io;
|
|
/*
|
|
* When bridge control VGA forwarding is enabled, bridges will
|
|
* provide positive decode on the PCI VGA defined I/O port and
|
|
* MMIO ranges. When enabled forwarding is only qualified on the
|
|
* I/O and memory enable bits in the bridge command register.
|
|
*/
|
|
MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS];
|
|
};
|
|
|
|
#define TYPE_PCI_BRIDGE "base-pci-bridge"
|
|
OBJECT_DECLARE_SIMPLE_TYPE(PCIBridge, PCI_BRIDGE)
|
|
|
|
struct PCIBridge {
|
|
/*< private >*/
|
|
PCIDevice parent_obj;
|
|
/*< public >*/
|
|
|
|
/* private member */
|
|
PCIBus sec_bus;
|
|
/*
|
|
* Memory regions for the bridge's address spaces. These regions are not
|
|
* directly added to system_memory/system_io or its descendants.
|
|
* Bridge's secondary bus points to these, so that devices
|
|
* under the bridge see these regions as its address spaces.
|
|
* The regions are as large as the entire address space -
|
|
* they don't take into account any windows.
|
|
*/
|
|
MemoryRegion address_space_mem;
|
|
MemoryRegion address_space_io;
|
|
|
|
PCIBridgeWindows *windows;
|
|
|
|
pci_map_irq_fn map_irq;
|
|
const char *bus_name;
|
|
};
|
|
|
|
#define PCI_BRIDGE_DEV_PROP_CHASSIS_NR "chassis_nr"
|
|
#define PCI_BRIDGE_DEV_PROP_MSI "msi"
|
|
#define PCI_BRIDGE_DEV_PROP_SHPC "shpc"
|
|
typedef struct CXLHost CXLHost;
|
|
|
|
struct PXBDev {
|
|
/*< private >*/
|
|
PCIDevice parent_obj;
|
|
/*< public >*/
|
|
|
|
uint8_t bus_nr;
|
|
uint16_t numa_node;
|
|
bool bypass_iommu;
|
|
struct cxl_dev {
|
|
CXLHost *cxl_host_bridge; /* Pointer to a CXLHost */
|
|
} cxl;
|
|
};
|
|
|
|
typedef struct PXBDev PXBDev;
|
|
#define TYPE_PXB_CXL_DEVICE "pxb-cxl"
|
|
DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV,
|
|
TYPE_PXB_CXL_DEVICE)
|
|
|
|
int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
|
|
uint16_t svid, uint16_t ssid,
|
|
Error **errp);
|
|
|
|
PCIDevice *pci_bridge_get_device(PCIBus *bus);
|
|
PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
|
|
|
|
pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
|
|
pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
|
|
|
|
void pci_bridge_update_mappings(PCIBridge *br);
|
|
void pci_bridge_write_config(PCIDevice *d,
|
|
uint32_t address, uint32_t val, int len);
|
|
void pci_bridge_disable_base_limit(PCIDevice *dev);
|
|
void pci_bridge_reset(DeviceState *qdev);
|
|
|
|
void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
|
|
void pci_bridge_exitfn(PCIDevice *pci_dev);
|
|
|
|
void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
Error **errp);
|
|
void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
Error **errp);
|
|
void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|
DeviceState *dev, Error **errp);
|
|
|
|
/*
|
|
* before qdev initialization(qdev_init()), this function sets bus_name and
|
|
* map_irq callback which are necessary for pci_bridge_initfn() to
|
|
* initialize bus.
|
|
*/
|
|
void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
|
|
pci_map_irq_fn map_irq);
|
|
|
|
/* TODO: add this define to pci_regs.h in linux and then in qemu. */
|
|
#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
|
|
#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */
|
|
#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */
|
|
#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */
|
|
#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */
|
|
|
|
typedef struct PCIBridgeQemuCap {
|
|
uint8_t id; /* Standard PCI capability header field */
|
|
uint8_t next; /* Standard PCI capability header field */
|
|
uint8_t len; /* Standard PCI vendor-specific capability header field */
|
|
uint8_t type; /* Red Hat vendor-specific capability type.
|
|
Types are defined with REDHAT_PCI_CAP_ prefix */
|
|
|
|
uint32_t bus_res; /* Minimum number of buses to reserve */
|
|
uint64_t io; /* IO space to reserve */
|
|
uint32_t mem; /* Non-prefetchable memory to reserve */
|
|
/* At most one of the following two fields may be set to a value
|
|
* different from -1 */
|
|
uint32_t mem_pref_32; /* Prefetchable memory to reserve (32-bit MMIO) */
|
|
uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */
|
|
} PCIBridgeQemuCap;
|
|
|
|
#define REDHAT_PCI_CAP_TYPE_OFFSET 3
|
|
#define REDHAT_PCI_CAP_RESOURCE_RESERVE 1
|
|
|
|
/*
|
|
* PCI BUS/IO/MEM/PREFMEM additional resources recorded as a
|
|
* capability in PCI configuration space to reserve on firmware init.
|
|
*/
|
|
typedef struct PCIResReserve {
|
|
uint32_t bus;
|
|
uint64_t io;
|
|
uint64_t mem_non_pref;
|
|
uint64_t mem_pref_32;
|
|
uint64_t mem_pref_64;
|
|
} PCIResReserve;
|
|
|
|
#define REDHAT_PCI_CAP_RES_RESERVE_BUS_RES 4
|
|
#define REDHAT_PCI_CAP_RES_RESERVE_IO 8
|
|
#define REDHAT_PCI_CAP_RES_RESERVE_MEM 16
|
|
#define REDHAT_PCI_CAP_RES_RESERVE_PREF_MEM_32 20
|
|
#define REDHAT_PCI_CAP_RES_RESERVE_PREF_MEM_64 24
|
|
#define REDHAT_PCI_CAP_RES_RESERVE_CAP_SIZE 32
|
|
|
|
int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
|
|
PCIResReserve res_reserve, Error **errp);
|
|
|
|
#endif /* QEMU_PCI_BRIDGE_H */
|