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_V2_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_V2_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->msi_dev_id = MCDI_DWORD(outbuf, 77 CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID); 78 79 dev_params->res_count = 0; 80 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { 81 res[dev_params->res_count].start = 82 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE); 83 res[dev_params->res_count].end = 84 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE) + 85 MCDI_QWORD(outbuf, 86 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) - 1; 87 res[dev_params->res_count].flags = IORESOURCE_MEM; 88 dev_params->res_count++; 89 } 90 91 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) != 0) { 92 res[dev_params->res_count].start = 93 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE); 94 res[dev_params->res_count].end = 95 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE) + 96 MCDI_QWORD(outbuf, 97 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) - 1; 98 res[dev_params->res_count].flags = IORESOURCE_MEM; 99 dev_params->res_count++; 100 } 101 102 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) != 0) { 103 res[dev_params->res_count].start = 104 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE); 105 res[dev_params->res_count].end = 106 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE) + 107 MCDI_QWORD(outbuf, 108 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) - 1; 109 res[dev_params->res_count].flags = IORESOURCE_MEM; 110 dev_params->res_count++; 111 } 112 113 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) != 0) { 114 res[dev_params->res_count].start = 115 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE); 116 res[dev_params->res_count].end = 117 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE) + 118 MCDI_QWORD(outbuf, 119 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) - 1; 120 res[dev_params->res_count].flags = IORESOURCE_MEM; 121 dev_params->res_count++; 122 } 123 124 dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID); 125 dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID); 126 dev_params->subsys_vendor = MCDI_WORD(outbuf, 127 CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID); 128 dev_params->subsys_device = MCDI_WORD(outbuf, 129 CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID); 130 dev_params->class = MCDI_DWORD(outbuf, 131 CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; 132 dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); 133 dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT); 134 135 return 0; 136 } 137 138 int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num) 139 { 140 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN); 141 int ret; 142 143 MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num); 144 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf), 145 NULL, 0, NULL); 146 147 return ret; 148 } 149 150 int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num) 151 { 152 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN); 153 int ret; 154 155 MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num); 156 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf), 157 NULL, 0, NULL); 158 159 return ret; 160 } 161 162 int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, 163 u32 msi_vector, u64 msi_address, u32 msi_data) 164 { 165 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN); 166 int ret; 167 168 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num); 169 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num); 170 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector); 171 MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address); 172 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data); 173 174 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf), 175 NULL, 0, NULL); 176 177 return ret; 178 } 179 180 int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) 181 { 182 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); 183 int ret; 184 185 MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_BUS, bus_num); 186 MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_DEVICE, dev_num); 187 188 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_RESET, inbuf, sizeof(inbuf), 189 NULL, 0, NULL); 190 191 return ret; 192 } 193 194 static int cdx_mcdi_ctrl_flag_get(struct cdx_mcdi *cdx, u8 bus_num, 195 u8 dev_num, u32 *flags) 196 { 197 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_IN_LEN); 198 MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN); 199 size_t outlen; 200 int ret; 201 202 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_BUS, bus_num); 203 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_DEVICE, dev_num); 204 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_GET, inbuf, 205 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 206 if (ret) 207 return ret; 208 209 if (outlen != MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN) 210 return -EIO; 211 212 *flags = MCDI_DWORD(outbuf, CDX_DEVICE_CONTROL_GET_OUT_FLAGS); 213 214 return 0; 215 } 216 217 static int cdx_mcdi_ctrl_flag_set(struct cdx_mcdi *cdx, u8 bus_num, 218 u8 dev_num, bool enable, int bit_pos) 219 { 220 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_SET_IN_LEN); 221 u32 flags; 222 int ret; 223 224 /* 225 * Get flags and then set/reset bit at bit_pos according to 226 * the input params. 227 */ 228 ret = cdx_mcdi_ctrl_flag_get(cdx, bus_num, dev_num, &flags); 229 if (ret) 230 return ret; 231 232 flags = flags & (u32)(~(BIT(bit_pos))); 233 if (enable) 234 flags |= (1 << bit_pos); 235 236 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_BUS, bus_num); 237 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_DEVICE, dev_num); 238 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_FLAGS, flags); 239 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_SET, inbuf, 240 sizeof(inbuf), NULL, 0, NULL); 241 242 return ret; 243 } 244 245 int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, 246 u8 dev_num, bool enable) 247 { 248 return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, 249 MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); 250 } 251 252 int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, 253 u8 dev_num, bool enable) 254 { 255 return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, 256 MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN); 257 } 258