Skip to content

Commit 7545216

Browse files
mbrost05johnharr-intel
authored andcommitted
drm/i915/guc: Optimize CTB writes and reads
CTB writes are now in the path of command submission and should be optimized for performance. Rather than reading CTB descriptor values (e.g. head, tail) which could result in accesses across the PCIe bus, store shadow local copies and only read/write the descriptor values when absolutely necessary. Also store the current space in the each channel locally. v2: (Michal) - Add additional sanity checks for head / tail pointers - Use GUC_CTB_HDR_LEN rather than magic 1 v3: (Michal / John H) - Drop redundant check of head value v4: (John H) - Drop redundant checks of tail / head values v5: (Michal) - Address more nits v6: (Michal) - Add GEM_BUG_ON sanity check on ctb->space Signed-off-by: John Harrison <[email protected]> Signed-off-by: Matthew Brost <[email protected]> Reviewed-by: Michal Wajdeczko <[email protected]> Signed-off-by: John Harrison <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent b43b995 commit 7545216

File tree

2 files changed

+67
-32
lines changed

2 files changed

+67
-32
lines changed

drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ static void guc_ct_buffer_desc_init(struct guc_ct_buffer_desc *desc)
130130
static void guc_ct_buffer_reset(struct intel_guc_ct_buffer *ctb)
131131
{
132132
ctb->broken = false;
133+
ctb->tail = 0;
134+
ctb->head = 0;
135+
ctb->space = CIRC_SPACE(ctb->tail, ctb->head, ctb->size);
136+
133137
guc_ct_buffer_desc_init(ctb->desc);
134138
}
135139

@@ -383,10 +387,8 @@ static int ct_write(struct intel_guc_ct *ct,
383387
{
384388
struct intel_guc_ct_buffer *ctb = &ct->ctbs.send;
385389
struct guc_ct_buffer_desc *desc = ctb->desc;
386-
u32 head = desc->head;
387-
u32 tail = desc->tail;
390+
u32 tail = ctb->tail;
388391
u32 size = ctb->size;
389-
u32 used;
390392
u32 header;
391393
u32 hxg;
392394
u32 type;
@@ -396,25 +398,22 @@ static int ct_write(struct intel_guc_ct *ct,
396398
if (unlikely(desc->status))
397399
goto corrupted;
398400

399-
if (unlikely((tail | head) >= size)) {
400-
CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n",
401-
head, tail, size);
401+
GEM_BUG_ON(tail > size);
402+
403+
#ifdef CONFIG_DRM_I915_DEBUG_GUC
404+
if (unlikely(tail != READ_ONCE(desc->tail))) {
405+
CT_ERROR(ct, "Tail was modified %u != %u\n",
406+
desc->tail, tail);
407+
desc->status |= GUC_CTB_STATUS_MISMATCH;
408+
goto corrupted;
409+
}
410+
if (unlikely(READ_ONCE(desc->head) >= size)) {
411+
CT_ERROR(ct, "Invalid head offset %u >= %u)\n",
412+
desc->head, size);
402413
desc->status |= GUC_CTB_STATUS_OVERFLOW;
403414
goto corrupted;
404415
}
405-
406-
/*
407-
* tail == head condition indicates empty. GuC FW does not support
408-
* using up the entire buffer to get tail == head meaning full.
409-
*/
410-
if (tail < head)
411-
used = (size - head) + tail;
412-
else
413-
used = tail - head;
414-
415-
/* make sure there is a space including extra dw for the header */
416-
if (unlikely(used + len + GUC_CTB_HDR_LEN >= size))
417-
return -ENOSPC;
416+
#endif
418417

419418
/*
420419
* dw0: CT header (including fence)
@@ -452,6 +451,11 @@ static int ct_write(struct intel_guc_ct *ct,
452451
*/
453452
write_barrier(ct);
454453

454+
/* update local copies */
455+
ctb->tail = tail;
456+
GEM_BUG_ON(ctb->space < len + GUC_CTB_HDR_LEN);
457+
ctb->space -= len + GUC_CTB_HDR_LEN;
458+
455459
/* now update descriptor */
456460
WRITE_ONCE(desc->tail, tail);
457461

@@ -469,7 +473,7 @@ static int ct_write(struct intel_guc_ct *ct,
469473
* @req: pointer to pending request
470474
* @status: placeholder for status
471475
*
472-
* For each sent request, Guc shall send bac CT response message.
476+
* For each sent request, GuC shall send back CT response message.
473477
* Our message handler will update status of tracked request once
474478
* response message with given fence is received. Wait here and
475479
* check for valid response status value.
@@ -525,24 +529,36 @@ static inline bool ct_deadlocked(struct intel_guc_ct *ct)
525529
return ret;
526530
}
527531

528-
static inline bool h2g_has_room(struct intel_guc_ct_buffer *ctb, u32 len_dw)
532+
static inline bool h2g_has_room(struct intel_guc_ct *ct, u32 len_dw)
529533
{
534+
struct intel_guc_ct_buffer *ctb = &ct->ctbs.send;
530535
struct guc_ct_buffer_desc *desc = ctb->desc;
531-
u32 head = READ_ONCE(desc->head);
536+
u32 head;
532537
u32 space;
533538

534-
space = CIRC_SPACE(desc->tail, head, ctb->size);
539+
if (ctb->space >= len_dw)
540+
return true;
541+
542+
head = READ_ONCE(desc->head);
543+
if (unlikely(head > ctb->size)) {
544+
CT_ERROR(ct, "Invalid head offset %u >= %u)\n",
545+
head, ctb->size);
546+
desc->status |= GUC_CTB_STATUS_OVERFLOW;
547+
ctb->broken = true;
548+
return false;
549+
}
550+
551+
space = CIRC_SPACE(ctb->tail, head, ctb->size);
552+
ctb->space = space;
535553

536554
return space >= len_dw;
537555
}
538556

539557
static int has_room_nb(struct intel_guc_ct *ct, u32 len_dw)
540558
{
541-
struct intel_guc_ct_buffer *ctb = &ct->ctbs.send;
542-
543559
lockdep_assert_held(&ct->ctbs.send.lock);
544560

545-
if (unlikely(!h2g_has_room(ctb, len_dw))) {
561+
if (unlikely(!h2g_has_room(ct, len_dw))) {
546562
if (ct->stall_time == KTIME_MAX)
547563
ct->stall_time = ktime_get();
548564

@@ -612,7 +628,7 @@ static int ct_send(struct intel_guc_ct *ct,
612628
*/
613629
retry:
614630
spin_lock_irqsave(&ctb->lock, flags);
615-
if (unlikely(!h2g_has_room(ctb, len + GUC_CTB_HDR_LEN))) {
631+
if (unlikely(!h2g_has_room(ct, len + GUC_CTB_HDR_LEN))) {
616632
if (ct->stall_time == KTIME_MAX)
617633
ct->stall_time = ktime_get();
618634
spin_unlock_irqrestore(&ctb->lock, flags);
@@ -732,8 +748,8 @@ static int ct_read(struct intel_guc_ct *ct, struct ct_incoming_msg **msg)
732748
{
733749
struct intel_guc_ct_buffer *ctb = &ct->ctbs.recv;
734750
struct guc_ct_buffer_desc *desc = ctb->desc;
735-
u32 head = desc->head;
736-
u32 tail = desc->tail;
751+
u32 head = ctb->head;
752+
u32 tail = READ_ONCE(desc->tail);
737753
u32 size = ctb->size;
738754
u32 *cmds = ctb->cmds;
739755
s32 available;
@@ -747,9 +763,19 @@ static int ct_read(struct intel_guc_ct *ct, struct ct_incoming_msg **msg)
747763
if (unlikely(desc->status))
748764
goto corrupted;
749765

750-
if (unlikely((tail | head) >= size)) {
751-
CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n",
752-
head, tail, size);
766+
GEM_BUG_ON(head > size);
767+
768+
#ifdef CONFIG_DRM_I915_DEBUG_GUC
769+
if (unlikely(head != READ_ONCE(desc->head))) {
770+
CT_ERROR(ct, "Head was modified %u != %u\n",
771+
desc->head, head);
772+
desc->status |= GUC_CTB_STATUS_MISMATCH;
773+
goto corrupted;
774+
}
775+
#endif
776+
if (unlikely(tail >= size)) {
777+
CT_ERROR(ct, "Invalid tail offset %u >= %u)\n",
778+
tail, size);
753779
desc->status |= GUC_CTB_STATUS_OVERFLOW;
754780
goto corrupted;
755781
}
@@ -802,6 +828,9 @@ static int ct_read(struct intel_guc_ct *ct, struct ct_incoming_msg **msg)
802828
}
803829
CT_DEBUG(ct, "received %*ph\n", 4 * len, (*msg)->msg);
804830

831+
/* update local copies */
832+
ctb->head = head;
833+
805834
/* now update descriptor */
806835
WRITE_ONCE(desc->head, head);
807836

drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,19 @@ struct intel_guc;
3333
* @desc: pointer to the buffer descriptor
3434
* @cmds: pointer to the commands buffer
3535
* @size: size of the commands buffer in dwords
36+
* @head: local shadow copy of head in dwords
37+
* @tail: local shadow copy of tail in dwords
38+
* @space: local shadow copy of space in dwords
3639
* @broken: flag to indicate if descriptor data is broken
3740
*/
3841
struct intel_guc_ct_buffer {
3942
spinlock_t lock;
4043
struct guc_ct_buffer_desc *desc;
4144
u32 *cmds;
4245
u32 size;
46+
u32 tail;
47+
u32 head;
48+
u32 space;
4349
bool broken;
4450
};
4551

0 commit comments

Comments
 (0)