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_functions.h" 9 10 int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx) 11 { 12 MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN); 13 size_t outlen; 14 int ret; 15 16 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_BUSES, NULL, 0, 17 outbuf, sizeof(outbuf), &outlen); 18 if (ret) 19 return ret; 20 21 if (outlen != MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN) 22 return -EIO; 23 24 return MCDI_DWORD(outbuf, CDX_BUS_ENUM_BUSES_OUT_BUS_COUNT); 25 } 26 27 int cdx_mcdi_get_num_devs(struct cdx_mcdi *cdx, int bus_num) 28 { 29 MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN); 30 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_IN_LEN); 31 size_t outlen; 32 int ret; 33 34 MCDI_SET_DWORD(inbuf, CDX_BUS_ENUM_DEVICES_IN_BUS, bus_num); 35 36 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_DEVICES, inbuf, sizeof(inbuf), 37 outbuf, sizeof(outbuf), &outlen); 38 if (ret) 39 return ret; 40 41 if (outlen != MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN) 42 return -EIO; 43 44 return MCDI_DWORD(outbuf, CDX_BUS_ENUM_DEVICES_OUT_DEVICE_COUNT); 45 } 46 47 int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, 48 u8 bus_num, u8 dev_num, 49 struct cdx_dev_params *dev_params) 50 { 51 MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN); 52 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); 53 struct resource *res = &dev_params->res[0]; 54 size_t outlen; 55 u32 req_id; 56 int ret; 57 58 MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_BUS, bus_num); 59 MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_DEVICE, dev_num); 60 61 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG, inbuf, sizeof(inbuf), 62 outbuf, sizeof(outbuf), &outlen); 63 if (ret) 64 return ret; 65 66 if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN) 67 return -EIO; 68 69 dev_params->bus_num = bus_num; 70 dev_params->dev_num = dev_num; 71 72 req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); 73 dev_params->req_id = req_id; 74 75 dev_params->msi_dev_id = MCDI_DWORD(outbuf, 76 CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID); 77 78 dev_params->res_count = 0; 79 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { 80 res[dev_params->res_count].start = 81 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE); 82 res[dev_params->res_count].end = 83 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE) + 84 MCDI_QWORD(outbuf, 85 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) - 1; 86 res[dev_params->res_count].flags = IORESOURCE_MEM; 87 dev_params->res_count++; 88 } 89 90 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) != 0) { 91 res[dev_params->res_count].start = 92 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE); 93 res[dev_params->res_count].end = 94 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE) + 95 MCDI_QWORD(outbuf, 96 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) - 1; 97 res[dev_params->res_count].flags = IORESOURCE_MEM; 98 dev_params->res_count++; 99 } 100 101 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) != 0) { 102 res[dev_params->res_count].start = 103 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE); 104 res[dev_params->res_count].end = 105 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE) + 106 MCDI_QWORD(outbuf, 107 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) - 1; 108 res[dev_params->res_count].flags = IORESOURCE_MEM; 109 dev_params->res_count++; 110 } 111 112 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) != 0) { 113 res[dev_params->res_count].start = 114 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE); 115 res[dev_params->res_count].end = 116 MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE) + 117 MCDI_QWORD(outbuf, 118 CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) - 1; 119 res[dev_params->res_count].flags = IORESOURCE_MEM; 120 dev_params->res_count++; 121 } 122 123 dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID); 124 dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID); 125 dev_params->subsys_vendor = MCDI_WORD(outbuf, 126 CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID); 127 dev_params->subsys_device = MCDI_WORD(outbuf, 128 CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID); 129 dev_params->class = MCDI_DWORD(outbuf, 130 CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; 131 dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); 132 dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT); 133 134 return 0; 135 } 136 137 int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num) 138 { 139 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN); 140 int ret; 141 142 MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num); 143 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf), 144 NULL, 0, NULL); 145 146 return ret; 147 } 148 149 int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num) 150 { 151 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN); 152 int ret; 153 154 MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num); 155 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf), 156 NULL, 0, NULL); 157 158 return ret; 159 } 160 161 int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, 162 u32 msi_vector, u64 msi_address, u32 msi_data) 163 { 164 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN); 165 int ret; 166 167 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num); 168 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num); 169 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector); 170 MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address); 171 MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data); 172 173 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf), 174 NULL, 0, NULL); 175 176 return ret; 177 } 178 179 int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) 180 { 181 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); 182 int ret; 183 184 MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_BUS, bus_num); 185 MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_DEVICE, dev_num); 186 187 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_RESET, inbuf, sizeof(inbuf), 188 NULL, 0, NULL); 189 190 return ret; 191 } 192 193 static int cdx_mcdi_ctrl_flag_get(struct cdx_mcdi *cdx, u8 bus_num, 194 u8 dev_num, u32 *flags) 195 { 196 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_IN_LEN); 197 MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN); 198 size_t outlen; 199 int ret; 200 201 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_BUS, bus_num); 202 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_DEVICE, dev_num); 203 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_GET, inbuf, 204 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 205 if (ret) 206 return ret; 207 208 if (outlen != MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN) 209 return -EIO; 210 211 *flags = MCDI_DWORD(outbuf, CDX_DEVICE_CONTROL_GET_OUT_FLAGS); 212 213 return 0; 214 } 215 216 static int cdx_mcdi_ctrl_flag_set(struct cdx_mcdi *cdx, u8 bus_num, 217 u8 dev_num, bool enable, int bit_pos) 218 { 219 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_SET_IN_LEN); 220 u32 flags; 221 int ret; 222 223 /* 224 * Get flags and then set/reset bit at bit_pos according to 225 * the input params. 226 */ 227 ret = cdx_mcdi_ctrl_flag_get(cdx, bus_num, dev_num, &flags); 228 if (ret) 229 return ret; 230 231 flags = flags & (u32)(~(BIT(bit_pos))); 232 if (enable) 233 flags |= (1 << bit_pos); 234 235 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_BUS, bus_num); 236 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_DEVICE, dev_num); 237 MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_FLAGS, flags); 238 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_SET, inbuf, 239 sizeof(inbuf), NULL, 0, NULL); 240 241 return ret; 242 } 243 244 int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, 245 u8 dev_num, bool enable) 246 { 247 return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, 248 MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); 249 } 250 251 int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, 252 u8 dev_num, bool enable) 253 { 254 return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, 255 MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN); 256 } 257