[SeaBIOS] [PATCH v3 2/5] hw/pci: introduce pcie-pci-bridge device
Alexander Bezzubikov
zuban32s at gmail.com
Mon Jul 31 20:40:41 CEST 2017
2017-07-31 14:23 GMT+03:00 Marcel Apfelbaum <marcel at redhat.com>:
> On 29/07/2017 2:37, Aleksandr Bezzubikov wrote:
>>
>> Introduce a new PCIExpress-to-PCI Bridge device,
>> which is a hot-pluggable PCI Express device and
>> supports devices hot-plug with SHPC.
>>
>> This device is intended to replace the DMI-to-PCI
>> Bridge in an overwhelming majority of use-cases.
>>
>> Signed-off-by: Aleksandr Bezzubikov <zuban32s at gmail.com>
>> ---
>> hw/pci-bridge/Makefile.objs | 2 +-
>> hw/pci-bridge/pcie_pci_bridge.c | 220
>> ++++++++++++++++++++++++++++++++++++++++
>> include/hw/pci/pci.h | 1 +
>> 3 files changed, 222 insertions(+), 1 deletion(-)
>> create mode 100644 hw/pci-bridge/pcie_pci_bridge.c
>>
>> diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
>> index c4683cf..666db37 100644
>> --- a/hw/pci-bridge/Makefile.objs
>> +++ b/hw/pci-bridge/Makefile.objs
>> @@ -1,4 +1,4 @@
>> -common-obj-y += pci_bridge_dev.o
>> +common-obj-y += pci_bridge_dev.o pcie_pci_bridge.o
>> common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o
>> common-obj-$(CONFIG_PXB) += pci_expander_bridge.o
>> common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
>> diff --git a/hw/pci-bridge/pcie_pci_bridge.c
>> b/hw/pci-bridge/pcie_pci_bridge.c
>> new file mode 100644
>> index 0000000..c28f820
>> --- /dev/null
>> +++ b/hw/pci-bridge/pcie_pci_bridge.c
>> @@ -0,0 +1,220 @@
>> +/*
>> + * QEMU Generic PCIE-PCI Bridge
>> + *
>> + * Copyright (c) 2017 Aleksandr Bezzubikov
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining
>> a copy
>> + * of this software and associated documentation files (the "Software"),
>> to deal
>> + * in the Software without restriction, including without limitation the
>> rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or
>> sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be
>> included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>> SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> IN
>> + * THE SOFTWARE.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "hw/pci/pci.h"
>> +#include "hw/pci/pci_bus.h"
>> +#include "hw/pci/pci_bridge.h"
>> +#include "hw/pci/msi.h"
>> +#include "hw/pci/shpc.h"
>> +#include "hw/pci/slotid_cap.h"
>> +
>
>
> Hi Aleksander,
Hi Marcel,
thanks for the review
>
>> +typedef struct PCIEPCIBridge {
>> + /*< private >*/
>> + PCIBridge parent_obj;
>> +
>> + bool msi_enable;
>
>
> Please rename the msi_enable property to "msi" in order
> to be aligned with the existent PCIBridgeDev and
> consider making it OnOffAuto for the same reason.
> (I am not sure about the last part though, we have
> no meaning for "auto" here)
>
Agreed about "msi", but OnOffAuto looks weird to me
as we always want MSI to be enabled.
>> + MemoryRegion bar;
>
>
> I suggest renaming it to shpc_bar, it will make the code
> more readable.
>
OK.
>> + /*< public >*/
>> +} PCIEPCIBridge;
>> +
>> +#define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge"
>> +#define PCIE_PCI_BRIDGE_DEV(obj) \
>> + OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV)
>> +
>> +static void pciepci_bridge_realize(PCIDevice *d, Error **errp)
>> +{
>> + PCIBridge *br = PCI_BRIDGE(d);
>> + PCIEPCIBridge *pcie_br = PCIE_PCI_BRIDGE_DEV(d);
>> + int rc, pos;
>> + Error *local_err = NULL;
>
>
> Since you don't "create" errors in this function, you
> could simply pass errp to the functions and not use
> local_err, it will save some code lines.
>
>
>> +
>> + pci_bridge_initfn(d, TYPE_PCI_BUS);
>> +
>> + d->config[PCI_INTERRUPT_PIN] = 0x1;
>> + memory_region_init(&pcie_br->bar, OBJECT(d), "shpc-bar",
>> + shpc_bar_size(d));
>> + rc = shpc_init(d, &br->sec_bus, &pcie_br->bar, 0, &local_err);
>> + if (rc) {
>> + error_propagate(errp, local_err);
>> + goto error;
>> + }
>> +
>> + rc = pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0, &local_err);
>> + if (rc < 0) {
>> + error_propagate(errp, local_err);
>> + goto cap_error;
>> + }
>> +
>> + pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF,
>> &local_err);
>> + if (pos < 0) {
>> + error_propagate(errp, local_err);
>> + goto pm_error;
>> + }
>> + d->exp.pm_cap = pos;
>> + pci_set_word(d->config + pos + PCI_PM_PMC, 0x3);
>> +
>> + pcie_cap_arifwd_init(d);
>> + pcie_cap_deverr_init(d);
>> +
>> + rc = pcie_aer_init(d, PCI_ERR_VER, 0x100, PCI_ERR_SIZEOF,
>> &local_err);
>> + if (rc < 0) {
>> + error_propagate(errp, local_err);
>> + goto aer_error;
>> + }
>> +
>> + if (pcie_br->msi_enable) {
>> + rc = msi_init(d, 0, 1, true, true, &local_err);
>> + if (rc < 0) {
>> + error_propagate(errp, local_err);
>> + goto msi_error;
>> + }
>> + }
>> + pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
>> + PCI_BASE_ADDRESS_MEM_TYPE_64, &pcie_br->bar);
>> + return;
>> +
>> +msi_error:
>> + pcie_aer_exit(d);
>> +aer_error:
>> +pm_error:
>> + pcie_cap_exit(d);
>> +cap_error:
>> + shpc_free(d);
>> +error:
>> + pci_bridge_exitfn(d);
>> +}
>> +
>> +static void pciepci_bridge_exit(PCIDevice *d)
>> +{
>> + PCIEPCIBridge *bridge_dev = PCIE_PCI_BRIDGE_DEV(d);
>> + pcie_cap_exit(d);
>> + shpc_cleanup(d, &bridge_dev->bar);
>> + pci_bridge_exitfn(d);
>> +}
>> +
>> +static void pciepci_bridge_reset(DeviceState *qdev)
>> +{
>> + PCIDevice *d = PCI_DEVICE(qdev);
>> + pci_bridge_reset(qdev);
>> + msi_reset(d);
>> + shpc_reset(d);
>> +}
>> +
>> +static void pcie_pci_bridge_write_config(PCIDevice *d,
>> + uint32_t address, uint32_t val, int len)
>> +{
>> + pci_bridge_write_config(d, address, val, len);
>> + msi_write_config(d, address, val, len);
>> + shpc_cap_write_config(d, address, val, len);
>> +}
>> +
>> +static bool pci_device_shpc_present(void *opaque, int version_id)
>> +{
>> + PCIDevice *dev = opaque;
>> +
>> + return shpc_present(dev);
>> +}
>> +
>> +static Property pcie_pci_bridge_dev_properties[] = {
>> + DEFINE_PROP_BOOL("msi_enable", PCIEPCIBridge, msi_enable, true),
>> + DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static const VMStateDescription pciepci_bridge_dev_vmstate = {
>> + .name = TYPE_PCIE_PCI_BRIDGE_DEV,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
>> + SHPC_VMSTATE(shpc, PCIDevice, pci_device_shpc_present),
>
>
> SHPC is always present for this device, right?
> You don't need tfor presence, just add it to the vmsate.
>
>
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static void pcie_pci_bridge_hotplug_cb(HotplugHandler *hotplug_dev,
>> + DeviceState *dev, Error **errp)
>> +{
>> + PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
>> +
>> + if (!shpc_present(pci_hotplug_dev)) {
>> + error_setg(errp, "standard hotplug controller has been disabled
>> for "
>> + "this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
>> + return;
>> + }
>> + shpc_device_hotplug_cb(hotplug_dev, dev, errp);
>> +}
>> +
>> +static void pcie_pci_bridge_hot_unplug_request_cb(HotplugHandler
>> *hotplug_dev,
>> + DeviceState *dev,
>> + Error **errp)
>> +{
>> + PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
>> +
>> + if (!shpc_present(pci_hotplug_dev)) {
>> + error_setg(errp, "standard hotplug controller has been disabled
>> for "
>> + "this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
>> + return;
>> + }
>> + shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
>> +}
>> +
>> +static void pciepci_bridge_class_init(ObjectClass *klass, void *data)
>> +{
>> + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
>> +
>> + k->is_express = 1;
>> + k->is_bridge = 1;
>> + k->vendor_id = PCI_VENDOR_ID_REDHAT;
>> + k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE;
>> + k->realize = pciepci_bridge_realize;
>> + k->exit = pciepci_bridge_exit;
>> + k->config_write = pcie_pci_bridge_write_config;
>> + dc->vmsd = &pciepci_bridge_dev_vmstate;
>> + dc->props = pcie_pci_bridge_dev_properties;
>> + dc->vmsd = &pciepci_bridge_dev_vmstate;
>> + dc->reset = &pciepci_bridge_reset;
>> + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
>> + hc->plug = pcie_pci_bridge_hotplug_cb;
>> + hc->unplug_request = pcie_pci_bridge_hot_unplug_request_cb;
>> +}
>> +
>> +static const TypeInfo pciepci_bridge_info = {
>> + .name = TYPE_PCIE_PCI_BRIDGE_DEV,
>> + .parent = TYPE_PCI_BRIDGE,
>> + .instance_size = sizeof(PCIEPCIBridge),
>> + .class_init = pciepci_bridge_class_init,
>> + .interfaces = (InterfaceInfo[]) {
>> + { TYPE_HOTPLUG_HANDLER },
>> + { },
>> + }
>> +};
>> +
>> +static void pciepci_register(void)
>> +{
>> + type_register_static(&pciepci_bridge_info);
>> +}
>> +
>> +type_init(pciepci_register);
>> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
>> index e598b09..b33a34f 100644
>> --- a/include/hw/pci/pci.h
>> +++ b/include/hw/pci/pci.h
>> @@ -98,6 +98,7 @@
>> #define PCI_DEVICE_ID_REDHAT_PXB_PCIE 0x000b
>> #define PCI_DEVICE_ID_REDHAT_PCIE_RP 0x000c
>> #define PCI_DEVICE_ID_REDHAT_XHCI 0x000d
>> +#define PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE 0x000e
>> #define PCI_DEVICE_ID_REDHAT_QXL 0x0100
>> #define FMT_PCIBUS PRIx64
>>
>
> Other than the comments above the implementation
> looks good to me.
>
> Thanks,
> Marcel
>
--
Alexander Bezzubikov
More information about the SeaBIOS
mailing list