[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 13/15] qapi: add HOTPLUG_STATE event
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[PATCH v3 13/15] qapi: add HOTPLUG_STATE event |
Date: |
Thu, 9 Feb 2023 23:08:06 +0300 |
For PCIe and SHPC hotplug it's important to track led indicators,
especially the power led. Add an event that helps.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
qapi/qdev.json | 62 ++++++++++++++++++++++++++++++++++++++++++++
include/hw/pci/pci.h | 15 +++++++++++
hw/pci/pci.c | 33 +++++++++++++++++++++++
hw/pci/pcie.c | 49 ++++++++++++++++++++++++++++++++++
hw/pci/shpc.c | 42 ++++++++++++++++++++++++++++++
5 files changed, 201 insertions(+)
diff --git a/qapi/qdev.json b/qapi/qdev.json
index 2708fb4e99..40dc34f091 100644
--- a/qapi/qdev.json
+++ b/qapi/qdev.json
@@ -158,3 +158,65 @@
##
{ 'event': 'DEVICE_UNPLUG_GUEST_ERROR',
'data': { '*device': 'str', 'path': 'str' } }
+
+##
+# @HotplugLedState:
+#
+# Since: 8.0
+##
+{ 'enum': 'HotplugLedState',
+ 'data': [ 'on', 'blink', 'off' ] }
+
+##
+# @HotplugPowerState:
+#
+# Since: 8.0
+##
+{ 'enum': 'HotplugPowerState',
+ 'data': [ 'on', 'off' ] }
+
+##
+# @HotplugSlotState:
+#
+# Since: 8.0
+##
+{ 'enum': 'HotplugSlotState',
+ 'data': [ 'power-only', 'enabled', 'disabled' ] }
+
+##
+# @HotplugState:
+#
+# @hotplug-device: hotplug device id
+# @hotplug-path: hotplug device path
+# @hotplug-slot: hotplug device slot (only for SHPC)
+# @device: device name
+# @path: device path
+# @power-led: Power Indicator
+# @attention-led: Attention Indicator
+# @state: slot state, only for SHPC hotplug controller
+# @power: Power Controller state, only for PCIe hotplug
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugState',
+ 'data': { '*hotplug-device': 'str',
+ 'hotplug-path': 'str',
+ '*hotplug-slot': 'int',
+ '*device': 'str',
+ 'path': 'str',
+ '*power-led': 'HotplugLedState',
+ '*attention-led': 'HotplugLedState',
+ '*state': 'HotplugSlotState',
+ '*power': 'HotplugPowerState' } }
+
+##
+# @HOTPLUG_STATE:
+#
+# Emitted whenever the state of hotplug controller is changed.
+# Only changed values are included into event.
+# Only SHPC and PCIe-native hotplug are supported.
+#
+# Since: 8.0
+##
+{ 'event': 'HOTPLUG_STATE',
+ 'data': 'HotplugState' }
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index b6c9c44527..900e22a7d3 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -7,6 +7,9 @@
/* PCI includes legacy ISA access. */
#include "hw/isa/isa.h"
+#include "qapi/qapi-types-qdev.h"
+#include "qapi/qapi-events-qdev.h"
+
extern bool pci_available;
/* PCI bus */
@@ -611,4 +614,16 @@ static inline void pci_irq_pulse(PCIDevice *pci_dev)
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector);
void pci_set_power(PCIDevice *pci_dev, bool state);
+void pci_hotplug_state_event(DeviceState *hotplug_dev,
+ bool has_slot, int64_t slot,
+ DeviceState *dev,
+ HotplugLedState power_led_old,
+ HotplugLedState power_led_new,
+ HotplugLedState attention_led_old,
+ HotplugLedState attention_led_new,
+ HotplugSlotState state_old,
+ HotplugSlotState state_new,
+ HotplugPowerState power_old,
+ HotplugPowerState power_new);
+
#endif
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 34fd1fb5b8..b7374d3d66 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2772,6 +2772,39 @@ void pci_set_power(PCIDevice *d, bool state)
}
}
+void pci_hotplug_state_event(DeviceState *hotplug_dev,
+ bool has_slot, int64_t slot,
+ DeviceState *dev,
+ HotplugLedState power_led_old,
+ HotplugLedState power_led_new,
+ HotplugLedState attention_led_old,
+ HotplugLedState attention_led_new,
+ HotplugSlotState state_old,
+ HotplugSlotState state_new,
+ HotplugPowerState power_old,
+ HotplugPowerState power_new)
+{
+ bool pwr_led = power_led_new != power_led_old;
+ bool attn_led = attention_led_new != attention_led_old;
+ bool state = state_new != state_old;
+ bool pwr = power_new != power_old;
+
+ if (!(pwr_led || attn_led || state || pwr)) {
+ /* No changes - no event */
+ return;
+ }
+
+ qapi_event_send_hotplug_state(hotplug_dev->id,
+ hotplug_dev->canonical_path,
+ has_slot, slot,
+ dev ? dev->id : NULL,
+ dev ? dev->canonical_path : NULL,
+ pwr_led, power_led_new,
+ attn_led, attention_led_new,
+ state, state_new,
+ pwr, power_new);
+}
+
static const TypeInfo pci_device_type_info = {
.name = TYPE_PCI_DEVICE,
.parent = TYPE_DEVICE,
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 774ce85619..37e2979b3c 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -45,6 +45,35 @@ static bool pcie_sltctl_powered_off(uint16_t sltctl)
(sltctl & PCI_EXP_SLTCTL_PIC) == PCI_EXP_SLTCTL_PWR_IND_OFF;
}
+static HotplugLedState pcie_led_state_to_qapi(uint16_t value)
+{
+ switch (value) {
+ case PCI_EXP_SLTCTL_PWR_IND_ON:
+ case PCI_EXP_SLTCTL_ATTN_IND_ON:
+ return HOTPLUG_LED_STATE_ON;
+ case PCI_EXP_SLTCTL_PWR_IND_BLINK:
+ case PCI_EXP_SLTCTL_ATTN_IND_BLINK:
+ return HOTPLUG_LED_STATE_BLINK;
+ case PCI_EXP_SLTCTL_PWR_IND_OFF:
+ case PCI_EXP_SLTCTL_ATTN_IND_OFF:
+ return HOTPLUG_LED_STATE_OFF;
+ default:
+ abort();
+ }
+}
+
+static HotplugPowerState pcie_power_state_to_qapi(uint16_t value)
+{
+ switch (value) {
+ case PCI_EXP_SLTCTL_PWR_ON:
+ return HOTPLUG_POWER_STATE_ON;
+ case PCI_EXP_SLTCTL_PWR_OFF:
+ return HOTPLUG_POWER_STATE_OFF;
+ default:
+ abort();
+ }
+}
+
/***************************************************************************
* pci express capability helper functions
*/
@@ -728,9 +757,13 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
uint16_t old_slt_ctl, uint16_t old_slt_sta,
uint32_t addr, uint32_t val, int len)
{
+ PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
uint32_t pos = dev->exp.exp_cap;
uint8_t *exp_cap = dev->config + pos;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+ uint16_t power_led, attn_led, pcc, old_power_led, old_attn_led, old_pcc;
+ DeviceState *child_dev =
+ DEVICE(pci_find_the_only_child(sec_bus, pci_bus_num(sec_bus), NULL));
if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
/*
@@ -768,6 +801,22 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
sltsta);
}
+ power_led = val & PCI_EXP_SLTCTL_PIC;
+ attn_led = val & PCI_EXP_SLTCTL_AIC;
+ pcc = val & PCI_EXP_SLTCTL_PCC;
+ old_power_led = old_slt_ctl & PCI_EXP_SLTCTL_PIC;
+ old_attn_led = old_slt_ctl & PCI_EXP_SLTCTL_AIC;
+ old_pcc = old_slt_ctl & PCI_EXP_SLTCTL_PCC;
+
+ pci_hotplug_state_event(DEVICE(dev), false, 0, child_dev,
+ pcie_led_state_to_qapi(old_power_led),
+ pcie_led_state_to_qapi(power_led),
+ pcie_led_state_to_qapi(old_attn_led),
+ pcie_led_state_to_qapi(attn_led),
+ 0, 0, /* no state */
+ pcie_power_state_to_qapi(old_pcc),
+ pcie_power_state_to_qapi(pcc));
+
/*
* If the slot is populated, power indicator is off and power
* controller is off, it is safe to detach the devices.
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index 9f964b1d70..3c62d6b054 100644
--- a/hw/pci/shpc.c
+++ b/hw/pci/shpc.c
@@ -8,6 +8,8 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/msi.h"
+#include "qapi/qapi-types-qdev.h"
+#include "qapi/qapi-events-qdev.h"
/* TODO: model power only and disabled slot states. */
/* TODO: handle SERR and wakeups */
@@ -123,6 +125,34 @@
#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1)
#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1)
+static HotplugLedState shpc_led_state_to_qapi(uint8_t value)
+{
+ switch (value) {
+ case SHPC_LED_ON:
+ return HOTPLUG_LED_STATE_ON;
+ case SHPC_LED_BLINK:
+ return HOTPLUG_LED_STATE_BLINK;
+ case SHPC_LED_OFF:
+ return HOTPLUG_LED_STATE_OFF;
+ default:
+ abort();
+ }
+}
+
+static HotplugSlotState shpc_slot_state_to_qapi(uint8_t value)
+{
+ switch (value) {
+ case SHPC_STATE_PWRONLY:
+ return HOTPLUG_SLOT_STATE_POWER_ONLY;
+ case SHPC_STATE_ENABLED:
+ return HOTPLUG_SLOT_STATE_ENABLED;
+ case SHPC_STATE_DISABLED:
+ return HOTPLUG_SLOT_STATE_DISABLED;
+ default:
+ abort();
+ }
+}
+
static uint8_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk)
{
uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
@@ -268,9 +298,12 @@ static void shpc_slot_command(PCIDevice *d, uint8_t target,
{
SHPCDevice *shpc = d->shpc;
int slot = SHPC_LOGICAL_TO_IDX(target);
+ int pci_slot = SHPC_IDX_TO_PCI(slot);
uint8_t old_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
uint8_t old_power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
uint8_t old_attn = shpc_get_status(shpc, slot, SHPC_SLOT_ATTN_LED_MASK);
+ DeviceState *child_dev =
+ DEVICE(shpc->sec_bus->devices[PCI_DEVFN(pci_slot, 0)]);
if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) {
shpc_invalid_command(shpc);
@@ -302,6 +335,15 @@ static void shpc_slot_command(PCIDevice *d, uint8_t target,
shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
}
+ pci_hotplug_state_event(DEVICE(d), true, SHPC_IDX_TO_PCI(slot), child_dev,
+ shpc_led_state_to_qapi(old_power),
+ shpc_led_state_to_qapi(power ?: old_power),
+ shpc_led_state_to_qapi(old_attn),
+ shpc_led_state_to_qapi(attn ?: old_attn),
+ shpc_slot_state_to_qapi(old_state),
+ shpc_slot_state_to_qapi(state ?: old_state),
+ 0, 0 /* no PCC */);
+
if (!shpc_slot_is_off(old_state, old_power, old_attn) &&
shpc_slot_is_off(state, power, attn))
{
--
2.34.1
- [PATCH v3 10/15] pcie: introduce pcie_sltctl_powered_off() helper, (continued)
- [PATCH v3 10/15] pcie: introduce pcie_sltctl_powered_off() helper, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 03/15] pci/shpc: shpc_slot_command(): handle PWRONLY -> ENABLED transition, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 07/15] pcie_regs: drop duplicated indicator value macros, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 01/15] pci/shpc: set attention led to OFF on reset, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 09/15] pcie: pcie_cap_slot_enable_power() use correct helper, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 11/15] pcie: set power indicator to off on reset by default, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 15/15] qapi: introduce query-hotplug command, Vladimir Sementsov-Ogievskiy, 2023/02/09
- [PATCH v3 13/15] qapi: add HOTPLUG_STATE event,
Vladimir Sementsov-Ogievskiy <=
- Re: [PATCH v3 13/15] qapi: add HOTPLUG_STATE event, Markus Armbruster, 2023/02/10
[PATCH v3 12/15] pci: introduce pci_find_the_only_child(), Vladimir Sementsov-Ogievskiy, 2023/02/09
[PATCH v3 14/15] qapi: introduce DEVICE_ON event, Vladimir Sementsov-Ogievskiy, 2023/02/09