Message ID | 20250122235159.2716036-5-dave.jiang@intel.com |
---|---|
State | New |
Headers | show |
Series | cxl: Add CXL feature commands support via fwctl | expand |
On Wed, 22 Jan 2025 16:50:35 -0700 Dave Jiang <dave.jiang@intel.com> wrote: > CXL spec r3.1 8.2.9.6.1 Get Supported Features (Opcode 0500h) > The command retrieve the list of supported device-specific features > (identified by UUID) and general information about each Feature. > > The driver will retrieve the feature entries in order to make checks and > provide information for the Get Feature and Set Feature command. One of > the main piece of information retrieved are the effects a Set Feature > command would have for a particular feature. > > Co-developed-by: Shiju Jose <shiju.jose@huawei.com> > Signed-off-by: Shiju Jose <shiju.jose@huawei.com> > Signed-off-by: Dave Jiang <dave.jiang@intel.com> One stray change below that either wants dropping or pushing to earlier patch. Not sure why I haven't given a tag on this one before now in either of the patch sets it features in. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> > --- > v1: > - Change input param from cxlds to cxl_mbox > - Move mbox_out declaration inline. (Jonathan) > - Fix __counted_by() input. (Jonathan) > - Return count for cxl_get_supported_features_count(). (Dan) > - Remove goto from cxl_get_supported_features(). (Dan) > - Return cxl_get_supported_feature_entry() directly. (Dan) > - Drop user path enumeration. (Dan) > - Move to the feature driver model. (Dan) > - Add support for 0 feature data requested. > - Add missing increment of feature data ptr during cop > diff --git a/drivers/cxl/features.c b/drivers/cxl/features.c > index 644add26975f..a5949312a4ab 100644 > --- a/drivers/cxl/features.c > +++ b/drivers/cxl/features.c > static int cxl_features_probe(struct device *dev) > { > struct cxl_features *features = to_cxl_features(dev); > + int rc; > + > struct cxl_features_state *cfs __free(kfree) = > kzalloc(sizeof(*cfs), GFP_KERNEL); > - Stray change that belongs in earlier patch if anywhere. > if (!cfs) > return -ENOMEM; > > cfs->features = features; > + rc = cxl_get_supported_features(cfs); > + if (rc) > + return rc; > + > dev_set_drvdata(dev, no_free_ptr(cfs)); > > return 0;
Dave Jiang wrote: > CXL spec r3.1 8.2.9.6.1 Get Supported Features (Opcode 0500h) > The command retrieve the list of supported device-specific features > (identified by UUID) and general information about each Feature. > > The driver will retrieve the feature entries in order to make checks and > provide information for the Get Feature and Set Feature command. One of > the main piece of information retrieved are the effects a Set Feature > command would have for a particular feature. > > Co-developed-by: Shiju Jose <shiju.jose@huawei.com> > Signed-off-by: Shiju Jose <shiju.jose@huawei.com> > Signed-off-by: Dave Jiang <dave.jiang@intel.com> > --- > v1: > - Change input param from cxlds to cxl_mbox > - Move mbox_out declaration inline. (Jonathan) > - Fix __counted_by() input. (Jonathan) > - Return count for cxl_get_supported_features_count(). (Dan) > - Remove goto from cxl_get_supported_features(). (Dan) > - Return cxl_get_supported_feature_entry() directly. (Dan) > - Drop user path enumeration. (Dan) > - Move to the feature driver model. (Dan) > - Add support for 0 feature data requested. > - Add missing increment of feature data ptr during copy. > --- > drivers/cxl/core/features.c | 28 +++++++ > drivers/cxl/core/mbox.c | 3 +- > drivers/cxl/cxl.h | 2 + > drivers/cxl/features.c | 146 +++++++++++++++++++++++++++++++++++- > include/cxl/features.h | 32 ++++++++ > 5 files changed, 209 insertions(+), 2 deletions(-) > > diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c > index eb6eb191a32e..66a4b82910e6 100644 > --- a/drivers/cxl/core/features.c > +++ b/drivers/cxl/core/features.c > @@ -1,6 +1,7 @@ > // SPDX-License-Identifier: GPL-2.0-only > /* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */ > #include <linux/device.h> > +#include <cxl/mailbox.h> > #include "cxl.h" > #include "core.h" > > @@ -69,3 +70,30 @@ struct cxl_features *cxl_features_alloc(struct cxl_mailbox *cxl_mbox, > return ERR_PTR(rc); > } > EXPORT_SYMBOL_NS_GPL(cxl_features_alloc, "CXL"); > + > +struct cxl_feat_entry * > +cxl_get_supported_feature_entry(struct cxl_features *features, > + const uuid_t *feat_uuid) > +{ > + struct cxl_feat_entry *feat_entry; > + struct cxl_features_state *cfs; > + int count; > + > + cfs = dev_get_drvdata(&features->dev); > + if (!cfs) > + return ERR_PTR(-EOPNOTSUPP); How could this function be called outside of the driver being enabled? If the driver might not be enabled when this is called, what stops it from being disabled immediately after this check? Went looking for the caller of this function... none in this patch set. If this is for the EDAC use case, that enabling had better be triggered from a known context where these questions have a satisfactory answer. As it stands I think you can just delete it, right? This has me thinking that the EDAC integration should just be a feature of the cxl_features_driver. ...that last sentence made me itch because I don't want to have to untangle future sentences like: A new feature of the features driver features a new Feature to complement the existing Features and other features. So I might need to ask you to be explicit about at least using capital 'Feature' when talking about a command, 'cxl_features_device' when talking about the device and 'cxl_features_driver' when talking about the driver. > diff --git a/drivers/cxl/features.c b/drivers/cxl/features.c > index 644add26975f..a5949312a4ab 100644 > --- a/drivers/cxl/features.c > +++ b/drivers/cxl/features.c [..] > +static int cxl_get_supported_features(struct cxl_features_state *cfs) > +{ > + int remain_feats, max_size, max_feats, start, rc, hdr_size; > + struct cxl_mailbox *cxl_mbox = cfs->features->cxl_mbox; > + int feat_size = sizeof(struct cxl_feat_entry); > + struct cxl_mbox_get_sup_feats_in mbox_in; > + struct cxl_feat_entry *entry; > + struct cxl_mbox_cmd mbox_cmd; > + struct cxl_mem_command *cmd; > + int count; > + > + /* Get supported features is optional, need to check */ > + cmd = cxl_find_feature_command(CXL_MBOX_OP_GET_SUPPORTED_FEATURES); > + if (!cmd) > + return -EOPNOTSUPP; > + if (!test_bit(cmd->info.id, cxl_mbox->feature_cmds)) > + return -EOPNOTSUPP; First, who is calling this function without knowing that features are supported? Like how did we get here if something already did that first level enumeration. Otherwise, that looks like a lot of work just to ask the question, "did the mailbox see CXL_MBOX_OP_GET_SUPPORTED_FEATURES" at init? That could probably all be boiled down into an enum like: enum cxl_features_capability { CXL_FEATURES_NONE, CXL_FEATURES_RO, CXL_FEATURES_RW, }; ...for tracking Feature command enumeration and optional write support. The cxl_mem_commands organization is quirk of the CXL ioctl implementation cxl_features is free to not copy it. Longer term we need to think about how to make cxl_mailbox more independent of the memory expander / cxl_pci use case. Whereby, perhaps the consumer of the mailbox passes is in a callback that takes action on each found command. Then we get out of this game of how to cache command capabilities that are awkward fits depending on command set or driver use case. [..]
On Thu, Jan 23, 2025 at 04:30:17PM -0800, Dan Williams wrote: > > +struct cxl_feat_entry * > > +cxl_get_supported_feature_entry(struct cxl_features *features, > > + const uuid_t *feat_uuid) > > +{ > > + struct cxl_feat_entry *feat_entry; > > + struct cxl_features_state *cfs; > > + int count; > > + > > + cfs = dev_get_drvdata(&features->dev); > > + if (!cfs) > > + return ERR_PTR(-EOPNOTSUPP); > > How could this function be called outside of the driver being enabled? +1 I hate these "defensive" checks. Either your API is always called under a properly bound driver, or your caller is horribly wrongly locked and the above does nothing but hide bugs. defensive "can't happen" assertions should be marked with WARN_ON(), but I wouldn't use that here - the oops on NULL backtrace is sufficiently clear. :) Jason
On Thu, 23 Jan 2025 16:30:17 -0800 Dan Williams <dan.j.williams@intel.com> wrote: > Dave Jiang wrote: > > CXL spec r3.1 8.2.9.6.1 Get Supported Features (Opcode 0500h) > > The command retrieve the list of supported device-specific features > > (identified by UUID) and general information about each Feature. > > > > The driver will retrieve the feature entries in order to make checks and > > provide information for the Get Feature and Set Feature command. One of > > the main piece of information retrieved are the effects a Set Feature > > command would have for a particular feature. > > > > Co-developed-by: Shiju Jose <shiju.jose@huawei.com> > > Signed-off-by: Shiju Jose <shiju.jose@huawei.com> > > Signed-off-by: Dave Jiang <dave.jiang@intel.com> > > --- > > v1: > > - Change input param from cxlds to cxl_mbox > > - Move mbox_out declaration inline. (Jonathan) > > - Fix __counted_by() input. (Jonathan) > > - Return count for cxl_get_supported_features_count(). (Dan) > > - Remove goto from cxl_get_supported_features(). (Dan) > > - Return cxl_get_supported_feature_entry() directly. (Dan) > > - Drop user path enumeration. (Dan) > > - Move to the feature driver model. (Dan) > > - Add support for 0 feature data requested. > > - Add missing increment of feature data ptr during copy. > > --- > > drivers/cxl/core/features.c | 28 +++++++ > > drivers/cxl/core/mbox.c | 3 +- > > drivers/cxl/cxl.h | 2 + > > drivers/cxl/features.c | 146 +++++++++++++++++++++++++++++++++++- > > include/cxl/features.h | 32 ++++++++ > > 5 files changed, 209 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c > > index eb6eb191a32e..66a4b82910e6 100644 > > --- a/drivers/cxl/core/features.c > > +++ b/drivers/cxl/core/features.c > > @@ -1,6 +1,7 @@ > > // SPDX-License-Identifier: GPL-2.0-only > > /* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */ > > #include <linux/device.h> > > +#include <cxl/mailbox.h> > > #include "cxl.h" > > #include "core.h" > > > > @@ -69,3 +70,30 @@ struct cxl_features *cxl_features_alloc(struct cxl_mailbox *cxl_mbox, > > return ERR_PTR(rc); > > } > > EXPORT_SYMBOL_NS_GPL(cxl_features_alloc, "CXL"); > > + > > +struct cxl_feat_entry * > > +cxl_get_supported_feature_entry(struct cxl_features *features, > > + const uuid_t *feat_uuid) > > +{ > > + struct cxl_feat_entry *feat_entry; > > + struct cxl_features_state *cfs; > > + int count; > > + > > + cfs = dev_get_drvdata(&features->dev); > > + if (!cfs) > > + return ERR_PTR(-EOPNOTSUPP); > > How could this function be called outside of the driver being enabled? > > If the driver might not be enabled when this is called, what stops it > from being disabled immediately after this check? > > Went looking for the caller of this function... none in this patch set. > > If this is for the EDAC use case, that enabling had better be triggered > from a known context where these questions have a satisfactory answer. > As it stands I think you can just delete it, right? > > This has me thinking that the EDAC integration should just be a feature > of the cxl_features_driver. I'm not 100% sure I see what you mean here, but if you mean pushing the registration code into cxl_features.ko... I replied to this in the other thread, but just to add a bit here. I think this creates a worse spiders web than we have today. Not all EDAC features we might add (e.g. device self test) have anything to do with get/set features. I'm not sure we'll support that one in EDAC soon though it might make sense if there is generality with non CXL systems (I've been meaning to look into that.) To me, the CXL features support is providing a service to some of the EDAC features, but they use other services from CXL drivers and potentially don't use CXL features at all. For now we have the repair drivers that only use the features support for a tiny bit of what they do (tweaking device initiated aspects and detailed record generation - if we even support those yet). At some point we may have core CXL functionality depending on get/set features as well as there are things we definitely don't want in either EDAC or fwctl like metabits storage controls. So I'd be careful adding any thing to cxl_features beyond stuff that is definitely clustered with fwctl bit or helpers. Soon I'd also expect us to add 'features' to fwctl interface that aren't using get/set features. I think you suggested that we could do this by making up some guids for them and pushing though this same interface. Jonathan
Jonathan Cameron wrote: > On Thu, 23 Jan 2025 16:30:17 -0800 > Dan Williams <dan.j.williams@intel.com> wrote: > > > Dave Jiang wrote: > > > CXL spec r3.1 8.2.9.6.1 Get Supported Features (Opcode 0500h) > > > The command retrieve the list of supported device-specific features > > > (identified by UUID) and general information about each Feature. > > > > > > The driver will retrieve the feature entries in order to make checks and > > > provide information for the Get Feature and Set Feature command. One of > > > the main piece of information retrieved are the effects a Set Feature > > > command would have for a particular feature. > > > > > > Co-developed-by: Shiju Jose <shiju.jose@huawei.com> > > > Signed-off-by: Shiju Jose <shiju.jose@huawei.com> > > > Signed-off-by: Dave Jiang <dave.jiang@intel.com> [..] > > This has me thinking that the EDAC integration should just be a feature > > of the cxl_features_driver. > > I'm not 100% sure I see what you mean here, but if you mean pushing > the registration code into cxl_features.ko... > > I replied to this in the other thread, but just to add a bit here. > I think this creates a worse spiders web than we have today. Not > all EDAC features we might add (e.g. device self test) have anything to do > with get/set features. I'm not sure we'll support that one in EDAC soon > though it might make sense if there is generality with non CXL systems > (I've been meaning to look into that.) I came to the same conclusion and am now skeptical of cxl_features.ko vs just extended the memdev ABI. We have long since shipped the expectation that command passthrough is a compile time policy option. Each component that wants a CXL-Features-FWCTL interface can just register one via CXL core helpers. In this case it will be similar to what currently happens with the fw_upload interface registered against the memdev, not a cxl_fw_upload.ko driver. > To me, the CXL features support is providing a service to some of the EDAC > features, but they use other services from CXL drivers and potentially > don't use CXL features at all. For now we have the repair drivers > that only use the features support for a tiny bit of what they do > (tweaking device initiated aspects and detailed record generation > - if we even support those yet). > > At some point we may have core CXL functionality depending on > get/set features as well as there are things we definitely don't > want in either EDAC or fwctl like metabits storage controls. > So I'd be careful adding any thing to cxl_features beyond stuff > that is definitely clustered with fwctl bit or helpers. > > Soon I'd also expect us to add 'features' to fwctl interface > that aren't using get/set features. I think you suggested that we > could do this by making up some guids for them and pushing though > this same interface. Yes, although I hope the availability of FWCTL encourages new and interesting device functionality to just be a Feature, so that we don't have to play Linux GUID games. That might be what triggers the creation of a query command because that could lead to future scenarios where the kernel needs to dynamically mark a Feature as exclusive that was previously allowed before the kernel knew about it.
diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c index eb6eb191a32e..66a4b82910e6 100644 --- a/drivers/cxl/core/features.c +++ b/drivers/cxl/core/features.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */ #include <linux/device.h> +#include <cxl/mailbox.h> #include "cxl.h" #include "core.h" @@ -69,3 +70,30 @@ struct cxl_features *cxl_features_alloc(struct cxl_mailbox *cxl_mbox, return ERR_PTR(rc); } EXPORT_SYMBOL_NS_GPL(cxl_features_alloc, "CXL"); + +struct cxl_feat_entry * +cxl_get_supported_feature_entry(struct cxl_features *features, + const uuid_t *feat_uuid) +{ + struct cxl_feat_entry *feat_entry; + struct cxl_features_state *cfs; + int count; + + cfs = dev_get_drvdata(&features->dev); + if (!cfs) + return ERR_PTR(-EOPNOTSUPP); + + if (!cfs->num_features) + return ERR_PTR(-ENOENT); + + /* Check CXL dev supports the feature */ + feat_entry = cfs->entries; + for (count = 0; count < cfs->num_features; + count++, feat_entry++) { + if (uuid_equal(&feat_entry->uuid, feat_uuid)) + return feat_entry; + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL_NS_GPL(cxl_get_supported_feature_entry, "CXL"); diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 5e21ff99d70f..0b4946205910 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -234,7 +234,7 @@ static struct cxl_mem_command *cxl_mem_find_command(u16 opcode) return NULL; } -static struct cxl_mem_command *cxl_find_feature_command(u16 opcode) +struct cxl_mem_command *cxl_find_feature_command(u16 opcode) { struct cxl_mem_command *c; @@ -244,6 +244,7 @@ static struct cxl_mem_command *cxl_find_feature_command(u16 opcode) return NULL; } +EXPORT_SYMBOL_NS_GPL(cxl_find_feature_command, "CXL"); static const char *cxl_mem_opcode_to_name(u16 opcode) { diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index ee29d1a1c8df..1284614d71d0 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -912,6 +912,8 @@ void cxl_coordinates_combine(struct access_coordinate *out, bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port); +struct cxl_mem_command *cxl_find_feature_command(u16 opcode); + /* * Unit test builds overrides this to __weak, find the 'strong' version * of these symbols in tools/testing/cxl/. diff --git a/drivers/cxl/features.c b/drivers/cxl/features.c index 644add26975f..a5949312a4ab 100644 --- a/drivers/cxl/features.c +++ b/drivers/cxl/features.c @@ -3,20 +3,164 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/pci.h> +#include <cxl/mailbox.h> #include <cxl/features.h> #include "cxl.h" +#include "cxlmem.h" + +static void cxl_free_feature_entries(void *entries) +{ + kvfree(entries); +} + +static int cxl_get_supported_features_count(struct cxl_mailbox *cxl_mbox) +{ + struct cxl_mbox_get_sup_feats_out mbox_out; + struct cxl_mbox_get_sup_feats_in mbox_in; + struct cxl_mbox_cmd mbox_cmd; + int rc; + + memset(&mbox_in, 0, sizeof(mbox_in)); + mbox_in.count = cpu_to_le32(sizeof(mbox_out)); + memset(&mbox_out, 0, sizeof(mbox_out)); + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_SUPPORTED_FEATURES, + .size_in = sizeof(mbox_in), + .payload_in = &mbox_in, + .size_out = sizeof(mbox_out), + .payload_out = &mbox_out, + .min_out = sizeof(mbox_out), + }; + rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); + if (rc < 0) + return rc; + + return le16_to_cpu(mbox_out.supported_feats); +} + +static int cxl_get_supported_features(struct cxl_features_state *cfs) +{ + int remain_feats, max_size, max_feats, start, rc, hdr_size; + struct cxl_mailbox *cxl_mbox = cfs->features->cxl_mbox; + int feat_size = sizeof(struct cxl_feat_entry); + struct cxl_mbox_get_sup_feats_in mbox_in; + struct cxl_feat_entry *entry; + struct cxl_mbox_cmd mbox_cmd; + struct cxl_mem_command *cmd; + int count; + + /* Get supported features is optional, need to check */ + cmd = cxl_find_feature_command(CXL_MBOX_OP_GET_SUPPORTED_FEATURES); + if (!cmd) + return -EOPNOTSUPP; + if (!test_bit(cmd->info.id, cxl_mbox->feature_cmds)) + return -EOPNOTSUPP; + + count = cxl_get_supported_features_count(cxl_mbox); + if (count == 0) + return 0; + if (count < 0) + return -ENXIO; + + struct cxl_feat_entry *entries __free(kvfree) = + kvmalloc(count * sizeof(*entries), GFP_KERNEL); + if (!entries) + return -ENOMEM; + + struct cxl_mbox_get_sup_feats_out *mbox_out __free(kvfree) = + kvmalloc(cxl_mbox->payload_size, GFP_KERNEL); + if (!mbox_out) + return -ENOMEM; + + hdr_size = sizeof(*mbox_out); + max_size = cxl_mbox->payload_size - hdr_size; + /* max feat entries that can fit in mailbox max payload size */ + max_feats = max_size / feat_size; + entry = entries; + + start = 0; + remain_feats = count; + do { + int retrieved, alloc_size, copy_feats; + int num_entries; + + if (remain_feats > max_feats) { + alloc_size = sizeof(*mbox_out) + max_feats * feat_size; + remain_feats = remain_feats - max_feats; + copy_feats = max_feats; + } else { + alloc_size = sizeof(*mbox_out) + remain_feats * feat_size; + copy_feats = remain_feats; + remain_feats = 0; + } + + memset(&mbox_in, 0, sizeof(mbox_in)); + mbox_in.count = cpu_to_le32(alloc_size); + mbox_in.start_idx = cpu_to_le16(start); + memset(mbox_out, 0, alloc_size); + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_SUPPORTED_FEATURES, + .size_in = sizeof(mbox_in), + .payload_in = &mbox_in, + .size_out = alloc_size, + .payload_out = mbox_out, + .min_out = hdr_size, + }; + rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); + if (rc < 0) + return rc; + + if (mbox_cmd.size_out <= hdr_size) + return -ENXIO; + + /* + * Make sure retrieved out buffer is multiple of feature + * entries. + */ + retrieved = mbox_cmd.size_out - hdr_size; + if (retrieved % feat_size) + return -ENXIO; + + num_entries = le16_to_cpu(mbox_out->num_entries); + /* + * If the reported output entries * defined entry size != + * retrieved output bytes, then the output package is incorrect. + */ + if (num_entries * feat_size != retrieved) + return -ENXIO; + + memcpy(entry, mbox_out->ents, retrieved); + entry++; + /* + * If the number of output entries is less than expected, add the + * remaining entries to the next batch. + */ + remain_feats += copy_feats - num_entries; + start += num_entries; + } while (remain_feats); + + cfs->num_features = count; + cfs->entries = no_free_ptr(entries); + return devm_add_action_or_reset(&cfs->features->dev, + cxl_free_feature_entries, cfs->entries); +} static int cxl_features_probe(struct device *dev) { struct cxl_features *features = to_cxl_features(dev); + int rc; + struct cxl_features_state *cfs __free(kfree) = kzalloc(sizeof(*cfs), GFP_KERNEL); - if (!cfs) return -ENOMEM; cfs->features = features; + rc = cxl_get_supported_features(cfs); + if (rc) + return rc; + dev_set_drvdata(dev, no_free_ptr(cfs)); return 0; diff --git a/include/cxl/features.h b/include/cxl/features.h index 7a8be3c621a1..429b9782667c 100644 --- a/include/cxl/features.h +++ b/include/cxl/features.h @@ -3,6 +3,8 @@ #ifndef __CXL_FEATURES_H__ #define __CXL_FEATURES_H__ +#include <linux/uuid.h> + struct cxl_mailbox; enum feature_cmds { @@ -19,12 +21,42 @@ struct cxl_features { }; #define to_cxl_features(dev) container_of(dev, struct cxl_features, dev) +/* Get Supported Features (0x500h) CXL r3.1 8.2.9.6.1 */ +struct cxl_mbox_get_sup_feats_in { + __le32 count; + __le16 start_idx; + u8 reserved[2]; +} __packed; + +struct cxl_feat_entry { + uuid_t uuid; + __le16 id; + __le16 get_feat_size; + __le16 set_feat_size; + __le32 flags; + u8 get_feat_ver; + u8 set_feat_ver; + __le16 effects; + u8 reserved[18]; +} __packed; + +struct cxl_mbox_get_sup_feats_out { + __le16 num_entries; + __le16 supported_feats; + u8 reserved[4]; + struct cxl_feat_entry ents[] __counted_by_le(num_entries); +} __packed; + struct cxl_features_state { struct cxl_features *features; int num_features; + struct cxl_feat_entry *entries; }; struct cxl_features *cxl_features_alloc(struct cxl_mailbox *cxl_mbox, struct device *parent); +struct cxl_feat_entry * +cxl_get_supported_feature_entry(struct cxl_features *features, + const uuid_t *feat_uuid); #endif