Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cdx: add cdx controller

CDX controller uses MCDI interface as a protocol to
communicate with the RPU firmware and registers the
detected CDX devices on the CDX bus. It also uses
RPMsg as the communication channel with the Firmware.

Signed-off-by: Nipun Gupta <nipun.gupta@amd.com>
Signed-off-by: Puneet Gupta <puneet.gupta@amd.com>
Signed-off-by: Abhijit Gangurde <abhijit.gangurde@amd.com>
Signed-off-by: Nikhil Agarwal <nikhil.agarwal@amd.com>
Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Tested-by: Nikhil Agarwal <nikhil.agarwal@amd.com>
Link: https://lore.kernel.org/r/20230313132636.31850-6-nipun.gupta@amd.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Nipun Gupta and committed by
Greg Kroah-Hartman
8a7923df eb96b740

+373 -1
+9
drivers/cdx/controller/Kconfig
··· 7 7 8 8 if CDX_BUS 9 9 10 + config CDX_CONTROLLER 11 + tristate "CDX bus controller" 12 + help 13 + CDX controller drives the CDX bus. It interacts with 14 + firmware to get the hardware devices and registers with 15 + the CDX bus. Say Y to enable the CDX hardware driver. 16 + 17 + If unsure, say N. 18 + 10 19 config MCDI_LOGGING 11 20 bool "MCDI Logging for the CDX controller" 12 21 depends on CDX_CONTROLLER
+1 -1
drivers/cdx/controller/Makefile
··· 6 6 # 7 7 8 8 obj-$(CONFIG_CDX_CONTROLLER) += cdx-controller.o 9 - cdx-controller-objs := mcdi.o 9 + cdx-controller-objs := cdx_controller.o mcdi.o mcdi_functions.o
+188
drivers/cdx/controller/cdx_controller.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * CDX host controller driver for AMD versal-net platform. 4 + * 5 + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 6 + */ 7 + 8 + #include <linux/of_platform.h> 9 + #include <linux/slab.h> 10 + #include <linux/cdx/cdx_bus.h> 11 + 12 + #include "../cdx.h" 13 + #include "mcdi_functions.h" 14 + #include "mcdi.h" 15 + 16 + static unsigned int cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd) 17 + { 18 + return MCDI_RPC_TIMEOUT; 19 + } 20 + 21 + static void cdx_mcdi_request(struct cdx_mcdi *cdx, 22 + const struct cdx_dword *hdr, size_t hdr_len, 23 + const struct cdx_dword *sdu, size_t sdu_len) 24 + { 25 + /* 26 + * This will get updated by rpmsg APIs, with RPMSG introduction 27 + * in CDX controller as a transport layer. 28 + */ 29 + } 30 + 31 + static const struct cdx_mcdi_ops mcdi_ops = { 32 + .mcdi_rpc_timeout = cdx_mcdi_rpc_timeout, 33 + .mcdi_request = cdx_mcdi_request, 34 + }; 35 + 36 + static int cdx_scan_devices(struct cdx_controller *cdx) 37 + { 38 + struct cdx_mcdi *cdx_mcdi = cdx->priv; 39 + u8 bus_num, dev_num, num_cdx_bus; 40 + int ret; 41 + 42 + /* MCDI FW Read: Fetch the number of CDX buses on this controller */ 43 + ret = cdx_mcdi_get_num_buses(cdx_mcdi); 44 + if (ret < 0) { 45 + dev_err(cdx->dev, 46 + "Get number of CDX buses failed: %d\n", ret); 47 + return ret; 48 + } 49 + num_cdx_bus = (u8)ret; 50 + 51 + for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) { 52 + u8 num_cdx_dev; 53 + 54 + /* MCDI FW Read: Fetch the number of devices present */ 55 + ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num); 56 + if (ret < 0) { 57 + dev_err(cdx->dev, 58 + "Get devices on CDX bus %d failed: %d\n", bus_num, ret); 59 + continue; 60 + } 61 + num_cdx_dev = (u8)ret; 62 + 63 + for (dev_num = 0; dev_num < num_cdx_dev; dev_num++) { 64 + struct cdx_dev_params dev_params; 65 + 66 + /* MCDI FW: Get the device config */ 67 + ret = cdx_mcdi_get_dev_config(cdx_mcdi, bus_num, 68 + dev_num, &dev_params); 69 + if (ret) { 70 + dev_err(cdx->dev, 71 + "CDX device config get failed for %d(bus):%d(dev), %d\n", 72 + bus_num, dev_num, ret); 73 + continue; 74 + } 75 + dev_params.cdx = cdx; 76 + 77 + /* Add the device to the cdx bus */ 78 + ret = cdx_device_add(&dev_params); 79 + if (ret) { 80 + dev_err(cdx->dev, "registering cdx dev: %d failed: %d\n", 81 + dev_num, ret); 82 + continue; 83 + } 84 + 85 + dev_dbg(cdx->dev, "CDX dev: %d on cdx bus: %d created\n", 86 + dev_num, bus_num); 87 + } 88 + } 89 + 90 + return 0; 91 + } 92 + 93 + static struct cdx_ops cdx_ops = { 94 + .scan = cdx_scan_devices, 95 + }; 96 + 97 + static int xlnx_cdx_probe(struct platform_device *pdev) 98 + { 99 + struct cdx_controller *cdx; 100 + struct cdx_mcdi *cdx_mcdi; 101 + int ret; 102 + 103 + cdx_mcdi = kzalloc(sizeof(*cdx_mcdi), GFP_KERNEL); 104 + if (!cdx_mcdi) 105 + return -ENOMEM; 106 + 107 + /* Store the MCDI ops */ 108 + cdx_mcdi->mcdi_ops = &mcdi_ops; 109 + /* MCDI FW: Initialize the FW path */ 110 + ret = cdx_mcdi_init(cdx_mcdi); 111 + if (ret) { 112 + dev_err_probe(&pdev->dev, ret, "MCDI Initialization failed\n"); 113 + goto mcdi_init_fail; 114 + } 115 + 116 + cdx = kzalloc(sizeof(*cdx), GFP_KERNEL); 117 + if (!cdx) { 118 + ret = -ENOMEM; 119 + goto cdx_alloc_fail; 120 + } 121 + platform_set_drvdata(pdev, cdx); 122 + 123 + cdx->dev = &pdev->dev; 124 + cdx->priv = cdx_mcdi; 125 + cdx->ops = &cdx_ops; 126 + 127 + return 0; 128 + 129 + cdx_alloc_fail: 130 + cdx_mcdi_finish(cdx_mcdi); 131 + mcdi_init_fail: 132 + kfree(cdx_mcdi); 133 + 134 + return ret; 135 + } 136 + 137 + static int xlnx_cdx_remove(struct platform_device *pdev) 138 + { 139 + struct cdx_controller *cdx = platform_get_drvdata(pdev); 140 + struct cdx_mcdi *cdx_mcdi = cdx->priv; 141 + 142 + kfree(cdx); 143 + 144 + cdx_mcdi_finish(cdx_mcdi); 145 + kfree(cdx_mcdi); 146 + 147 + return 0; 148 + } 149 + 150 + static const struct of_device_id cdx_match_table[] = { 151 + {.compatible = "xlnx,versal-net-cdx",}, 152 + { }, 153 + }; 154 + 155 + MODULE_DEVICE_TABLE(of, cdx_match_table); 156 + 157 + static struct platform_driver cdx_pdriver = { 158 + .driver = { 159 + .name = "cdx-controller", 160 + .pm = NULL, 161 + .of_match_table = cdx_match_table, 162 + }, 163 + .probe = xlnx_cdx_probe, 164 + .remove = xlnx_cdx_remove, 165 + }; 166 + 167 + static int __init cdx_controller_init(void) 168 + { 169 + int ret; 170 + 171 + ret = platform_driver_register(&cdx_pdriver); 172 + if (ret) 173 + pr_err("platform_driver_register() failed: %d\n", ret); 174 + 175 + return ret; 176 + } 177 + 178 + static void __exit cdx_controller_exit(void) 179 + { 180 + platform_driver_unregister(&cdx_pdriver); 181 + } 182 + 183 + module_init(cdx_controller_init); 184 + module_exit(cdx_controller_exit); 185 + 186 + MODULE_AUTHOR("AMD Inc."); 187 + MODULE_DESCRIPTION("CDX controller for AMD devices"); 188 + MODULE_LICENSE("GPL");
+125
drivers/cdx/controller/mcdi_functions.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 4 + */ 5 + 6 + #include <linux/module.h> 7 + 8 + #include "mcdi.h" 9 + #include "mcdi_functions.h" 10 + 11 + int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx) 12 + { 13 + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN); 14 + size_t outlen; 15 + int ret; 16 + 17 + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_BUSES, NULL, 0, 18 + outbuf, sizeof(outbuf), &outlen); 19 + if (ret) 20 + return ret; 21 + 22 + if (outlen != MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN) 23 + return -EIO; 24 + 25 + return MCDI_DWORD(outbuf, CDX_BUS_ENUM_BUSES_OUT_BUS_COUNT); 26 + } 27 + 28 + int cdx_mcdi_get_num_devs(struct cdx_mcdi *cdx, int bus_num) 29 + { 30 + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN); 31 + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_IN_LEN); 32 + size_t outlen; 33 + int ret; 34 + 35 + MCDI_SET_DWORD(inbuf, CDX_BUS_ENUM_DEVICES_IN_BUS, bus_num); 36 + 37 + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_DEVICES, inbuf, sizeof(inbuf), 38 + outbuf, sizeof(outbuf), &outlen); 39 + if (ret) 40 + return ret; 41 + 42 + if (outlen != MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN) 43 + return -EIO; 44 + 45 + return MCDI_DWORD(outbuf, CDX_BUS_ENUM_DEVICES_OUT_DEVICE_COUNT); 46 + } 47 + 48 + int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, 49 + u8 bus_num, u8 dev_num, 50 + struct cdx_dev_params *dev_params) 51 + { 52 + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN); 53 + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); 54 + struct resource *res = &dev_params->res[0]; 55 + size_t outlen; 56 + u32 req_id; 57 + int ret; 58 + 59 + MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_BUS, bus_num); 60 + MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_DEVICE, dev_num); 61 + 62 + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG, inbuf, sizeof(inbuf), 63 + outbuf, sizeof(outbuf), &outlen); 64 + if (ret) 65 + return ret; 66 + 67 + if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN) 68 + return -EIO; 69 + 70 + dev_params->bus_num = bus_num; 71 + dev_params->dev_num = dev_num; 72 + 73 + req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); 74 + dev_params->req_id = req_id; 75 + 76 + dev_params->res_count = 0; 77 + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { 78 + res[dev_params->res_count].start = 79 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE); 80 + res[dev_params->res_count].end = 81 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE) + 82 + MCDI_QWORD(outbuf, 83 + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) - 1; 84 + res[dev_params->res_count].flags = IORESOURCE_MEM; 85 + dev_params->res_count++; 86 + } 87 + 88 + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) != 0) { 89 + res[dev_params->res_count].start = 90 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE); 91 + res[dev_params->res_count].end = 92 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE) + 93 + MCDI_QWORD(outbuf, 94 + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) - 1; 95 + res[dev_params->res_count].flags = IORESOURCE_MEM; 96 + dev_params->res_count++; 97 + } 98 + 99 + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) != 0) { 100 + res[dev_params->res_count].start = 101 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE); 102 + res[dev_params->res_count].end = 103 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE) + 104 + MCDI_QWORD(outbuf, 105 + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) - 1; 106 + res[dev_params->res_count].flags = IORESOURCE_MEM; 107 + dev_params->res_count++; 108 + } 109 + 110 + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) != 0) { 111 + res[dev_params->res_count].start = 112 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE); 113 + res[dev_params->res_count].end = 114 + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE) + 115 + MCDI_QWORD(outbuf, 116 + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) - 1; 117 + res[dev_params->res_count].flags = IORESOURCE_MEM; 118 + dev_params->res_count++; 119 + } 120 + 121 + dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID); 122 + dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID); 123 + 124 + return 0; 125 + }
+50
drivers/cdx/controller/mcdi_functions.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 2 + * 3 + * Header file for MCDI FW interaction for CDX bus. 4 + * 5 + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 6 + */ 7 + 8 + #ifndef CDX_MCDI_FUNCTIONS_H 9 + #define CDX_MCDI_FUNCTIONS_H 10 + 11 + #include "mcdi.h" 12 + #include "../cdx.h" 13 + 14 + /** 15 + * cdx_mcdi_get_num_buses - Get the total number of buses on 16 + * the controller. 17 + * @cdx: pointer to MCDI interface. 18 + * 19 + * Return: total number of buses available on the controller, 20 + * <0 on failure 21 + */ 22 + int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx); 23 + 24 + /** 25 + * cdx_mcdi_get_num_devs - Get the total number of devices on 26 + * a particular bus of the controller. 27 + * @cdx: pointer to MCDI interface. 28 + * @bus_num: Bus number. 29 + * 30 + * Return: total number of devices available on the bus, <0 on failure 31 + */ 32 + int cdx_mcdi_get_num_devs(struct cdx_mcdi *cdx, int bus_num); 33 + 34 + /** 35 + * cdx_mcdi_get_dev_config - Get configuration for a particular 36 + * bus_num:dev_num 37 + * @cdx: pointer to MCDI interface. 38 + * @bus_num: Bus number. 39 + * @dev_num: Device number. 40 + * @dev_params: Pointer to cdx_dev_params, this is populated by this 41 + * device with the configuration corresponding to the provided 42 + * bus_num:dev_num. 43 + * 44 + * Return: 0 total number of devices available on the bus, <0 on failure 45 + */ 46 + int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, 47 + u8 bus_num, u8 dev_num, 48 + struct cdx_dev_params *dev_params); 49 + 50 + #endif /* CDX_MCDI_FUNCTIONS_H */