@@ -130,6 +130,10 @@ static void guc_ct_buffer_desc_init(struct guc_ct_buffer_desc *desc)
130130static 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
539557static 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 */
613629retry :
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
0 commit comments