From 55c4f093b3a527c52cc8ed7138c330512973c9e6 Mon Sep 17 00:00:00 2001 From: fangying Date: Wed, 18 Mar 2020 12:49:33 +0800 Subject: [PATCH 1/2] pcie: Add pcie-root-port fast plug/unplug feature If a device is plugged in the pcie-root-port when VM kernel is booting, the kernel may wrongly disable the device. This bug was brought in by two patches of the linux kernel: https://patchwork.kernel.org/patch/10575355/ https://patchwork.kernel.org/patch/10766219/ VM runtime like kata uses this feature to boot microVM, so we must fix it up. We hack into the pcie native hotplug patch so that hotplug/unplug will work under this circumstance. Signed-off-by: Ying Fang --- hw/core/machine.c | 1 + hw/pci-bridge/gen_pcie_root_port.c | 3 ++- hw/pci/pcie.c | 23 +++++++++++++++++++---- include/hw/pci/pcie_port.h | 3 ++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 2baf9ec3..3138f97b 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -33,6 +33,7 @@ GlobalProperty hw_compat_3_1[] = { { "pcie-root-port", "x-speed", "2_5" }, { "pcie-root-port", "x-width", "1" }, { "pcie-root-port", "fast-plug", "0" }, + { "pcie-root-port", "fast-unplug", "0" }, { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" }, { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" }, { "tpm-crb", "ppi", "false" }, diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 3179c4ea..2fbb11d0 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -131,7 +131,8 @@ static Property gen_rp_props[] = { speed, PCIE_LINK_SPEED_16), DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot, width, PCIE_LINK_WIDTH_32), - DEFINE_PROP_UINT8("fast-plug", PCIESlot, disable_lnksta_dllla, 0), + DEFINE_PROP_UINT8("fast-plug", PCIESlot, fast_plug, 0), + DEFINE_PROP_UINT8("fast-unplug", PCIESlot, fast_unplug, 0), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index c0d6ff13..2a8ff86d 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -85,7 +85,7 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) * To fix this up, let's enable the PCI_EXP_LNKSTA_DLLLA * only if it is a PCIESlot device. */ - if (s == NULL || s->disable_lnksta_dllla == 0) { + if (s == NULL || s->fast_plug == 0) { if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_DLLLA); @@ -136,8 +136,11 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) */ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_DLLLARC); - pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, - PCI_EXP_LNKSTA_DLLLA); + + if(s->fast_plug == 0) { + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, + PCI_EXP_LNKSTA_DLLLA); + } /* * Target Link Speed defaults to the highest link speed supported by @@ -477,6 +480,8 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, Error *local_err = NULL; PCIDevice *pci_dev = PCI_DEVICE(dev); PCIBus *bus = pci_get_bus(pci_dev); + PCIESlot *s = PCIE_SLOT(PCI_DEVICE(hotplug_dev)); + uint8_t *exp_cap = pci_dev->config + pci_dev->exp.exp_cap; pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err); if (local_err) { @@ -495,7 +500,17 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, return; } - pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev)); + if ((pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) && s->fast_plug) { + pci_word_test_and_clear_mask(exp_cap+ PCI_EXP_LNKSTA, + PCI_EXP_LNKSTA_DLLLA); + } + + if (s->fast_unplug) { + pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), + PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP); + } else { + pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev)); + } } /* pci express slot for pci express root/downstream port diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index c3969921..b57af4ee 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -50,7 +50,8 @@ struct PCIESlot { uint8_t chassis; uint16_t slot; - uint8_t disable_lnksta_dllla; + uint8_t fast_plug; + uint8_t fast_unplug; PCIExpLinkSpeed speed; PCIExpLinkWidth width; -- 2.19.1