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