On Mon, May 18, 2026 at 09:37:14AM +0200, khaled saleh wrote:
> The Standard Hot-Plug Controller (SHPC) specification (PI=1) defines
> 66MHz conventional PCI as a valid bus speed mode. While QEMU defined
> the relevant constants, it hardcoded the secondary bus speed to 33MHz
> and advertised 0 slots as 66MHz capable.
> 
> This patch enables 66MHz support by:
> 1. Allowing SHPC_SEC_BUS_66 in shpc_set_sec_bus_speed().
> 2. Advertising all slots as 66MHz capable in shpc_reset().
> 3. Dynamically checking and reporting a slot's 66MHz capability based
>    on the plugged PCI device's Status Register (PCI_STATUS_66MHZ).
> 
> PCI-X speeds remain unsupported and will continue to trigger an
> INVALID_MODE command status error.
> 
> Signed-off-by: khaled saleh <[email protected]>
> ---
>  hw/pci/shpc.c | 29 ++++++++++++++++++++++++-----
>  1 file changed, 24 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
> index 938602866d..3becde7f10 100644
> --- a/hw/pci/shpc.c
> +++ b/hw/pci/shpc.c
> @@ -12,7 +12,7 @@
>  
>  /* TODO: model power only and disabled slot states. */
>  /* TODO: handle SERR and wakeups */
> -/* TODO: consider enabling 66MHz support */
> +
>  
>  /* TODO: remove fully only on state DISABLED and LED off.
>   * track state to properly record this. */
> @@ -30,7 +30,7 @@
>  #define SHPC_PHYS_BUTTON  0x8000
>  #define SHPC_SEC_BUS      0x10 /* 2 bytes */
>  #define SHPC_SEC_BUS_33   0x0
> -#define SHPC_SEC_BUS_66   0x1 /* Unused */
> +#define SHPC_SEC_BUS_66   0x1
>  #define SHPC_SEC_BUS_MASK 0x7
>  #define SHPC_MSI_CTL      0x12 /* 1 byte */
>  #define SHPC_PROG_IFC     0x13 /* 1 byte */
> @@ -169,6 +169,17 @@ static void shpc_set_status(SHPCDevice *shpc,
>      pci_word_test_and_set_mask(status, value << ctz32(msk));
>  }
>  
> +static bool shpc_device_is_66mhz_capable(SHPCDevice *shpc, int slot)
> +{
> +    int pci_slot = SHPC_IDX_TO_PCI(slot);
> +    PCIDevice *dev = shpc->sec_bus->devices[PCI_DEVFN(pci_slot, 0)];
> +
> +    if (!dev) {
> +        return false;
> +    }
> +    return pci_get_word(dev->config + PCI_STATUS) & PCI_STATUS_66MHZ;
> +}
> +
>  static void shpc_interrupt_update(PCIDevice *d)
>  {
>      SHPCDevice *shpc = d->shpc;
> @@ -203,6 +214,7 @@ static void shpc_set_sec_bus_speed(SHPCDevice *shpc, 
> uint8_t speed)
>  {
>      switch (speed) {
>      case SHPC_SEC_BUS_33:
> +    case SHPC_SEC_BUS_66:
>          shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
>          shpc->config[SHPC_SEC_BUS] |= speed;
>          break;
> @@ -220,7 +232,7 @@ void shpc_reset(PCIDevice *d)
>      memset(shpc->config, 0, SHPC_SIZEOF(d));
>      pci_set_byte(shpc->config + SHPC_NSLOTS, nslots);
>      pci_set_long(shpc->config + SHPC_SLOTS_33, nslots);
> -    pci_set_long(shpc->config + SHPC_SLOTS_66, 0);
> +    pci_set_long(shpc->config + SHPC_SLOTS_66, nslots);
>      pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0));
>      pci_set_word(shpc->config + SHPC_PHYS_SLOT,
>                   SHPC_IDX_TO_PHYSICAL(0) |
> @@ -256,7 +268,9 @@ void shpc_reset(PCIDevice *d)
>              shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK);
>          }
>          shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_ATTN_LED_MASK);
> -        shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66);
> +        shpc_set_status(shpc, i,
> +                        shpc_device_is_66mhz_capable(shpc, i) ? 1 : 0,
> +                        SHPC_SLOT_STATUS_66);
>      }
>      shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33);
>      shpc->msi_requested = 0;
> @@ -578,6 +592,9 @@ void shpc_device_plug_cb(HotplugHandler *hotplug_dev, 
> DeviceState *dev,
>          shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
>          shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
>                          SHPC_SLOT_STATUS_PRSNT_MASK);
> +        shpc_set_status(shpc, slot,
> +                        shpc_device_is_66mhz_capable(shpc, slot) ? 1 : 0,
> +                        SHPC_SLOT_STATUS_66);
>          return;
>      }
>  
> @@ -596,7 +613,9 @@ void shpc_device_plug_cb(HotplugHandler *hotplug_dev, 
> DeviceState *dev,
>          shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
>              SHPC_SLOT_EVENT_BUTTON;
>      }
> -    shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
> +    shpc_set_status(shpc, slot,
> +                    shpc_device_is_66mhz_capable(shpc, slot) ? 1 : 0,
> +                    SHPC_SLOT_STATUS_66);
>      shpc_interrupt_update(pci_hotplug_dev);
>  }
>  
> -- 
> 2.34.1


This can't be done unconditionally without breaking cross version
migration. You need to add a property (prefixed with "x-" to mark it
not a stable ABI) and then tweak it in the compat machinery.

-- 
MST


Reply via email to