258 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 11int 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 28int 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 48int 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 138int 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 150int 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 162int 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 180int 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 194static 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 217static 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 to226 * 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 245int 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 252int 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