1*1f95f618SAnoop Vijay // SPDX-License-Identifier: MIT 2*1f95f618SAnoop Vijay /* 3*1f95f618SAnoop Vijay * Copyright © 2026 Intel Corporation 4*1f95f618SAnoop Vijay */ 5*1f95f618SAnoop Vijay 6*1f95f618SAnoop Vijay #include <linux/bitfield.h> 7*1f95f618SAnoop Vijay #include <linux/cleanup.h> 8*1f95f618SAnoop Vijay #include <linux/minmax.h> 9*1f95f618SAnoop Vijay #include <linux/slab.h> 10*1f95f618SAnoop Vijay #include <linux/string.h> 11*1f95f618SAnoop Vijay 12*1f95f618SAnoop Vijay #include "regs/xe_sysctrl_regs.h" 13*1f95f618SAnoop Vijay #include "xe_device.h" 14*1f95f618SAnoop Vijay #include "xe_mmio.h" 15*1f95f618SAnoop Vijay #include "xe_pm.h" 16*1f95f618SAnoop Vijay #include "xe_printk.h" 17*1f95f618SAnoop Vijay #include "xe_sysctrl.h" 18*1f95f618SAnoop Vijay #include "xe_sysctrl_mailbox.h" 19*1f95f618SAnoop Vijay #include "xe_sysctrl_mailbox_types.h" 20*1f95f618SAnoop Vijay 21*1f95f618SAnoop Vijay struct xe_sysctrl_mailbox_msg_hdr { 22*1f95f618SAnoop Vijay __le32 data; 23*1f95f618SAnoop Vijay } __packed; 24*1f95f618SAnoop Vijay 25*1f95f618SAnoop Vijay #define XE_SYSCTRL_HDR_GROUP_ID(hdr) \ 26*1f95f618SAnoop Vijay FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data)) 27*1f95f618SAnoop Vijay 28*1f95f618SAnoop Vijay #define XE_SYSCTRL_HDR_COMMAND(hdr) \ 29*1f95f618SAnoop Vijay FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data)) 30*1f95f618SAnoop Vijay 31*1f95f618SAnoop Vijay #define XE_SYSCTRL_HDR_IS_RESPONSE(hdr) \ 32*1f95f618SAnoop Vijay FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, le32_to_cpu((hdr)->data)) 33*1f95f618SAnoop Vijay 34*1f95f618SAnoop Vijay #define XE_SYSCTRL_HDR_RESULT(hdr) \ 35*1f95f618SAnoop Vijay FIELD_GET(SYSCTRL_HDR_RESULT_MASK, le32_to_cpu((hdr)->data)) 36*1f95f618SAnoop Vijay 37*1f95f618SAnoop Vijay static bool sysctrl_wait_bit_clear(struct xe_sysctrl *sc, u32 bit_mask, 38*1f95f618SAnoop Vijay unsigned int timeout_ms) 39*1f95f618SAnoop Vijay { 40*1f95f618SAnoop Vijay int ret; 41*1f95f618SAnoop Vijay 42*1f95f618SAnoop Vijay ret = xe_mmio_wait32_not(sc->mmio, SYSCTRL_MB_CTRL, bit_mask, bit_mask, 43*1f95f618SAnoop Vijay timeout_ms * 1000, NULL, false); 44*1f95f618SAnoop Vijay 45*1f95f618SAnoop Vijay return ret == 0; 46*1f95f618SAnoop Vijay } 47*1f95f618SAnoop Vijay 48*1f95f618SAnoop Vijay static bool sysctrl_wait_bit_set(struct xe_sysctrl *sc, u32 bit_mask, 49*1f95f618SAnoop Vijay unsigned int timeout_ms) 50*1f95f618SAnoop Vijay { 51*1f95f618SAnoop Vijay int ret; 52*1f95f618SAnoop Vijay 53*1f95f618SAnoop Vijay ret = xe_mmio_wait32(sc->mmio, SYSCTRL_MB_CTRL, bit_mask, bit_mask, 54*1f95f618SAnoop Vijay timeout_ms * 1000, NULL, false); 55*1f95f618SAnoop Vijay 56*1f95f618SAnoop Vijay return ret == 0; 57*1f95f618SAnoop Vijay } 58*1f95f618SAnoop Vijay 59*1f95f618SAnoop Vijay static int sysctrl_write_frame(struct xe_sysctrl *sc, const void *frame, 60*1f95f618SAnoop Vijay size_t len) 61*1f95f618SAnoop Vijay { 62*1f95f618SAnoop Vijay static const struct xe_reg regs[] = { 63*1f95f618SAnoop Vijay SYSCTRL_MB_DATA0, SYSCTRL_MB_DATA1, SYSCTRL_MB_DATA2, SYSCTRL_MB_DATA3 64*1f95f618SAnoop Vijay }; 65*1f95f618SAnoop Vijay struct xe_device *xe = sc_to_xe(sc); 66*1f95f618SAnoop Vijay u32 val[XE_SYSCTRL_MB_FRAME_SIZE / sizeof(u32)] = {0}; 67*1f95f618SAnoop Vijay u32 dw = DIV_ROUND_UP(len, sizeof(u32)); 68*1f95f618SAnoop Vijay u32 i; 69*1f95f618SAnoop Vijay 70*1f95f618SAnoop Vijay xe_assert(xe, len > 0 && len <= XE_SYSCTRL_MB_FRAME_SIZE); 71*1f95f618SAnoop Vijay 72*1f95f618SAnoop Vijay memcpy(val, frame, len); 73*1f95f618SAnoop Vijay 74*1f95f618SAnoop Vijay for (i = 0; i < dw; i++) 75*1f95f618SAnoop Vijay xe_mmio_write32(sc->mmio, regs[i], val[i]); 76*1f95f618SAnoop Vijay 77*1f95f618SAnoop Vijay return 0; 78*1f95f618SAnoop Vijay } 79*1f95f618SAnoop Vijay 80*1f95f618SAnoop Vijay static int sysctrl_read_frame(struct xe_sysctrl *sc, void *frame, 81*1f95f618SAnoop Vijay size_t len) 82*1f95f618SAnoop Vijay { 83*1f95f618SAnoop Vijay static const struct xe_reg regs[] = { 84*1f95f618SAnoop Vijay SYSCTRL_MB_DATA0, SYSCTRL_MB_DATA1, SYSCTRL_MB_DATA2, SYSCTRL_MB_DATA3 85*1f95f618SAnoop Vijay }; 86*1f95f618SAnoop Vijay struct xe_device *xe = sc_to_xe(sc); 87*1f95f618SAnoop Vijay u32 val[XE_SYSCTRL_MB_FRAME_SIZE / sizeof(u32)] = {0}; 88*1f95f618SAnoop Vijay u32 dw = DIV_ROUND_UP(len, sizeof(u32)); 89*1f95f618SAnoop Vijay u32 i; 90*1f95f618SAnoop Vijay 91*1f95f618SAnoop Vijay xe_assert(xe, len > 0 && len <= XE_SYSCTRL_MB_FRAME_SIZE); 92*1f95f618SAnoop Vijay 93*1f95f618SAnoop Vijay for (i = 0; i < dw; i++) 94*1f95f618SAnoop Vijay val[i] = xe_mmio_read32(sc->mmio, regs[i]); 95*1f95f618SAnoop Vijay 96*1f95f618SAnoop Vijay memcpy(frame, val, len); 97*1f95f618SAnoop Vijay 98*1f95f618SAnoop Vijay return 0; 99*1f95f618SAnoop Vijay } 100*1f95f618SAnoop Vijay 101*1f95f618SAnoop Vijay static void sysctrl_clear_response(struct xe_sysctrl *sc) 102*1f95f618SAnoop Vijay { 103*1f95f618SAnoop Vijay xe_mmio_rmw32(sc->mmio, SYSCTRL_MB_CTRL, SYSCTRL_MB_CTRL_RUN_BUSY_OUT, 0); 104*1f95f618SAnoop Vijay } 105*1f95f618SAnoop Vijay 106*1f95f618SAnoop Vijay static int sysctrl_prepare_command(struct xe_device *xe, 107*1f95f618SAnoop Vijay u8 group_id, u8 command, 108*1f95f618SAnoop Vijay const void *data_in, size_t data_in_len, 109*1f95f618SAnoop Vijay u8 **mbox_cmd, size_t *cmd_size) 110*1f95f618SAnoop Vijay { 111*1f95f618SAnoop Vijay struct xe_sysctrl_mailbox_msg_hdr *hdr; 112*1f95f618SAnoop Vijay size_t size; 113*1f95f618SAnoop Vijay u8 *buffer; 114*1f95f618SAnoop Vijay 115*1f95f618SAnoop Vijay xe_assert(xe, command <= SYSCTRL_HDR_COMMAND_MAX); 116*1f95f618SAnoop Vijay 117*1f95f618SAnoop Vijay if (data_in_len > XE_SYSCTRL_MB_MAX_MESSAGE_SIZE - sizeof(*hdr)) { 118*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Input data too large: %zu bytes\n", data_in_len); 119*1f95f618SAnoop Vijay return -EINVAL; 120*1f95f618SAnoop Vijay } 121*1f95f618SAnoop Vijay 122*1f95f618SAnoop Vijay size = sizeof(*hdr) + data_in_len; 123*1f95f618SAnoop Vijay 124*1f95f618SAnoop Vijay buffer = kmalloc(size, GFP_KERNEL); 125*1f95f618SAnoop Vijay if (!buffer) 126*1f95f618SAnoop Vijay return -ENOMEM; 127*1f95f618SAnoop Vijay 128*1f95f618SAnoop Vijay hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer; 129*1f95f618SAnoop Vijay hdr->data = cpu_to_le32(FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) | 130*1f95f618SAnoop Vijay FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command)); 131*1f95f618SAnoop Vijay 132*1f95f618SAnoop Vijay if (data_in && data_in_len) 133*1f95f618SAnoop Vijay memcpy(buffer + sizeof(*hdr), data_in, data_in_len); 134*1f95f618SAnoop Vijay 135*1f95f618SAnoop Vijay *mbox_cmd = buffer; 136*1f95f618SAnoop Vijay *cmd_size = size; 137*1f95f618SAnoop Vijay 138*1f95f618SAnoop Vijay return 0; 139*1f95f618SAnoop Vijay } 140*1f95f618SAnoop Vijay 141*1f95f618SAnoop Vijay static int sysctrl_send_frames(struct xe_sysctrl *sc, 142*1f95f618SAnoop Vijay const u8 *mbox_cmd, 143*1f95f618SAnoop Vijay size_t cmd_size, unsigned int timeout_ms) 144*1f95f618SAnoop Vijay { 145*1f95f618SAnoop Vijay struct xe_device *xe = sc_to_xe(sc); 146*1f95f618SAnoop Vijay u32 ctrl_reg, total_frames, frame; 147*1f95f618SAnoop Vijay size_t bytes_sent, frame_size; 148*1f95f618SAnoop Vijay 149*1f95f618SAnoop Vijay total_frames = DIV_ROUND_UP(cmd_size, XE_SYSCTRL_MB_FRAME_SIZE); 150*1f95f618SAnoop Vijay 151*1f95f618SAnoop Vijay if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) { 152*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Mailbox busy\n"); 153*1f95f618SAnoop Vijay return -EBUSY; 154*1f95f618SAnoop Vijay } 155*1f95f618SAnoop Vijay 156*1f95f618SAnoop Vijay sc->phase_bit ^= 1; 157*1f95f618SAnoop Vijay bytes_sent = 0; 158*1f95f618SAnoop Vijay 159*1f95f618SAnoop Vijay for (frame = 0; frame < total_frames; frame++) { 160*1f95f618SAnoop Vijay frame_size = min_t(size_t, cmd_size - bytes_sent, XE_SYSCTRL_MB_FRAME_SIZE); 161*1f95f618SAnoop Vijay 162*1f95f618SAnoop Vijay if (sysctrl_write_frame(sc, mbox_cmd + bytes_sent, frame_size)) { 163*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Failed to write frame %u\n", frame); 164*1f95f618SAnoop Vijay sc->phase_bit = 0; 165*1f95f618SAnoop Vijay return -EIO; 166*1f95f618SAnoop Vijay } 167*1f95f618SAnoop Vijay 168*1f95f618SAnoop Vijay ctrl_reg = SYSCTRL_MB_CTRL_RUN_BUSY | 169*1f95f618SAnoop Vijay REG_FIELD_PREP(SYSCTRL_FRAME_CURRENT_MASK, frame) | 170*1f95f618SAnoop Vijay REG_FIELD_PREP(SYSCTRL_FRAME_TOTAL_MASK, total_frames - 1) | 171*1f95f618SAnoop Vijay SYSCTRL_MB_CTRL_CMD | 172*1f95f618SAnoop Vijay (sc->phase_bit ? SYSCTRL_FRAME_PHASE : 0); 173*1f95f618SAnoop Vijay 174*1f95f618SAnoop Vijay xe_mmio_write32(sc->mmio, SYSCTRL_MB_CTRL, ctrl_reg); 175*1f95f618SAnoop Vijay 176*1f95f618SAnoop Vijay if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) { 177*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Frame %u acknowledgment timeout\n", frame); 178*1f95f618SAnoop Vijay sc->phase_bit = 0; 179*1f95f618SAnoop Vijay return -ETIMEDOUT; 180*1f95f618SAnoop Vijay } 181*1f95f618SAnoop Vijay 182*1f95f618SAnoop Vijay bytes_sent += frame_size; 183*1f95f618SAnoop Vijay } 184*1f95f618SAnoop Vijay 185*1f95f618SAnoop Vijay return 0; 186*1f95f618SAnoop Vijay } 187*1f95f618SAnoop Vijay 188*1f95f618SAnoop Vijay static int sysctrl_process_frame(struct xe_sysctrl *sc, void *out, 189*1f95f618SAnoop Vijay size_t frame_size, unsigned int timeout_ms, 190*1f95f618SAnoop Vijay bool *done) 191*1f95f618SAnoop Vijay { 192*1f95f618SAnoop Vijay u32 curr_frame, total_frames, ctrl_reg; 193*1f95f618SAnoop Vijay struct xe_device *xe = sc_to_xe(sc); 194*1f95f618SAnoop Vijay int ret; 195*1f95f618SAnoop Vijay 196*1f95f618SAnoop Vijay if (!sysctrl_wait_bit_set(sc, SYSCTRL_MB_CTRL_RUN_BUSY_OUT, timeout_ms)) { 197*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Response frame timeout\n"); 198*1f95f618SAnoop Vijay return -ETIMEDOUT; 199*1f95f618SAnoop Vijay } 200*1f95f618SAnoop Vijay 201*1f95f618SAnoop Vijay ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL); 202*1f95f618SAnoop Vijay total_frames = FIELD_GET(SYSCTRL_FRAME_TOTAL_MASK, ctrl_reg); 203*1f95f618SAnoop Vijay curr_frame = FIELD_GET(SYSCTRL_FRAME_CURRENT_MASK, ctrl_reg); 204*1f95f618SAnoop Vijay 205*1f95f618SAnoop Vijay ret = sysctrl_read_frame(sc, out, frame_size); 206*1f95f618SAnoop Vijay if (ret) 207*1f95f618SAnoop Vijay return ret; 208*1f95f618SAnoop Vijay 209*1f95f618SAnoop Vijay sysctrl_clear_response(sc); 210*1f95f618SAnoop Vijay 211*1f95f618SAnoop Vijay if (curr_frame == total_frames) 212*1f95f618SAnoop Vijay *done = true; 213*1f95f618SAnoop Vijay 214*1f95f618SAnoop Vijay return 0; 215*1f95f618SAnoop Vijay } 216*1f95f618SAnoop Vijay 217*1f95f618SAnoop Vijay static int sysctrl_receive_frames(struct xe_sysctrl *sc, 218*1f95f618SAnoop Vijay const struct xe_sysctrl_mailbox_msg_hdr *req, 219*1f95f618SAnoop Vijay void *data_out, size_t data_out_len, 220*1f95f618SAnoop Vijay size_t *rdata_len, unsigned int timeout_ms) 221*1f95f618SAnoop Vijay { 222*1f95f618SAnoop Vijay struct xe_sysctrl_mailbox_msg_hdr *hdr; 223*1f95f618SAnoop Vijay struct xe_device *xe = sc_to_xe(sc); 224*1f95f618SAnoop Vijay size_t remain = sizeof(*hdr) + data_out_len; 225*1f95f618SAnoop Vijay u8 *buffer __free(kfree) = kzalloc(remain, GFP_KERNEL); 226*1f95f618SAnoop Vijay size_t frame_size; 227*1f95f618SAnoop Vijay bool done = false; 228*1f95f618SAnoop Vijay int ret = 0; 229*1f95f618SAnoop Vijay u8 *out; 230*1f95f618SAnoop Vijay 231*1f95f618SAnoop Vijay if (!buffer) 232*1f95f618SAnoop Vijay return -ENOMEM; 233*1f95f618SAnoop Vijay 234*1f95f618SAnoop Vijay out = buffer; 235*1f95f618SAnoop Vijay while (!done && remain) { 236*1f95f618SAnoop Vijay frame_size = min_t(size_t, remain, XE_SYSCTRL_MB_FRAME_SIZE); 237*1f95f618SAnoop Vijay 238*1f95f618SAnoop Vijay ret = sysctrl_process_frame(sc, out, frame_size, timeout_ms, 239*1f95f618SAnoop Vijay &done); 240*1f95f618SAnoop Vijay if (ret) 241*1f95f618SAnoop Vijay return ret; 242*1f95f618SAnoop Vijay 243*1f95f618SAnoop Vijay remain -= frame_size; 244*1f95f618SAnoop Vijay out += frame_size; 245*1f95f618SAnoop Vijay } 246*1f95f618SAnoop Vijay 247*1f95f618SAnoop Vijay hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer; 248*1f95f618SAnoop Vijay 249*1f95f618SAnoop Vijay if (!XE_SYSCTRL_HDR_IS_RESPONSE(hdr) || 250*1f95f618SAnoop Vijay XE_SYSCTRL_HDR_GROUP_ID(hdr) != XE_SYSCTRL_HDR_GROUP_ID(req) || 251*1f95f618SAnoop Vijay XE_SYSCTRL_HDR_COMMAND(hdr) != XE_SYSCTRL_HDR_COMMAND(req)) { 252*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Response header mismatch\n"); 253*1f95f618SAnoop Vijay return -EPROTO; 254*1f95f618SAnoop Vijay } 255*1f95f618SAnoop Vijay 256*1f95f618SAnoop Vijay if (XE_SYSCTRL_HDR_RESULT(hdr) != 0) { 257*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Firmware error: 0x%02lx\n", 258*1f95f618SAnoop Vijay XE_SYSCTRL_HDR_RESULT(hdr)); 259*1f95f618SAnoop Vijay return -EIO; 260*1f95f618SAnoop Vijay } 261*1f95f618SAnoop Vijay 262*1f95f618SAnoop Vijay memcpy(data_out, hdr + 1, data_out_len); 263*1f95f618SAnoop Vijay *rdata_len = out - buffer - sizeof(*hdr); 264*1f95f618SAnoop Vijay 265*1f95f618SAnoop Vijay return 0; 266*1f95f618SAnoop Vijay } 267*1f95f618SAnoop Vijay 268*1f95f618SAnoop Vijay static int sysctrl_send_command(struct xe_sysctrl *sc, 269*1f95f618SAnoop Vijay const u8 *mbox_cmd, size_t cmd_size, 270*1f95f618SAnoop Vijay void *data_out, size_t data_out_len, 271*1f95f618SAnoop Vijay size_t *rdata_len, unsigned int timeout_ms) 272*1f95f618SAnoop Vijay { 273*1f95f618SAnoop Vijay const struct xe_sysctrl_mailbox_msg_hdr *hdr; 274*1f95f618SAnoop Vijay size_t received; 275*1f95f618SAnoop Vijay int ret; 276*1f95f618SAnoop Vijay 277*1f95f618SAnoop Vijay ret = sysctrl_send_frames(sc, mbox_cmd, cmd_size, timeout_ms); 278*1f95f618SAnoop Vijay if (ret) 279*1f95f618SAnoop Vijay return ret; 280*1f95f618SAnoop Vijay 281*1f95f618SAnoop Vijay if (!data_out || !rdata_len) 282*1f95f618SAnoop Vijay return 0; 283*1f95f618SAnoop Vijay 284*1f95f618SAnoop Vijay hdr = (const struct xe_sysctrl_mailbox_msg_hdr *)mbox_cmd; 285*1f95f618SAnoop Vijay 286*1f95f618SAnoop Vijay ret = sysctrl_receive_frames(sc, hdr, data_out, data_out_len, 287*1f95f618SAnoop Vijay &received, timeout_ms); 288*1f95f618SAnoop Vijay if (ret) 289*1f95f618SAnoop Vijay return ret; 290*1f95f618SAnoop Vijay 291*1f95f618SAnoop Vijay *rdata_len = received; 292*1f95f618SAnoop Vijay 293*1f95f618SAnoop Vijay return 0; 294*1f95f618SAnoop Vijay } 295*1f95f618SAnoop Vijay 296*1f95f618SAnoop Vijay /** 297*1f95f618SAnoop Vijay * xe_sysctrl_mailbox_init - Initialize System Controller mailbox interface 298*1f95f618SAnoop Vijay * @sc: System controller structure 299*1f95f618SAnoop Vijay * 300*1f95f618SAnoop Vijay * Initialize system controller mailbox interface for communication. 301*1f95f618SAnoop Vijay */ 302*1f95f618SAnoop Vijay void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc) 303*1f95f618SAnoop Vijay { 304*1f95f618SAnoop Vijay u32 ctrl_reg; 305*1f95f618SAnoop Vijay 306*1f95f618SAnoop Vijay ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL); 307*1f95f618SAnoop Vijay sc->phase_bit = (ctrl_reg & SYSCTRL_FRAME_PHASE) ? 1 : 0; 308*1f95f618SAnoop Vijay } 309*1f95f618SAnoop Vijay 310*1f95f618SAnoop Vijay /** 311*1f95f618SAnoop Vijay * xe_sysctrl_send_command() - Send mailbox command to System Controller 312*1f95f618SAnoop Vijay * @sc: System Controller instance 313*1f95f618SAnoop Vijay * @cmd: Command descriptor containing request header and payload buffers 314*1f95f618SAnoop Vijay * @rdata_len: Pointer to store actual response data length 315*1f95f618SAnoop Vijay * 316*1f95f618SAnoop Vijay * Sends a mailbox command to System Controller firmware using 317*1f95f618SAnoop Vijay * System Controller mailbox and waits for a response. 318*1f95f618SAnoop Vijay * 319*1f95f618SAnoop Vijay * Request payload is provided via @cmd->data_in and @cmd->data_in_len. 320*1f95f618SAnoop Vijay * If a response is expected, @cmd->data_out must point to a buffer of 321*1f95f618SAnoop Vijay * size @cmd->data_out_len supplied by caller. 322*1f95f618SAnoop Vijay * 323*1f95f618SAnoop Vijay * On success, @rdata_len is updated with number of valid response bytes 324*1f95f618SAnoop Vijay * returned by firmware, bounded by @cmd->data_out_len. 325*1f95f618SAnoop Vijay * 326*1f95f618SAnoop Vijay * Return: 0 on success, or negative errno on failure. 327*1f95f618SAnoop Vijay */ 328*1f95f618SAnoop Vijay int xe_sysctrl_send_command(struct xe_sysctrl *sc, 329*1f95f618SAnoop Vijay struct xe_sysctrl_mailbox_command *cmd, 330*1f95f618SAnoop Vijay size_t *rdata_len) 331*1f95f618SAnoop Vijay { 332*1f95f618SAnoop Vijay struct xe_device *xe = sc_to_xe(sc); 333*1f95f618SAnoop Vijay u8 group_id, command_code; 334*1f95f618SAnoop Vijay u8 *mbox_cmd = NULL; 335*1f95f618SAnoop Vijay size_t cmd_size = 0; 336*1f95f618SAnoop Vijay int ret; 337*1f95f618SAnoop Vijay 338*1f95f618SAnoop Vijay guard(xe_pm_runtime_noresume)(xe); 339*1f95f618SAnoop Vijay 340*1f95f618SAnoop Vijay if (!xe->info.has_sysctrl) 341*1f95f618SAnoop Vijay return -ENODEV; 342*1f95f618SAnoop Vijay 343*1f95f618SAnoop Vijay xe_assert(xe, cmd->data_in || cmd->data_out); 344*1f95f618SAnoop Vijay xe_assert(xe, !cmd->data_in || cmd->data_in_len); 345*1f95f618SAnoop Vijay xe_assert(xe, !cmd->data_out || cmd->data_out_len); 346*1f95f618SAnoop Vijay 347*1f95f618SAnoop Vijay group_id = XE_SYSCTRL_APP_HDR_GROUP_ID(&cmd->header); 348*1f95f618SAnoop Vijay command_code = XE_SYSCTRL_APP_HDR_COMMAND(&cmd->header); 349*1f95f618SAnoop Vijay 350*1f95f618SAnoop Vijay might_sleep(); 351*1f95f618SAnoop Vijay 352*1f95f618SAnoop Vijay ret = sysctrl_prepare_command(xe, group_id, command_code, 353*1f95f618SAnoop Vijay cmd->data_in, cmd->data_in_len, 354*1f95f618SAnoop Vijay &mbox_cmd, &cmd_size); 355*1f95f618SAnoop Vijay if (ret) { 356*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Failed to prepare command: %pe\n", ERR_PTR(ret)); 357*1f95f618SAnoop Vijay return ret; 358*1f95f618SAnoop Vijay } 359*1f95f618SAnoop Vijay 360*1f95f618SAnoop Vijay guard(mutex)(&sc->cmd_lock); 361*1f95f618SAnoop Vijay 362*1f95f618SAnoop Vijay ret = sysctrl_send_command(sc, mbox_cmd, cmd_size, 363*1f95f618SAnoop Vijay cmd->data_out, cmd->data_out_len, rdata_len, 364*1f95f618SAnoop Vijay XE_SYSCTRL_MB_DEFAULT_TIMEOUT_MS); 365*1f95f618SAnoop Vijay if (ret) 366*1f95f618SAnoop Vijay xe_err(xe, "sysctrl: Mailbox command failed: %pe\n", ERR_PTR(ret)); 367*1f95f618SAnoop Vijay 368*1f95f618SAnoop Vijay kfree(mbox_cmd); 369*1f95f618SAnoop Vijay 370*1f95f618SAnoop Vijay return ret; 371*1f95f618SAnoop Vijay } 372