1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2023-2026 Intel Corporation */ 3 #include <linux/align.h> 4 #include <linux/bitfield.h> 5 #include <linux/bits.h> 6 #include <linux/cleanup.h> 7 #include <linux/dev_printk.h> 8 #include <linux/err.h> 9 #include <linux/io.h> 10 #include <linux/pci.h> 11 #include <linux/sizes.h> 12 #include <linux/spinlock.h> 13 #include <linux/types.h> 14 15 #include "hw_heci.h" 16 #include "hw_heci_regs.h" 17 #include "hw_msg.h" 18 19 /** 20 * heci_reg_read - Reads 32bit data from the issei heci device 21 * @hw: the heci hardware structure 22 * @offset: offset from which to read the data 23 * 24 * Return: register value (u32) 25 */ 26 static inline u32 heci_reg_read(const struct issei_heci_hw *hw, unsigned long offset) 27 { 28 return ioread32(hw->mem_addr + offset); 29 } 30 31 /** 32 * heci_reg_write - Writes 32bit data to the issei heci device 33 * 34 * @hw: the heci hardware structure 35 * @offset: offset from which to write the data 36 * @value: register value to write (u32) 37 */ 38 static inline void heci_reg_write(const struct issei_heci_hw *hw, unsigned long offset, u32 value) 39 { 40 iowrite32(value, hw->mem_addr + offset); 41 } 42 43 /** 44 * heci_fwcbrw_read - Reads 32bit data from heci circular buffer 45 * @hw: the heci hardware structure 46 * 47 * Return: FW_CB_RW register value (u32) 48 */ 49 static inline u32 heci_fwcbrw_read(const struct issei_heci_hw *hw) 50 { 51 return heci_reg_read(hw, FW_CB_RW); 52 } 53 54 /** 55 * heci_hcbww_write - write 32bit data to the host circular buffer 56 * @hw: the heci hardware structure 57 * @data: 32bit data to be written to the host circular buffer 58 */ 59 static inline void heci_hcbww_write(const struct issei_heci_hw *hw, u32 data) 60 { 61 heci_reg_write(hw, H_CB_WW, data); 62 } 63 64 /** 65 * heci_irq_src - Filters IRQ source bits from the host CSR 66 * @hcsr: host CSR register value 67 * 68 * Return: interrupt source bits of host CSR 69 */ 70 static inline u32 heci_irq_src(u32 hcsr) 71 { 72 return hcsr & H_CSR_IS; 73 } 74 75 /** 76 * heci_hcsr_read - Reads 32bit data from the host CSR 77 * @idev: the device structure 78 * 79 * Return: H_CSR register value (u32) 80 */ 81 static inline u32 heci_hcsr_read(const struct issei_device *idev) 82 { 83 return heci_reg_read(to_heci_hw(idev), H_CSR); 84 } 85 86 /** 87 * heci_hcsr_write - writes H_CSR register to device 88 * @idev: the device structure 89 * @reg: new register value 90 */ 91 static inline void heci_hcsr_write(struct issei_device *idev, u32 reg) 92 { 93 heci_reg_write(to_heci_hw(idev), H_CSR, reg); 94 } 95 96 /** 97 * heci_hcsr_set - writes H_CSR register to the heci device 98 * @idev: the device structure 99 * @reg: new register value 100 * 101 * Writes H_CSR register to the heci device 102 * and ignores the H_IS bit for it is write-one-to-zero. 103 * 104 */ 105 static inline void heci_hcsr_set(struct issei_device *idev, u32 reg) 106 { 107 reg &= ~H_CSR_IS; 108 heci_hcsr_write(idev, reg); 109 } 110 111 /** 112 * heci_hcsr_set_hig - set host interrupt (set H_CSR_IG) 113 * @idev: the device structure 114 */ 115 static inline void heci_hcsr_set_hig(struct issei_device *idev) 116 { 117 u32 reg; 118 119 reg = heci_hcsr_read(idev) | H_CSR_IG; 120 heci_hcsr_set(idev, reg); 121 } 122 123 /** 124 * heci_fwcsr_read - Reads 32bit data from the FW CSR 125 * @idev: the device structure 126 * 127 * Return: FW_CSR_HA register value (u32) 128 */ 129 static inline u32 heci_fwcsr_read(const struct issei_device *idev) 130 { 131 return heci_reg_read(to_heci_hw(idev), FW_CSR_HA); 132 } 133 134 /** 135 * heci_count_full_read_slots - counts read full slots. 136 * @idev: the device structure 137 * 138 * Return: -EOVERFLOW if overflow, otherwise filled slots count 139 */ 140 static int heci_count_full_read_slots(struct issei_device *idev) 141 { 142 u8 buffer_depth, filled_slots; 143 u8 read_ptr, write_ptr; 144 u32 reg; 145 146 reg = heci_fwcsr_read(idev); 147 buffer_depth = (u8)FIELD_GET(FW_CSR_CBD, reg); 148 read_ptr = (u8)FIELD_GET(FW_CSR_CBRP, reg); 149 write_ptr = (u8)FIELD_GET(FW_CSR_CBWP, reg); 150 filled_slots = write_ptr - read_ptr; 151 152 /* check for overflow */ 153 if (filled_slots > buffer_depth) 154 return -EOVERFLOW; 155 156 dev_dbg(&idev->dev, "filled_slots = %08x\n", filled_slots); 157 return filled_slots; 158 } 159 160 /** 161 * heci_irq_disable - disables heci device interrupts 162 * @idev: the device structure 163 * @reg: supplied hcsr register value 164 * 165 * disables heci device interrupts using supplied hcsr register value. 166 */ 167 static inline void heci_irq_disable(struct issei_device *idev, u32 reg) 168 { 169 reg &= ~H_CSR_IE; 170 heci_hcsr_set(idev, reg); 171 } 172 173 /** 174 * heci_irq_clear - clear and stop interrupts 175 * @idev: the device structure 176 * @reg: supplied hcsr register value 177 */ 178 static inline void heci_irq_clear(struct issei_device *idev, u32 reg) 179 { 180 if (heci_irq_src(reg)) 181 heci_hcsr_write(idev, reg); 182 } 183 184 /** 185 * issei_heci_irq_clear - clear and stop interrupts 186 * @idev: the device structure 187 */ 188 static void issei_heci_irq_clear(struct issei_device *idev) 189 { 190 u32 reg = heci_hcsr_read(idev); 191 192 heci_irq_clear(idev, reg); 193 } 194 195 /** 196 * issei_heci_irq_enable - enables heci device interrupts 197 * @idev: the device structure 198 */ 199 static void issei_heci_irq_enable(struct issei_device *idev) 200 { 201 u32 reg; 202 203 reg = heci_hcsr_read(idev) | H_CSR_IE; 204 heci_hcsr_set(idev, reg); 205 } 206 207 /** 208 * issei_heci_irq_disable - disables heci device interrupts 209 * @idev: the device structure 210 */ 211 static void issei_heci_irq_disable(struct issei_device *idev) 212 { 213 u32 reg = heci_hcsr_read(idev); 214 215 heci_irq_disable(idev, reg); 216 } 217 218 static void issei_heci_irq_sync(struct issei_device *idev) 219 { 220 synchronize_irq(to_heci_hw(idev)->irq); 221 } 222 223 /** 224 * issei_heci_hw_reset_release - release device from the reset 225 * @idev: the device structure 226 */ 227 static void issei_heci_hw_reset_release(struct issei_device *idev) 228 { 229 u32 reg = heci_hcsr_read(idev); 230 231 reg |= H_CSR_IG; 232 reg &= ~H_CSR_RST; 233 heci_hcsr_set(idev, reg); 234 } 235 236 /** 237 * heci_hw_is_ready - check whether the hw has turned ready 238 * @idev: the device structure 239 * 240 * Return: bool 241 */ 242 static bool heci_hw_is_ready(struct issei_device *idev) 243 { 244 u32 reg = heci_fwcsr_read(idev); 245 246 return reg & FW_CSR_RDY; 247 } 248 249 /** 250 * heci_hw_is_resetting - check whether the hw is in reset 251 * @idev: the device structure 252 * 253 * Return: bool 254 */ 255 static bool heci_hw_is_resetting(struct issei_device *idev) 256 { 257 u32 reg = heci_fwcsr_read(idev); 258 259 return reg & FW_CSR_RST; 260 } 261 262 /** 263 * issei_heci_host_set_ready - enable device 264 * @idev: the device structure 265 */ 266 static void issei_heci_host_set_ready(struct issei_device *idev) 267 { 268 u32 reg = heci_hcsr_read(idev); 269 270 reg |= H_CSR_IE | H_CSR_IG | H_CSR_RDY; 271 heci_hcsr_set(idev, reg); 272 } 273 274 /** 275 * issei_heci_hw_reset - resets fw via heci csr register. 276 * @idev: the device structure 277 * @enable: if interrupt should be enabled after reset. 278 * 279 * Return: 0 on success an error code otherwise 280 */ 281 static int issei_heci_hw_reset(struct issei_device *idev, bool enable) 282 { 283 u32 reg; 284 285 if (enable) 286 issei_heci_irq_enable(idev); 287 288 reg = heci_hcsr_read(idev); 289 /* 290 * H_CSR_RST may be found lit before reset is started, 291 * for example if preceding reset flow hasn't completed. 292 * In that case asserting H_CSR_RST will be ignored, therefore 293 * we need to clean H_CSR_RST bit to start a successful reset sequence. 294 */ 295 if (reg & H_CSR_RST) { 296 dev_warn(&idev->dev, "H_CSR_RST is set = 0x%08X", reg); 297 reg &= ~H_CSR_RST; 298 heci_hcsr_set(idev, reg); 299 reg = heci_hcsr_read(idev); 300 } 301 302 reg |= H_CSR_RST | H_CSR_IG | H_CSR_IS; 303 304 if (!enable) 305 reg &= ~H_CSR_IE; 306 307 heci_hcsr_write(idev, reg); 308 309 /* 310 * Host reads the H_CSR once to ensure that the 311 * posted write to H_CSR completes. 312 */ 313 reg = heci_hcsr_read(idev); 314 315 if (!(reg & H_CSR_RST)) 316 dev_warn(&idev->dev, "H_CSR_RST is not set = 0x%08X", reg); 317 318 if (reg & H_CSR_RDY) 319 dev_warn(&idev->dev, "H_CSR_RDY is not cleared 0x%08X", reg); 320 321 if (!enable) 322 issei_heci_hw_reset_release(idev); 323 return 0; 324 } 325 326 /** 327 * issei_heci_irq_write_generate - generate interrupt to signal write completion. 328 * @idev: the device structure 329 * 330 * Return: 0 on success, -EIO if hardware is not ready and requires reset 331 */ 332 static int issei_heci_irq_write_generate(struct issei_device *idev) 333 { 334 struct issei_heci_hw *hw = to_heci_hw(idev); 335 336 scoped_guard(spinlock_irqsave, &hw->access_lock) 337 heci_hcsr_set_hig(idev); 338 if (!heci_hw_is_ready(idev)) 339 return -EIO; 340 return 0; 341 } 342 343 /** 344 * issei_heci_hw_config - initial hardware configuration. 345 * @idev: the device structure 346 * 347 * Return: 0 always 348 */ 349 static int issei_heci_hw_config(struct issei_device *idev) 350 { 351 struct issei_heci_hw *hw = to_heci_hw(idev); 352 u32 reg; 353 354 /* Doesn't change in runtime */ 355 reg = heci_hcsr_read(idev); 356 hw->hbuf_depth = FIELD_GET(H_CSR_CBD, reg); 357 358 return 0; 359 } 360 361 /** 362 * heci_write_hbuf - write to hardware buffer 363 * @idev: the device structure 364 * @data: data to write 365 * @data_len: data size 366 * 367 * Return: 0 on success, <0 on error 368 */ 369 static int heci_write_hbuf(struct issei_device *idev, const void *data, size_t data_len) 370 { 371 struct issei_heci_hw *hw = to_heci_hw(idev); 372 373 if (!IS_ALIGNED(data_len, CB_SLOT_SIZE)) { 374 dev_err(&idev->dev, "Data size %zu not aligned to slot size %zu\n", 375 data_len, CB_SLOT_SIZE); 376 return -EINVAL; 377 } 378 379 scoped_guard(spinlock_irqsave, &hw->access_lock) { 380 const u32 *reg_buf = data; 381 size_t i; 382 383 for (i = 0; i < data_len / CB_SLOT_SIZE; i++) 384 heci_hcbww_write(hw, reg_buf[i]); 385 } 386 387 return issei_heci_irq_write_generate(idev); 388 } 389 390 /** 391 * heci_read_hbuf - read data from hardware buffer 392 * @idev: the device structure 393 * @data: buffer to store read data 394 * @data_len: buffer size 395 * 396 * Return: 0 on success, <0 on error 397 */ 398 static int heci_read_hbuf(struct issei_device *idev, void *data, size_t data_len) 399 { 400 struct issei_heci_hw *hw = to_heci_hw(idev); 401 u32 *reg_buf = data; 402 403 if (!IS_ALIGNED(data_len, CB_SLOT_SIZE)) { 404 dev_err(&idev->dev, "Data size %zu not aligned to slot size %zu\n", 405 data_len, CB_SLOT_SIZE); 406 return -EINVAL; 407 } 408 409 scoped_guard(spinlock_irqsave, &hw->access_lock) { 410 for (; data_len >= CB_SLOT_SIZE; data_len -= CB_SLOT_SIZE) 411 *reg_buf++ = heci_fwcbrw_read(hw); 412 } 413 return 0; 414 } 415 416 /** 417 * issei_heci_setup_message_send - send setup message to firmware 418 * @idev: the device structure 419 * 420 * Return: 0 on success, <0 on error 421 */ 422 static int issei_heci_setup_message_send(struct issei_device *idev) 423 { 424 struct ham_setup_shared_memory_req req = { 425 .msg_id = HAM_CB_MESSAGE_ID_REQ, 426 .ver = HAM_CB_MESSAGE_VER, 427 .reserved = 0, 428 .buffer_physical_address = idev->dma.daddr, 429 .host_to_fw_section_length = idev->dma.length.h2f, 430 .fw_to_host_section_length = idev->dma.length.f2h, 431 .control_length = idev->dma.length.ctl 432 }; 433 int ret; 434 435 ret = heci_write_hbuf(idev, &req, sizeof(req)); 436 if (ret) 437 dev_err(&idev->dev, "Shared memory req write failed ret = %d\n", ret); 438 439 return ret; 440 } 441 442 /** 443 * issei_heci_setup_message_recv - receive setup message response from firmware 444 * @idev: the device structure 445 * 446 * Return: 0 on success, <0 on error 447 */ 448 static int issei_heci_setup_message_recv(struct issei_device *idev) 449 { 450 struct ham_setup_shared_memory_res res; 451 int ret; 452 453 if (heci_count_full_read_slots(idev) != sizeof(res) / CB_SLOT_SIZE) { 454 dev_dbg(&idev->dev, "Setup response is not fully received\n"); 455 return -ENODATA; 456 } 457 458 ret = heci_read_hbuf(idev, &res, sizeof(res)); 459 if (ret) { 460 dev_err(&idev->dev, "Shared memory res read failed ret = %d\n", ret); 461 return ret; 462 } 463 464 if (res.msg_id != HAM_CB_MESSAGE_ID_RES) { 465 dev_err(&idev->dev, "Shared memory res header 0x%x != 0x%x\n", 466 res.msg_id, HAM_CB_MESSAGE_ID_RES); 467 return -EPROTO; 468 } 469 if (res.status != 0) { 470 dev_err(&idev->dev, "Shared memory res status %d != 0\n", res.status); 471 return -EPROTO; 472 } 473 474 return 0; 475 } 476 477 static const struct issei_hw_ops hw_heci_ops = { 478 .irq_clear = issei_heci_irq_clear, 479 .irq_enable = issei_heci_irq_enable, 480 .irq_disable = issei_heci_irq_disable, 481 .irq_sync = issei_heci_irq_sync, 482 483 .hw_reset = issei_heci_hw_reset, 484 .hw_config = issei_heci_hw_config, 485 .hw_reset_release = issei_heci_hw_reset_release, 486 .host_set_ready = issei_heci_host_set_ready, 487 488 .hw_is_ready = heci_hw_is_ready, 489 490 .setup_message_send = issei_heci_setup_message_send, 491 .setup_message_recv = issei_heci_setup_message_recv, 492 .irq_write_generate = issei_heci_irq_write_generate, 493 }; 494 495 const struct issei_hw_ops *issei_heci_get_ops(void) 496 { 497 return &hw_heci_ops; 498 } 499 500 irqreturn_t issei_heci_irq_quick_handler(int irq, void *dev_id) 501 { 502 struct issei_device *idev = dev_id; 503 struct issei_heci_hw *hw = to_heci_hw(idev); 504 u32 reg; 505 506 reg = heci_hcsr_read(idev); 507 if (!heci_irq_src(reg)) 508 return IRQ_NONE; 509 510 scoped_guard(spinlock_irqsave, &hw->access_lock) { 511 reg = heci_hcsr_read(idev); 512 heci_irq_clear(idev, reg); 513 514 if (heci_hw_is_resetting(idev)) 515 heci_hcsr_set_hig(idev); 516 } 517 518 dev_dbg(&idev->dev, "interrupt source 0x%08X\n", heci_irq_src(reg)); 519 520 issei_poke_process_thread(idev); 521 522 return IRQ_HANDLED; 523 } 524 525 static const struct hw_heci_cfg hw_heci_pch_cfg = { 526 .dma_length.h2f = SZ_64K, 527 .dma_length.f2h = SZ_64K, 528 .dma_length.ctl = SZ_4K, 529 }; 530 531 const struct hw_heci_cfg *issei_heci_get_cfg(kernel_ulong_t idx) 532 { 533 return &hw_heci_pch_cfg; 534 } 535 536 /** 537 * issei_heci_dev_init - initializes the issei device structure with hw_heci 538 * @idev: device structure 539 * @mem_addr: memory address on bar 540 * @cfg: per device generation config 541 */ 542 void issei_heci_dev_init(struct issei_device *idev, 543 void __iomem *mem_addr, const struct hw_heci_cfg *cfg) 544 { 545 struct issei_heci_hw *hw = to_heci_hw(idev); 546 547 spin_lock_init(&hw->access_lock); 548 hw->mem_addr = mem_addr; 549 hw->cfg = cfg; 550 } 551