diff options
| author | Mark Brown <broonie@kernel.org> | 2026-09-07 14:48:21 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-09-07 14:48:21 +0100 |
| commit | 91c8ed45e8604f22c2946118c7edc977cd4dac92 (patch) | |
| tree | fd20c0d3194bffd0e27fc9fc684d1121a2ce0cf2 /drivers | |
| parent | 49ef5f8c80c3b05d981b2a1d2477179605eecaac (diff) | |
| parent | 999811aca000b0d3d1c838c60dc9db7c72eb0c73 (diff) | |
| download | linux-next-91c8ed45e8604f22c2946118c7edc977cd4dac92.tar.gz linux-next-91c8ed45e8604f22c2946118c7edc977cd4dac92.zip | |
Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/cxl/core/core.h | 8 | ||||
| -rw-r--r-- | drivers/cxl/core/edac.c | 30 | ||||
| -rw-r--r-- | drivers/cxl/core/features.c | 56 | ||||
| -rw-r--r-- | drivers/cxl/core/mce.c | 8 | ||||
| -rw-r--r-- | drivers/cxl/core/ras.c | 6 | ||||
| -rw-r--r-- | drivers/cxl/core/region.c | 5 |
6 files changed, 74 insertions, 39 deletions
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 35eaf636adc9..bb380ec6daeb 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -217,10 +217,10 @@ int cxl_port_get_possible_dports(struct cxl_port *port); #ifdef CONFIG_CXL_FEATURES struct cxl_feat_entry * cxl_feature_info(struct cxl_features_state *cxlfs, const uuid_t *uuid); -size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, - enum cxl_get_feat_selection selection, - void *feat_out, size_t feat_out_size, u16 offset, - u16 *return_code); +ssize_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, + enum cxl_get_feat_selection selection, + void *feat_out, size_t feat_out_size, u16 offset, + u16 *return_code); int cxl_set_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, u8 feat_version, const void *feat_data, size_t feat_data_size, u32 feat_flag, u16 offset, diff --git a/drivers/cxl/core/edac.c b/drivers/cxl/core/edac.c index b321971fef58..34b81e8dfbbb 100644 --- a/drivers/cxl/core/edac.c +++ b/drivers/cxl/core/edac.c @@ -78,7 +78,7 @@ static int cxl_mem_scrub_get_attrbs(struct cxl_mailbox *cxl_mbox, u8 *cap, u16 *cycle, u8 *flags, u8 *min_cycle) { size_t rd_data_size = sizeof(struct cxl_scrub_rd_attrbs); - size_t data_size; + ssize_t data_size; struct cxl_scrub_rd_attrbs *rd_attrbs __free(kfree) = kzalloc(rd_data_size, GFP_KERNEL); if (!rd_attrbs) @@ -87,7 +87,9 @@ static int cxl_mem_scrub_get_attrbs(struct cxl_mailbox *cxl_mbox, u8 *cap, data_size = cxl_get_feature(cxl_mbox, &CXL_FEAT_PATROL_SCRUB_UUID, CXL_GET_FEAT_SEL_CURRENT_VALUE, rd_attrbs, rd_data_size, 0, NULL); - if (!data_size) + if (data_size < 0) + return data_size; + if ((size_t)data_size != rd_data_size) return -EIO; *cap = rd_attrbs->scrub_cycle_cap; @@ -551,7 +553,7 @@ static int cxl_mem_ecs_get_attrbs(struct device *dev, struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; struct cxl_ecs_fru_rd_attrbs *fru_rd_attrbs; size_t rd_data_size; - size_t data_size; + ssize_t data_size; rd_data_size = cxl_ecs_ctx->get_feat_size; @@ -563,7 +565,9 @@ static int cxl_mem_ecs_get_attrbs(struct device *dev, data_size = cxl_get_feature(cxl_mbox, &CXL_FEAT_ECS_UUID, CXL_GET_FEAT_SEL_CURRENT_VALUE, rd_attrbs, rd_data_size, 0, NULL); - if (!data_size) + if (data_size < 0) + return data_size; + if ((size_t)data_size != rd_data_size) return -EIO; fru_rd_attrbs = rd_attrbs->fru_attrbs; @@ -583,7 +587,7 @@ static int cxl_mem_ecs_set_attrbs(struct device *dev, struct cxl_ecs_fru_wr_attrbs *fru_wr_attrbs; size_t rd_data_size, wr_data_size; u16 num_media_frus, count; - size_t data_size; + ssize_t data_size; num_media_frus = cxl_ecs_ctx->num_media_frus; rd_data_size = cxl_ecs_ctx->get_feat_size; @@ -596,7 +600,9 @@ static int cxl_mem_ecs_set_attrbs(struct device *dev, data_size = cxl_get_feature(cxl_mbox, &CXL_FEAT_ECS_UUID, CXL_GET_FEAT_SEL_CURRENT_VALUE, rd_attrbs, rd_data_size, 0, NULL); - if (!data_size) + if (data_size < 0) + return data_size; + if ((size_t)data_size != rd_data_size) return -EIO; struct cxl_ecs_wr_attrbs *wr_attrbs __free(kvfree) = @@ -1264,7 +1270,7 @@ cxl_mem_sparing_get_attrbs(struct cxl_mem_sparing_context *cxl_sparing_ctx) struct cxl_memdev *cxlmd = cxl_sparing_ctx->cxlmd; struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; u16 restriction_flags; - size_t data_size; + ssize_t data_size; u16 return_code; struct cxl_memdev_sparing_rd_attrbs *rd_attrbs __free(kfree) = kzalloc(rd_data_size, GFP_KERNEL); @@ -1274,7 +1280,9 @@ cxl_mem_sparing_get_attrbs(struct cxl_mem_sparing_context *cxl_sparing_ctx) data_size = cxl_get_feature(cxl_mbox, &cxl_sparing_ctx->repair_uuid, CXL_GET_FEAT_SEL_CURRENT_VALUE, rd_attrbs, rd_data_size, 0, &return_code); - if (!data_size) + if (data_size < 0) + return data_size; + if ((size_t)data_size != rd_data_size) return -EIO; cxl_sparing_ctx->op_class = rd_attrbs->hdr.op_class; @@ -1750,7 +1758,7 @@ static int cxl_mem_ppr_get_attrbs(struct cxl_ppr_context *cxl_ppr_ctx) struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd; struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; u16 restriction_flags; - size_t data_size; + ssize_t data_size; u16 return_code; struct cxl_memdev_ppr_rd_attrbs *rd_attrbs __free(kfree) = @@ -1761,7 +1769,9 @@ static int cxl_mem_ppr_get_attrbs(struct cxl_ppr_context *cxl_ppr_ctx) data_size = cxl_get_feature(cxl_mbox, &cxl_ppr_ctx->repair_uuid, CXL_GET_FEAT_SEL_CURRENT_VALUE, rd_attrbs, rd_data_size, 0, &return_code); - if (!data_size) + if (data_size < 0) + return data_size; + if ((size_t)data_size != rd_data_size) return -EIO; cxl_ppr_ctx->op_class = rd_attrbs->hdr.op_class; diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c index ba6d2a5acb74..95f47193fb61 100644 --- a/drivers/cxl/core/features.c +++ b/drivers/cxl/core/features.c @@ -220,10 +220,10 @@ int devm_cxl_setup_features(struct cxl_dev_state *cxlds) } EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_features, "CXL"); -size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, - enum cxl_get_feat_selection selection, - void *feat_out, size_t feat_out_size, u16 offset, - u16 *return_code) +ssize_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, + enum cxl_get_feat_selection selection, + void *feat_out, size_t feat_out_size, u16 offset, + u16 *return_code) { size_t data_to_rd_size; struct cxl_mbox_get_feat_in pi; @@ -232,10 +232,13 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, int rc; if (return_code) - *return_code = CXL_MBOX_CMD_RC_INPUT; + *return_code = CXL_MBOX_CMD_RC_SUCCESS; if (!feat_out || !feat_out_size) - return 0; + return -EINVAL; + + if (feat_out_size > U16_MAX - offset) + return -EINVAL; uuid_copy(&pi.uuid, feat_uuid); pi.selection = selection; @@ -256,17 +259,25 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, .min_out = data_to_rd_size, }; rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); + /* + * Per CXL r4.0 8.2.10.6.2, when Offset + Count runs past the + * end of the Feature the device returns only the bytes up to + * the Feature size. cxl_internal_send_cmd() reports that as + * -EIO with a short payload, so stop and return what arrived. + */ + if (rc == -EIO && mbox_cmd.size_out && + mbox_cmd.size_out < data_to_rd_size) { + data_rcvd_size += mbox_cmd.size_out; + break; + } if (rc < 0 || !mbox_cmd.size_out) { if (return_code) *return_code = mbox_cmd.return_code; - return 0; + return rc < 0 ? rc : -EIO; } data_rcvd_size += mbox_cmd.size_out; } while (data_rcvd_size < feat_out_size); - if (return_code) - *return_code = CXL_MBOX_CMD_RC_SUCCESS; - return data_rcvd_size; } @@ -286,7 +297,10 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox, size_t hdr_size; if (return_code) - *return_code = CXL_MBOX_CMD_RC_INPUT; + *return_code = CXL_MBOX_CMD_RC_SUCCESS; + + if (feat_data_size > U16_MAX - offset) + return -EINVAL; struct cxl_mbox_set_feat_in *pi __free(kfree) = kzalloc(cxl_mbox->payload_size, GFP_KERNEL); @@ -334,11 +348,8 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox, } data_sent_size += data_in_size; - if (data_sent_size >= feat_data_size) { - if (return_code) - *return_code = CXL_MBOX_CMD_RC_SUCCESS; + if (data_sent_size >= feat_data_size) return 0; - } if ((feat_data_size - data_sent_size) <= (cxl_mbox->payload_size - hdr_size)) { data_in_size = feat_data_size - data_sent_size; @@ -462,6 +473,7 @@ static void *cxlctl_get_feature(struct cxl_features_state *cxlfs, const struct cxl_mbox_get_feat_in *feat_in; u16 offset, count, return_code; size_t out_size = *out_len; + ssize_t data_size; if (rpc_in->op_size != sizeof(*feat_in)) return ERR_PTR(-EINVAL); @@ -482,16 +494,20 @@ static void *cxlctl_get_feature(struct cxl_features_state *cxlfs, if (!rpc_out) return ERR_PTR(-ENOMEM); - out_size = cxl_get_feature(cxl_mbox, &feat_in->uuid, - feat_in->selection, rpc_out->payload, - count, offset, &return_code); + data_size = cxl_get_feature(cxl_mbox, &feat_in->uuid, + feat_in->selection, rpc_out->payload, + count, offset, &return_code); + if (data_size <= 0 && + return_code == CXL_MBOX_CMD_RC_SUCCESS) + return ERR_PTR(data_size ?: -EIO); *out_len = sizeof(struct fwctl_rpc_cxl_out); - if (!out_size) { + if (data_size <= 0) { rpc_out->size = 0; rpc_out->retval = return_code; return no_free_ptr(rpc_out); } + out_size = data_size; rpc_out->size = out_size; rpc_out->retval = CXL_MBOX_CMD_RC_SUCCESS; *out_len += out_size; @@ -536,6 +552,8 @@ static void *cxlctl_set_feature(struct cxl_features_state *cxlfs, rc = cxl_set_feature(cxl_mbox, &feat_in->uuid, feat_in->version, feat_in->feat_data, data_size, flags, offset, &return_code); + if (rc && return_code == CXL_MBOX_CMD_RC_SUCCESS) + return ERR_PTR(rc); *out_len = sizeof(*rpc_out); if (rc) { rpc_out->retval = return_code; diff --git a/drivers/cxl/core/mce.c b/drivers/cxl/core/mce.c index 65fed913b221..3ac6802e750d 100644 --- a/drivers/cxl/core/mce.c +++ b/drivers/cxl/core/mce.c @@ -18,7 +18,13 @@ static int cxl_handle_mce(struct notifier_block *nb, unsigned long val, u64 spa, spa_alias; unsigned long pfn; - if (!mce || !mce_usable_address(mce)) + if (!mce) + return NOTIFY_DONE; + + if (mce_is_correctable(mce)) + return NOTIFY_DONE; + + if (!mce_usable_address(mce)) return NOTIFY_DONE; spa = mce->addr & MCI_ADDR_PHYSADDR; diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c index e307361bb39e..0759fc9b07de 100644 --- a/drivers/cxl/core/ras.c +++ b/drivers/cxl/core/ras.c @@ -70,9 +70,9 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd, trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, hl); } -static int match_memdev_by_parent(struct device *dev, const void *uport) +static int match_memdev_by_parent(struct device *dev, const void *parent) { - if (is_cxl_memdev(dev) && dev->parent == uport) + if (is_cxl_memdev(dev) && dev->parent == parent) return 1; return 0; } @@ -108,7 +108,7 @@ void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) return; struct device *mem_dev __free(put_device) = bus_find_device( - &cxl_bus_type, NULL, pdev, match_memdev_by_parent); + &cxl_bus_type, NULL, &pdev->dev, match_memdev_by_parent); if (!mem_dev) return; diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 27e63e6dab7c..75b8092e6dc2 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1367,7 +1367,8 @@ static int check_last_peer(struct cxl_endpoint_decoder *cxled, /* * If this position wants to share a dport with the last endpoint mapped * then that endpoint, at index 'position - distance', must also be - * mapped by this dport. + * mapped by this dport. An endpoint that this port does not map at all + * fails that requirement. */ if (pos < distance) { dev_dbg(&cxlr->dev, "%s:%s: cannot host %s:%s at %d\n", @@ -1378,7 +1379,7 @@ static int check_last_peer(struct cxl_endpoint_decoder *cxled, cxled_peer = p->targets[pos - distance]; cxlmd_peer = cxled_to_memdev(cxled_peer); ep_peer = cxl_ep_load(port, cxlmd_peer); - if (ep->dport != ep_peer->dport) { + if (!ep_peer || ep->dport != ep_peer->dport) { dev_dbg(&cxlr->dev, "%s:%s: %s:%s pos %d mismatched peer %s:%s\n", dev_name(port->uport_dev), dev_name(&port->dev), |
