diff options
author | John Levon <john.levon@nutanix.com> | 2021-04-23 17:51:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-23 17:51:10 +0100 |
commit | 13e3f8d38bc23c2a95654c46addea84ca6de365a (patch) | |
tree | 302018fdfde5724854b8a0ad7efe6805ff933c6c | |
parent | f8e47df6b874fb8a5f06089512820e3e8c8a6c4a (diff) | |
download | libvfio-user-13e3f8d38bc23c2a95654c46addea84ca6de365a.zip libvfio-user-13e3f8d38bc23c2a95654c46addea84ca6de365a.tar.gz libvfio-user-13e3f8d38bc23c2a95654c46addea84ca6de365a.tar.bz2 |
correct PM capability definition (#452)
the static size assert for the PMCS register was checking the wrong struct;
however, the struct was nonetheless 4 bytes long, due to uint bitfields. This
accidentally meant the containing struct pmcap was the correct size (the
alignment attribute makes no difference).
After fixing struct pmcs, we'll include the additional two bytes defined in the
PCI PM specification, Section 3.2. These are "optional", but as elsewhere, we'll
require them when adding the capability.
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
-rw-r--r-- | include/pci_caps/pm.h | 30 | ||||
-rw-r--r-- | lib/pci_caps.c | 15 |
2 files changed, 33 insertions, 12 deletions
diff --git a/include/pci_caps/pm.h b/include/pci_caps/pm.h index 6daa812..00f8889 100644 --- a/include/pci_caps/pm.h +++ b/include/pci_caps/pm.h @@ -39,6 +39,9 @@ extern "C" { #endif +/* + * Power Management Capabilities Register + */ struct pc { unsigned int vs:3; unsigned int pmec:1; @@ -51,29 +54,34 @@ struct pc { } __attribute__((packed)); _Static_assert(sizeof(struct pc) == 0x2, "bad PC size"); +/* + * Power Management Status and Control Register + */ struct pmcs { union { uint16_t raw; struct { - unsigned int ps:2; - unsigned int res1:1; - unsigned int nsfrst:1; - unsigned int res2:4; - unsigned int pmee:1; - unsigned int dse:4; - unsigned int dsc:2; - unsigned int pmes:1; + unsigned short ps:2; + unsigned short res1:1; + unsigned short nsfrst:1; + unsigned short res2:4; + unsigned short pmee:1; + unsigned short dse:4; + unsigned short dsc:2; + unsigned short pmes:1; }; }; } __attribute__((packed)); -_Static_assert(sizeof(struct pc) == 0x2, "bad PMCS size"); +_Static_assert(sizeof(struct pmcs) == 0x2, "bad PMCS size"); struct pmcap { struct cap_hdr hdr; struct pc pc; struct pmcs pmcs; -} __attribute__((packed)) __attribute__ ((aligned(8))); /* FIXME why does it need to be aligned? */ -_Static_assert(sizeof(struct pmcap) == PCI_PM_SIZEOF, "bad PC size"); + uint8_t pmcsr_bse; + uint8_t data; +} __attribute__((packed)); +_Static_assert(sizeof(struct pmcap) == PCI_PM_SIZEOF, "bad pmcap size"); _Static_assert(offsetof(struct pmcap, hdr) == 0, "bad offset"); #ifdef __cplusplus diff --git a/lib/pci_caps.c b/lib/pci_caps.c index 50b1ec3..8ed5643 100644 --- a/lib/pci_caps.c +++ b/lib/pci_caps.c @@ -141,7 +141,7 @@ cap_write_pm(vfu_ctx_t *vfu_ctx, struct pci_cap *cap, char * buf, if (count != sizeof(struct pc)) { return ERROR_INT(EINVAL); } - vfu_log(vfu_ctx, LOG_ERR, "FIXME: write to pmcp::pc unimplemented"); + vfu_log(vfu_ctx, LOG_ERR, "FIXME: write to pmcap::pc unimplemented"); return ERROR_INT(ENOTSUP); case offsetof(struct pmcap, pmcs): if (count != sizeof(struct pmcs)) { @@ -149,6 +149,19 @@ cap_write_pm(vfu_ctx_t *vfu_ctx, struct pci_cap *cap, char * buf, } handle_pmcs_write(vfu_ctx, pm, (struct pmcs *)buf); return sizeof(struct pmcs); + case offsetof(struct pmcap, pmcsr_bse): + if (count != 1) { + return ERROR_INT(EINVAL); + } + vfu_log(vfu_ctx, LOG_ERR, + "FIXME: write to pmcap::pmcsr_bse unimplemented"); + return ERROR_INT(ENOTSUP); + case offsetof(struct pmcap, data): + if (count != 1) { + return ERROR_INT(EINVAL); + } + vfu_log(vfu_ctx, LOG_ERR, "FIXME: write to pmcap::data unimplemented"); + return ERROR_INT(ENOTSUP); } return ERROR_INT(EINVAL); } |