|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | 2 | /* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */ |
| 3 | +#include <linux/fwctl.h> |
3 | 4 | #include <linux/device.h> |
4 | 5 | #include <cxl/mailbox.h> |
5 | 6 | #include <cxl/features.h> |
@@ -331,3 +332,74 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox, |
331 | 332 | } |
332 | 333 | } while (true); |
333 | 334 | } |
| 335 | + |
| 336 | +/* FWCTL support */ |
| 337 | + |
| 338 | +static inline struct cxl_memdev *fwctl_to_memdev(struct fwctl_device *fwctl_dev) |
| 339 | +{ |
| 340 | + return to_cxl_memdev(fwctl_dev->dev.parent); |
| 341 | +} |
| 342 | + |
| 343 | +static int cxlctl_open_uctx(struct fwctl_uctx *uctx) |
| 344 | +{ |
| 345 | + return 0; |
| 346 | +} |
| 347 | + |
| 348 | +static void cxlctl_close_uctx(struct fwctl_uctx *uctx) |
| 349 | +{ |
| 350 | +} |
| 351 | + |
| 352 | +static void *cxlctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, |
| 353 | + void *in, size_t in_len, size_t *out_len) |
| 354 | +{ |
| 355 | + /* Place holder */ |
| 356 | + return ERR_PTR(-EOPNOTSUPP); |
| 357 | +} |
| 358 | + |
| 359 | +static const struct fwctl_ops cxlctl_ops = { |
| 360 | + .device_type = FWCTL_DEVICE_TYPE_CXL, |
| 361 | + .uctx_size = sizeof(struct fwctl_uctx), |
| 362 | + .open_uctx = cxlctl_open_uctx, |
| 363 | + .close_uctx = cxlctl_close_uctx, |
| 364 | + .fw_rpc = cxlctl_fw_rpc, |
| 365 | +}; |
| 366 | + |
| 367 | +DEFINE_FREE(free_fwctl_dev, struct fwctl_device *, if (_T) fwctl_put(_T)) |
| 368 | + |
| 369 | +static void free_memdev_fwctl(void *_fwctl_dev) |
| 370 | +{ |
| 371 | + struct fwctl_device *fwctl_dev = _fwctl_dev; |
| 372 | + |
| 373 | + fwctl_unregister(fwctl_dev); |
| 374 | + fwctl_put(fwctl_dev); |
| 375 | +} |
| 376 | + |
| 377 | +int devm_cxl_setup_fwctl(struct cxl_memdev *cxlmd) |
| 378 | +{ |
| 379 | + struct cxl_dev_state *cxlds = cxlmd->cxlds; |
| 380 | + struct cxl_features_state *cxlfs; |
| 381 | + int rc; |
| 382 | + |
| 383 | + cxlfs = to_cxlfs(cxlds); |
| 384 | + if (!cxlfs) |
| 385 | + return -ENODEV; |
| 386 | + |
| 387 | + /* No need to setup FWCTL if there are no user allowed features found */ |
| 388 | + if (!cxlfs->entries->num_user_features) |
| 389 | + return -ENODEV; |
| 390 | + |
| 391 | + struct fwctl_device *fwctl_dev __free(free_fwctl_dev) = |
| 392 | + _fwctl_alloc_device(&cxlmd->dev, &cxlctl_ops, sizeof(*fwctl_dev)); |
| 393 | + if (!fwctl_dev) |
| 394 | + return -ENOMEM; |
| 395 | + |
| 396 | + rc = fwctl_register(fwctl_dev); |
| 397 | + if (rc) |
| 398 | + return rc; |
| 399 | + |
| 400 | + return devm_add_action_or_reset(&cxlmd->dev, free_memdev_fwctl, |
| 401 | + no_free_ptr(fwctl_dev)); |
| 402 | +} |
| 403 | +EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_fwctl, "CXL"); |
| 404 | + |
| 405 | +MODULE_IMPORT_NS("FWCTL"); |
0 commit comments