Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/guc: Extract GuC error capture lists

Upon the G2H Notify-Err-Capture event, parse through the
GuC Log Buffer (error-capture-subregion) and generate one or
more capture-nodes. A single node represents a single "engine-
instance-capture-dump" and contains at least 3 register lists:
global, engine-class and engine-instance. An internal link
list is maintained to store one or more nodes.

Because the link-list node generation happen before the call
to devcoredump, duplicate global and engine-class register
lists for each engine-instance register dump if we find
dependent-engine resets in a engine-capture-group.

To avoid dynamically allocate the output nodes during gt reset,
pre-allocate a fixed number of empty nodes up front (at the
time of ADS registration) that we can consume from or return to
an internal cached list of nodes.

Signed-off-by: Zhanjun Dong <zhanjun.dong@intel.com>
Reviewed-by: Alan Previn <alan.previn.teres.alexis@intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241004193428.3311145-5-zhanjun.dong@intel.com

authored by

Zhanjun Dong and committed by
Matt Roper
8bfc4963 84d15f42

+883 -20
+8
drivers/gpu/drm/xe/abi/guc_actions_abi.h
··· 176 176 #define GUC_LOG_CONTROL_VERBOSITY_MASK (0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT) 177 177 #define GUC_LOG_CONTROL_DEFAULT_LOGGING (1 << 8) 178 178 179 + enum xe_guc_state_capture_event_status { 180 + XE_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0, 181 + XE_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1, 182 + }; 183 + 184 + #define XE_GUC_STATE_CAPTURE_EVENT_STATUS_MASK 0x000000FF 185 + #define XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION_DATA_LEN 1 186 + 179 187 #define XE_GUC_TLB_INVAL_TYPE_SHIFT 0 180 188 #define XE_GUC_TLB_INVAL_MODE_SHIFT 8 181 189 /* Flush PPC or SMRO caches along with TLB invalidation request */
+55
drivers/gpu/drm/xe/abi/guc_log_abi.h
··· 17 17 18 18 #define GUC_LOG_BUFFER_TYPE_MAX 3 19 19 20 + /** 21 + * struct guc_log_buffer_state - GuC log buffer state 22 + * 23 + * Below state structure is used for coordination of retrieval of GuC firmware 24 + * logs. Separate state is maintained for each log buffer type. 25 + * read_ptr points to the location where Xe read last in log buffer and 26 + * is read only for GuC firmware. write_ptr is incremented by GuC with number 27 + * of bytes written for each log entry and is read only for Xe. 28 + * When any type of log buffer becomes half full, GuC sends a flush interrupt. 29 + * GuC firmware expects that while it is writing to 2nd half of the buffer, 30 + * first half would get consumed by Host and then get a flush completed 31 + * acknowledgment from Host, so that it does not end up doing any overwrite 32 + * causing loss of logs. So when buffer gets half filled & Xe has requested 33 + * for interrupt, GuC will set flush_to_file field, set the sampled_write_ptr 34 + * to the value of write_ptr and raise the interrupt. 35 + * On receiving the interrupt Xe should read the buffer, clear flush_to_file 36 + * field and also update read_ptr with the value of sample_write_ptr, before 37 + * sending an acknowledgment to GuC. marker & version fields are for internal 38 + * usage of GuC and opaque to Xe. buffer_full_cnt field is incremented every 39 + * time GuC detects the log buffer overflow. 40 + */ 41 + struct guc_log_buffer_state { 42 + /** @marker: buffer state start marker */ 43 + u32 marker[2]; 44 + /** @read_ptr: the last byte offset that was read by KMD previously */ 45 + u32 read_ptr; 46 + /** 47 + * @write_ptr: the next byte offset location that will be written by 48 + * GuC 49 + */ 50 + u32 write_ptr; 51 + /** @size: Log buffer size */ 52 + u32 size; 53 + /** 54 + * @sampled_write_ptr: Log buffer write pointer 55 + * This is written by GuC to the byte offset of the next free entry in 56 + * the buffer on log buffer half full or state capture notification 57 + */ 58 + u32 sampled_write_ptr; 59 + /** 60 + * @wrap_offset: wraparound offset 61 + * This is the byte offset of location 1 byte after last valid guc log 62 + * event entry written by Guc firmware before there was a wraparound. 63 + * This field is updated by guc firmware and should be used by Host 64 + * when copying buffer contents to file. 65 + */ 66 + u32 wrap_offset; 67 + /** @flags: Flush to file flag and buffer full count */ 68 + u32 flags; 69 + #define GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE GENMASK(0, 0) 70 + #define GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT GENMASK(4, 1) 71 + /** @version: The Guc-Log-Entry format version */ 72 + u32 version; 73 + } __packed; 74 + 20 75 #endif
+722 -3
drivers/gpu/drm/xe/xe_guc_capture.c
··· 10 10 11 11 #include "abi/guc_actions_abi.h" 12 12 #include "abi/guc_capture_abi.h" 13 + #include "abi/guc_log_abi.h" 13 14 #include "regs/xe_engine_regs.h" 14 15 #include "regs/xe_gt_regs.h" 15 16 #include "regs/xe_guc_regs.h" ··· 32 31 #include "xe_hw_engine_types.h" 33 32 #include "xe_macros.h" 34 33 #include "xe_map.h" 34 + 35 + /* 36 + * struct __guc_capture_bufstate 37 + * 38 + * Book-keeping structure used to track read and write pointers 39 + * as we extract error capture data from the GuC-log-buffer's 40 + * error-capture region as a stream of dwords. 41 + */ 42 + struct __guc_capture_bufstate { 43 + u32 size; 44 + u32 data_offset; 45 + u32 rd; 46 + u32 wr; 47 + }; 48 + 49 + /* 50 + * struct __guc_capture_parsed_output - extracted error capture node 51 + * 52 + * A single unit of extracted error-capture output data grouped together 53 + * at an engine-instance level. We keep these nodes in a linked list. 54 + * See cachelist and outlist below. 55 + */ 56 + struct __guc_capture_parsed_output { 57 + /* 58 + * A single set of 3 capture lists: a global-list 59 + * an engine-class-list and an engine-instance list. 60 + * outlist in __guc_capture_parsed_output will keep 61 + * a linked list of these nodes that will eventually 62 + * be detached from outlist and attached into to 63 + * xe_codedump in response to a context reset 64 + */ 65 + struct list_head link; 66 + bool is_partial; 67 + u32 eng_class; 68 + u32 eng_inst; 69 + u32 guc_id; 70 + u32 lrca; 71 + struct gcap_reg_list_info { 72 + u32 vfid; 73 + u32 num_regs; 74 + struct guc_mmio_reg *regs; 75 + } reginfo[GUC_STATE_CAPTURE_TYPE_MAX]; 76 + #define GCAP_PARSED_REGLIST_INDEX_GLOBAL BIT(GUC_STATE_CAPTURE_TYPE_GLOBAL) 77 + #define GCAP_PARSED_REGLIST_INDEX_ENGCLASS BIT(GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS) 78 + }; 35 79 36 80 /* 37 81 * Define all device tables of GuC error capture register lists ··· 267 221 [GUC_STATE_CAPTURE_TYPE_MAX] 268 222 [GUC_CAPTURE_LIST_CLASS_MAX]; 269 223 void *ads_null_cache; 224 + struct list_head cachelist; 225 + #define PREALLOC_NODES_MAX_COUNT (3 * GUC_MAX_ENGINE_CLASSES * GUC_MAX_INSTANCES_PER_CLASS) 226 + #define PREALLOC_NODES_DEFAULT_NUMREGS 64 227 + 228 + int max_mmio_per_node; 229 + struct list_head outlist; 270 230 }; 271 231 272 232 static const struct __guc_mmio_reg_descr_group * ··· 502 450 if (match) 503 451 num_regs += match->num_regs; 504 452 else 505 - /* Estimate steering register size for rcs/ccs */ 506 - if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) 453 + /* 454 + * If a caller wants the full register dump size but we have 455 + * not yet got the hw-config, which is before max_mmio_per_node 456 + * is initialized, then provide a worst-case number for 457 + * extlists based on max dss fuse bits, but only ever for 458 + * render/compute 459 + */ 460 + if (owner == GUC_CAPTURE_LIST_INDEX_PF && 461 + type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS && 462 + capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE && 463 + !guc->capture->max_mmio_per_node) 507 464 num_regs += guc_capture_get_steer_reg_num(guc_to_xe(guc)) * 508 465 XE_MAX_DSS_FUSE_BITS; 509 466 ··· 810 749 buffer_size, spare_size, capture_size); 811 750 } 812 751 752 + static void 753 + guc_capture_add_node_to_list(struct __guc_capture_parsed_output *node, 754 + struct list_head *list) 755 + { 756 + list_add_tail(&node->link, list); 757 + } 758 + 759 + static void 760 + guc_capture_add_node_to_outlist(struct xe_guc_state_capture *gc, 761 + struct __guc_capture_parsed_output *node) 762 + { 763 + guc_capture_add_node_to_list(node, &gc->outlist); 764 + } 765 + 766 + static void 767 + guc_capture_add_node_to_cachelist(struct xe_guc_state_capture *gc, 768 + struct __guc_capture_parsed_output *node) 769 + { 770 + guc_capture_add_node_to_list(node, &gc->cachelist); 771 + } 772 + 773 + static void 774 + guc_capture_init_node(struct xe_guc *guc, struct __guc_capture_parsed_output *node) 775 + { 776 + struct guc_mmio_reg *tmp[GUC_STATE_CAPTURE_TYPE_MAX]; 777 + int i; 778 + 779 + for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { 780 + tmp[i] = node->reginfo[i].regs; 781 + memset(tmp[i], 0, sizeof(struct guc_mmio_reg) * 782 + guc->capture->max_mmio_per_node); 783 + } 784 + memset(node, 0, sizeof(*node)); 785 + for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) 786 + node->reginfo[i].regs = tmp[i]; 787 + 788 + INIT_LIST_HEAD(&node->link); 789 + } 790 + 791 + /** 792 + * DOC: Init, G2H-event and reporting flows for GuC-error-capture 793 + * 794 + * KMD Init time flows: 795 + * -------------------- 796 + * --> alloc A: GuC input capture regs lists (registered to GuC via ADS). 797 + * xe_guc_ads acquires the register lists by calling 798 + * xe_guc_capture_getlistsize and xe_guc_capture_getlist 'n' times, 799 + * where n = 1 for global-reg-list + 800 + * num_engine_classes for class-reg-list + 801 + * num_engine_classes for instance-reg-list 802 + * (since all instances of the same engine-class type 803 + * have an identical engine-instance register-list). 804 + * ADS module also calls separately for PF vs VF. 805 + * 806 + * --> alloc B: GuC output capture buf (registered via guc_init_params(log_param)) 807 + * Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small) 808 + * Note2: 'x 3' to hold multiple capture groups 809 + * 810 + * GUC Runtime notify capture: 811 + * -------------------------- 812 + * --> G2H STATE_CAPTURE_NOTIFICATION 813 + * L--> xe_guc_capture_process 814 + * L--> Loop through B (head..tail) and for each engine instance's 815 + * err-state-captured register-list we find, we alloc 'C': 816 + * --> alloc C: A capture-output-node structure that includes misc capture info along 817 + * with 3 register list dumps (global, engine-class and engine-instance) 818 + * This node is created from a pre-allocated list of blank nodes in 819 + * guc->capture->cachelist and populated with the error-capture 820 + * data from GuC and then it's added into guc->capture->outlist linked 821 + * list. This list is used for matchup and printout by xe_devcoredump_read 822 + * and xe_hw_engine_snapshot_print, (when user invokes the devcoredump sysfs). 823 + * 824 + * GUC --> notify context reset: 825 + * ----------------------------- 826 + * --> guc_exec_queue_timedout_job 827 + * L--> xe_devcoredump 828 + * L--> devcoredump_snapshot 829 + * --> xe_hw_engine_snapshot_capture 830 + * 831 + * User Sysfs / Debugfs 832 + * -------------------- 833 + * --> xe_devcoredump_read-> 834 + * L--> xxx_snapshot_print 835 + * L--> xe_hw_engine_snapshot_print 836 + * Print register lists values saved at 837 + * guc->capture->outlist 838 + * 839 + */ 840 + 841 + static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf) 842 + { 843 + if (buf->wr >= buf->rd) 844 + return (buf->wr - buf->rd); 845 + return (buf->size - buf->rd) + buf->wr; 846 + } 847 + 848 + static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf) 849 + { 850 + if (buf->rd > buf->wr) 851 + return (buf->size - buf->rd); 852 + return (buf->wr - buf->rd); 853 + } 854 + 855 + /* 856 + * GuC's error-capture output is a ring buffer populated in a byte-stream fashion: 857 + * 858 + * The GuC Log buffer region for error-capture is managed like a ring buffer. 859 + * The GuC firmware dumps error capture logs into this ring in a byte-stream flow. 860 + * Additionally, as per the current and foreseeable future, all packed error- 861 + * capture output structures are dword aligned. 862 + * 863 + * That said, if the GuC firmware is in the midst of writing a structure that is larger 864 + * than one dword but the tail end of the err-capture buffer-region has lesser space left, 865 + * we would need to extract that structure one dword at a time straddled across the end, 866 + * onto the start of the ring. 867 + * 868 + * Below function, guc_capture_log_remove_bytes is a helper for that. All callers of this 869 + * function would typically do a straight-up memcpy from the ring contents and will only 870 + * call this helper if their structure-extraction is straddling across the end of the 871 + * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease 872 + * scalability for future expansion of output data types without requiring a redesign 873 + * of the flow controls. 874 + */ 875 + static int 876 + guc_capture_log_remove_bytes(struct xe_guc *guc, struct __guc_capture_bufstate *buf, 877 + void *out, int bytes_needed) 878 + { 879 + #define GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX 3 880 + 881 + int fill_size = 0, tries = GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX; 882 + int copy_size, avail; 883 + 884 + xe_assert(guc_to_xe(guc), bytes_needed % sizeof(u32) == 0); 885 + 886 + if (bytes_needed > guc_capture_buf_cnt(buf)) 887 + return -1; 888 + 889 + while (bytes_needed > 0 && tries--) { 890 + int misaligned; 891 + 892 + avail = guc_capture_buf_cnt_to_end(buf); 893 + misaligned = avail % sizeof(u32); 894 + /* wrap if at end */ 895 + if (!avail) { 896 + /* output stream clipped */ 897 + if (!buf->rd) 898 + return fill_size; 899 + buf->rd = 0; 900 + continue; 901 + } 902 + 903 + /* Only copy to u32 aligned data */ 904 + copy_size = avail < bytes_needed ? avail - misaligned : bytes_needed; 905 + xe_map_memcpy_from(guc_to_xe(guc), out + fill_size, &guc->log.bo->vmap, 906 + buf->data_offset + buf->rd, copy_size); 907 + buf->rd += copy_size; 908 + fill_size += copy_size; 909 + bytes_needed -= copy_size; 910 + 911 + if (misaligned) 912 + xe_gt_warn(guc_to_gt(guc), 913 + "Bytes extraction not dword aligned, clipping.\n"); 914 + } 915 + 916 + return fill_size; 917 + } 918 + 919 + static int 920 + guc_capture_log_get_group_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf, 921 + struct guc_state_capture_group_header_t *ghdr) 922 + { 923 + int fullsize = sizeof(struct guc_state_capture_group_header_t); 924 + 925 + if (guc_capture_log_remove_bytes(guc, buf, ghdr, fullsize) != fullsize) 926 + return -1; 927 + return 0; 928 + } 929 + 930 + static int 931 + guc_capture_log_get_data_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf, 932 + struct guc_state_capture_header_t *hdr) 933 + { 934 + int fullsize = sizeof(struct guc_state_capture_header_t); 935 + 936 + if (guc_capture_log_remove_bytes(guc, buf, hdr, fullsize) != fullsize) 937 + return -1; 938 + return 0; 939 + } 940 + 941 + static int 942 + guc_capture_log_get_register(struct xe_guc *guc, struct __guc_capture_bufstate *buf, 943 + struct guc_mmio_reg *reg) 944 + { 945 + int fullsize = sizeof(struct guc_mmio_reg); 946 + 947 + if (guc_capture_log_remove_bytes(guc, buf, reg, fullsize) != fullsize) 948 + return -1; 949 + return 0; 950 + } 951 + 952 + static struct __guc_capture_parsed_output * 953 + guc_capture_get_prealloc_node(struct xe_guc *guc) 954 + { 955 + struct __guc_capture_parsed_output *found = NULL; 956 + 957 + if (!list_empty(&guc->capture->cachelist)) { 958 + struct __guc_capture_parsed_output *n, *ntmp; 959 + 960 + /* get first avail node from the cache list */ 961 + list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link) { 962 + found = n; 963 + break; 964 + } 965 + } else { 966 + struct __guc_capture_parsed_output *n, *ntmp; 967 + 968 + /* traverse down and steal back the oldest node already allocated */ 969 + list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) { 970 + found = n; 971 + } 972 + } 973 + if (found) { 974 + list_del(&found->link); 975 + guc_capture_init_node(guc, found); 976 + } 977 + 978 + return found; 979 + } 980 + 981 + static struct __guc_capture_parsed_output * 982 + guc_capture_clone_node(struct xe_guc *guc, struct __guc_capture_parsed_output *original, 983 + u32 keep_reglist_mask) 984 + { 985 + struct __guc_capture_parsed_output *new; 986 + int i; 987 + 988 + new = guc_capture_get_prealloc_node(guc); 989 + if (!new) 990 + return NULL; 991 + if (!original) 992 + return new; 993 + 994 + new->is_partial = original->is_partial; 995 + 996 + /* copy reg-lists that we want to clone */ 997 + for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { 998 + if (keep_reglist_mask & BIT(i)) { 999 + XE_WARN_ON(original->reginfo[i].num_regs > 1000 + guc->capture->max_mmio_per_node); 1001 + 1002 + memcpy(new->reginfo[i].regs, original->reginfo[i].regs, 1003 + original->reginfo[i].num_regs * sizeof(struct guc_mmio_reg)); 1004 + 1005 + new->reginfo[i].num_regs = original->reginfo[i].num_regs; 1006 + new->reginfo[i].vfid = original->reginfo[i].vfid; 1007 + 1008 + if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS) { 1009 + new->eng_class = original->eng_class; 1010 + } else if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) { 1011 + new->eng_inst = original->eng_inst; 1012 + new->guc_id = original->guc_id; 1013 + new->lrca = original->lrca; 1014 + } 1015 + } 1016 + } 1017 + 1018 + return new; 1019 + } 1020 + 1021 + static int 1022 + guc_capture_extract_reglists(struct xe_guc *guc, struct __guc_capture_bufstate *buf) 1023 + { 1024 + struct xe_gt *gt = guc_to_gt(guc); 1025 + struct guc_state_capture_group_header_t ghdr = {0}; 1026 + struct guc_state_capture_header_t hdr = {0}; 1027 + struct __guc_capture_parsed_output *node = NULL; 1028 + struct guc_mmio_reg *regs = NULL; 1029 + int i, numlists, numregs, ret = 0; 1030 + enum guc_state_capture_type datatype; 1031 + struct guc_mmio_reg tmp; 1032 + bool is_partial = false; 1033 + 1034 + i = guc_capture_buf_cnt(buf); 1035 + if (!i) 1036 + return -ENODATA; 1037 + 1038 + if (i % sizeof(u32)) { 1039 + xe_gt_warn(gt, "Got mis-aligned register capture entries\n"); 1040 + ret = -EIO; 1041 + goto bailout; 1042 + } 1043 + 1044 + /* first get the capture group header */ 1045 + if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) { 1046 + ret = -EIO; 1047 + goto bailout; 1048 + } 1049 + /* 1050 + * we would typically expect a layout as below where n would be expected to be 1051 + * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine 1052 + * instances being reset together. 1053 + * ____________________________________________ 1054 + * | Capture Group | 1055 + * | ________________________________________ | 1056 + * | | Capture Group Header: | | 1057 + * | | - num_captures = 5 | | 1058 + * | |______________________________________| | 1059 + * | ________________________________________ | 1060 + * | | Capture1: | | 1061 + * | | Hdr: GLOBAL, numregs=a | | 1062 + * | | ____________________________________ | | 1063 + * | | | Reglist | | | 1064 + * | | | - reg1, reg2, ... rega | | | 1065 + * | | |__________________________________| | | 1066 + * | |______________________________________| | 1067 + * | ________________________________________ | 1068 + * | | Capture2: | | 1069 + * | | Hdr: CLASS=RENDER/COMPUTE, numregs=b| | 1070 + * | | ____________________________________ | | 1071 + * | | | Reglist | | | 1072 + * | | | - reg1, reg2, ... regb | | | 1073 + * | | |__________________________________| | | 1074 + * | |______________________________________| | 1075 + * | ________________________________________ | 1076 + * | | Capture3: | | 1077 + * | | Hdr: INSTANCE=RCS, numregs=c | | 1078 + * | | ____________________________________ | | 1079 + * | | | Reglist | | | 1080 + * | | | - reg1, reg2, ... regc | | | 1081 + * | | |__________________________________| | | 1082 + * | |______________________________________| | 1083 + * | ________________________________________ | 1084 + * | | Capture4: | | 1085 + * | | Hdr: CLASS=RENDER/COMPUTE, numregs=d| | 1086 + * | | ____________________________________ | | 1087 + * | | | Reglist | | | 1088 + * | | | - reg1, reg2, ... regd | | | 1089 + * | | |__________________________________| | | 1090 + * | |______________________________________| | 1091 + * | ________________________________________ | 1092 + * | | Capture5: | | 1093 + * | | Hdr: INSTANCE=CCS0, numregs=e | | 1094 + * | | ____________________________________ | | 1095 + * | | | Reglist | | | 1096 + * | | | - reg1, reg2, ... rege | | | 1097 + * | | |__________________________________| | | 1098 + * | |______________________________________| | 1099 + * |__________________________________________| 1100 + */ 1101 + is_partial = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_CAPTURE_GROUP_TYPE, ghdr.info); 1102 + numlists = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_NUM_CAPTURES, ghdr.info); 1103 + 1104 + while (numlists--) { 1105 + if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) { 1106 + ret = -EIO; 1107 + break; 1108 + } 1109 + 1110 + datatype = FIELD_GET(GUC_STATE_CAPTURE_HEADER_CAPTURE_TYPE, hdr.info); 1111 + if (datatype > GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) { 1112 + /* unknown capture type - skip over to next capture set */ 1113 + numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES, 1114 + hdr.num_mmio_entries); 1115 + while (numregs--) { 1116 + if (guc_capture_log_get_register(guc, buf, &tmp)) { 1117 + ret = -EIO; 1118 + break; 1119 + } 1120 + } 1121 + continue; 1122 + } else if (node) { 1123 + /* 1124 + * Based on the current capture type and what we have so far, 1125 + * decide if we should add the current node into the internal 1126 + * linked list for match-up when xe_devcoredump calls later 1127 + * (and alloc a blank node for the next set of reglists) 1128 + * or continue with the same node or clone the current node 1129 + * but only retain the global or class registers (such as the 1130 + * case of dependent engine resets). 1131 + */ 1132 + if (datatype == GUC_STATE_CAPTURE_TYPE_GLOBAL) { 1133 + guc_capture_add_node_to_outlist(guc->capture, node); 1134 + node = NULL; 1135 + } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS && 1136 + node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS].num_regs) { 1137 + /* Add to list, clone node and duplicate global list */ 1138 + guc_capture_add_node_to_outlist(guc->capture, node); 1139 + node = guc_capture_clone_node(guc, node, 1140 + GCAP_PARSED_REGLIST_INDEX_GLOBAL); 1141 + } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE && 1142 + node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE].num_regs) { 1143 + /* Add to list, clone node and duplicate global + class lists */ 1144 + guc_capture_add_node_to_outlist(guc->capture, node); 1145 + node = guc_capture_clone_node(guc, node, 1146 + (GCAP_PARSED_REGLIST_INDEX_GLOBAL | 1147 + GCAP_PARSED_REGLIST_INDEX_ENGCLASS)); 1148 + } 1149 + } 1150 + 1151 + if (!node) { 1152 + node = guc_capture_get_prealloc_node(guc); 1153 + if (!node) { 1154 + ret = -ENOMEM; 1155 + break; 1156 + } 1157 + if (datatype != GUC_STATE_CAPTURE_TYPE_GLOBAL) 1158 + xe_gt_dbg(gt, "Register capture missing global dump: %08x!\n", 1159 + datatype); 1160 + } 1161 + node->is_partial = is_partial; 1162 + node->reginfo[datatype].vfid = FIELD_GET(GUC_STATE_CAPTURE_HEADER_VFID, hdr.owner); 1163 + 1164 + switch (datatype) { 1165 + case GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE: 1166 + node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS, 1167 + hdr.info); 1168 + node->eng_inst = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_INSTANCE, 1169 + hdr.info); 1170 + node->lrca = hdr.lrca; 1171 + node->guc_id = hdr.guc_id; 1172 + break; 1173 + case GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS: 1174 + node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS, 1175 + hdr.info); 1176 + break; 1177 + default: 1178 + break; 1179 + } 1180 + 1181 + numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES, 1182 + hdr.num_mmio_entries); 1183 + if (numregs > guc->capture->max_mmio_per_node) { 1184 + xe_gt_dbg(gt, "Register capture list extraction clipped by prealloc!\n"); 1185 + numregs = guc->capture->max_mmio_per_node; 1186 + } 1187 + node->reginfo[datatype].num_regs = numregs; 1188 + regs = node->reginfo[datatype].regs; 1189 + i = 0; 1190 + while (numregs--) { 1191 + if (guc_capture_log_get_register(guc, buf, &regs[i++])) { 1192 + ret = -EIO; 1193 + break; 1194 + } 1195 + } 1196 + } 1197 + 1198 + bailout: 1199 + if (node) { 1200 + /* If we have data, add to linked list for match-up when xe_devcoredump calls */ 1201 + for (i = GUC_STATE_CAPTURE_TYPE_GLOBAL; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { 1202 + if (node->reginfo[i].regs) { 1203 + guc_capture_add_node_to_outlist(guc->capture, node); 1204 + node = NULL; 1205 + break; 1206 + } 1207 + } 1208 + if (node) /* else return it back to cache list */ 1209 + guc_capture_add_node_to_cachelist(guc->capture, node); 1210 + } 1211 + return ret; 1212 + } 1213 + 1214 + static int __guc_capture_flushlog_complete(struct xe_guc *guc) 1215 + { 1216 + u32 action[] = { 1217 + XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE, 1218 + GUC_LOG_BUFFER_CAPTURE 1219 + }; 1220 + 1221 + return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action)); 1222 + } 1223 + 1224 + static void __guc_capture_process_output(struct xe_guc *guc) 1225 + { 1226 + unsigned int buffer_size, read_offset, write_offset, full_count; 1227 + struct xe_uc *uc = container_of(guc, typeof(*uc), guc); 1228 + struct guc_log_buffer_state log_buf_state_local; 1229 + struct __guc_capture_bufstate buf; 1230 + bool new_overflow; 1231 + int ret, tmp; 1232 + u32 log_buf_state_offset; 1233 + u32 src_data_offset; 1234 + 1235 + log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_BUFFER_CAPTURE; 1236 + src_data_offset = xe_guc_get_log_buffer_offset(&guc->log, GUC_LOG_BUFFER_CAPTURE); 1237 + 1238 + /* 1239 + * Make a copy of the state structure, inside GuC log buffer 1240 + * (which is uncached mapped), on the stack to avoid reading 1241 + * from it multiple times. 1242 + */ 1243 + xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap, 1244 + log_buf_state_offset, sizeof(struct guc_log_buffer_state)); 1245 + 1246 + buffer_size = xe_guc_get_log_buffer_size(&guc->log, GUC_LOG_BUFFER_CAPTURE); 1247 + read_offset = log_buf_state_local.read_ptr; 1248 + write_offset = log_buf_state_local.sampled_write_ptr; 1249 + full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags); 1250 + 1251 + /* Bookkeeping stuff */ 1252 + tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags); 1253 + guc->log.stats[GUC_LOG_BUFFER_CAPTURE].flush += tmp; 1254 + new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_BUFFER_CAPTURE, 1255 + full_count); 1256 + 1257 + /* Now copy the actual logs. */ 1258 + if (unlikely(new_overflow)) { 1259 + /* copy the whole buffer in case of overflow */ 1260 + read_offset = 0; 1261 + write_offset = buffer_size; 1262 + } else if (unlikely((read_offset > buffer_size) || 1263 + (write_offset > buffer_size))) { 1264 + xe_gt_err(guc_to_gt(guc), 1265 + "Register capture buffer in invalid state: read = 0x%X, size = 0x%X!\n", 1266 + read_offset, buffer_size); 1267 + /* copy whole buffer as offsets are unreliable */ 1268 + read_offset = 0; 1269 + write_offset = buffer_size; 1270 + } 1271 + 1272 + buf.size = buffer_size; 1273 + buf.rd = read_offset; 1274 + buf.wr = write_offset; 1275 + buf.data_offset = src_data_offset; 1276 + 1277 + if (!xe_guc_read_stopped(guc)) { 1278 + do { 1279 + ret = guc_capture_extract_reglists(guc, &buf); 1280 + if (ret && ret != -ENODATA) 1281 + xe_gt_dbg(guc_to_gt(guc), "Capture extraction failed:%d\n", ret); 1282 + } while (ret >= 0); 1283 + } 1284 + 1285 + /* Update the state of log buffer err-cap state */ 1286 + xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap, 1287 + log_buf_state_offset + offsetof(struct guc_log_buffer_state, read_ptr), u32, 1288 + write_offset); 1289 + 1290 + /* 1291 + * Clear the flush_to_file from local first, the local was loaded by above 1292 + * xe_map_memcpy_from, then write out the "updated local" through 1293 + * xe_map_wr() 1294 + */ 1295 + log_buf_state_local.flags &= ~GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE; 1296 + xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap, 1297 + log_buf_state_offset + offsetof(struct guc_log_buffer_state, flags), u32, 1298 + log_buf_state_local.flags); 1299 + __guc_capture_flushlog_complete(guc); 1300 + } 1301 + 1302 + /* 1303 + * xe_guc_capture_process - Process GuC register captured data 1304 + * @guc: The GuC object 1305 + * 1306 + * When GuC captured data is ready, GuC will send message 1307 + * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be 1308 + * called to process the data comes with the message. 1309 + * 1310 + * Returns: None 1311 + */ 1312 + void xe_guc_capture_process(struct xe_guc *guc) 1313 + { 1314 + if (guc->capture) 1315 + __guc_capture_process_output(guc); 1316 + } 1317 + 1318 + static struct __guc_capture_parsed_output * 1319 + guc_capture_alloc_one_node(struct xe_guc *guc) 1320 + { 1321 + struct drm_device *drm = guc_to_drm(guc); 1322 + struct __guc_capture_parsed_output *new; 1323 + int i; 1324 + 1325 + new = drmm_kzalloc(drm, sizeof(*new), GFP_KERNEL); 1326 + if (!new) 1327 + return NULL; 1328 + 1329 + for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { 1330 + new->reginfo[i].regs = drmm_kzalloc(drm, guc->capture->max_mmio_per_node * 1331 + sizeof(struct guc_mmio_reg), GFP_KERNEL); 1332 + if (!new->reginfo[i].regs) { 1333 + while (i) 1334 + drmm_kfree(drm, new->reginfo[--i].regs); 1335 + drmm_kfree(drm, new); 1336 + return NULL; 1337 + } 1338 + } 1339 + guc_capture_init_node(guc, new); 1340 + 1341 + return new; 1342 + } 1343 + 1344 + static void 1345 + __guc_capture_create_prealloc_nodes(struct xe_guc *guc) 1346 + { 1347 + struct __guc_capture_parsed_output *node = NULL; 1348 + int i; 1349 + 1350 + for (i = 0; i < PREALLOC_NODES_MAX_COUNT; ++i) { 1351 + node = guc_capture_alloc_one_node(guc); 1352 + if (!node) { 1353 + xe_gt_warn(guc_to_gt(guc), "Register capture pre-alloc-cache failure\n"); 1354 + /* dont free the priors, use what we got and cleanup at shutdown */ 1355 + return; 1356 + } 1357 + guc_capture_add_node_to_cachelist(guc->capture, node); 1358 + } 1359 + } 1360 + 1361 + static int 1362 + guc_get_max_reglist_count(struct xe_guc *guc) 1363 + { 1364 + int i, j, k, tmp, maxregcount = 0; 1365 + 1366 + for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) { 1367 + for (j = 0; j < GUC_STATE_CAPTURE_TYPE_MAX; ++j) { 1368 + for (k = 0; k < GUC_CAPTURE_LIST_CLASS_MAX; ++k) { 1369 + const struct __guc_mmio_reg_descr_group *match; 1370 + 1371 + if (j == GUC_STATE_CAPTURE_TYPE_GLOBAL && k > 0) 1372 + continue; 1373 + 1374 + tmp = 0; 1375 + match = guc_capture_get_one_list(guc->capture->reglists, i, j, k); 1376 + if (match) 1377 + tmp = match->num_regs; 1378 + 1379 + match = guc_capture_get_one_list(guc->capture->extlists, i, j, k); 1380 + if (match) 1381 + tmp += match->num_regs; 1382 + 1383 + if (tmp > maxregcount) 1384 + maxregcount = tmp; 1385 + } 1386 + } 1387 + } 1388 + if (!maxregcount) 1389 + maxregcount = PREALLOC_NODES_DEFAULT_NUMREGS; 1390 + 1391 + return maxregcount; 1392 + } 1393 + 1394 + static void 1395 + guc_capture_create_prealloc_nodes(struct xe_guc *guc) 1396 + { 1397 + /* skip if we've already done the pre-alloc */ 1398 + if (guc->capture->max_mmio_per_node) 1399 + return; 1400 + 1401 + guc->capture->max_mmio_per_node = guc_get_max_reglist_count(guc); 1402 + __guc_capture_create_prealloc_nodes(guc); 1403 + } 1404 + 813 1405 /* 814 1406 * xe_guc_capture_steered_list_init - Init steering register list 815 1407 * @guc: The GuC object 816 1408 * 817 - * Init steering register list for GuC register capture 1409 + * Init steering register list for GuC register capture, create pre-alloc node 818 1410 */ 819 1411 void xe_guc_capture_steered_list_init(struct xe_guc *guc) 820 1412 { ··· 1479 765 */ 1480 766 guc_capture_alloc_steered_lists(guc); 1481 767 check_guc_capture_size(guc); 768 + guc_capture_create_prealloc_nodes(guc); 1482 769 } 1483 770 1484 771 /* ··· 1498 783 return -ENOMEM; 1499 784 1500 785 guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc)); 786 + 787 + INIT_LIST_HEAD(&guc->capture->outlist); 788 + INIT_LIST_HEAD(&guc->capture->cachelist); 789 + 1501 790 return 0; 1502 791 }
+1
drivers/gpu/drm/xe/xe_guc_capture.h
··· 37 37 return xe_guc_class_to_capture_class(xe_engine_class_to_guc_class(class)); 38 38 } 39 39 40 + void xe_guc_capture_process(struct xe_guc *guc); 40 41 int xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type, 41 42 enum guc_capture_list_class_type capture_class, void **outptr); 42 43 int xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
+2
drivers/gpu/drm/xe/xe_guc_ct.c
··· 1254 1254 /* Selftest only at the moment */ 1255 1255 break; 1256 1256 case XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION: 1257 + ret = xe_guc_error_capture_handler(guc, payload, adj_len); 1258 + break; 1257 1259 case XE_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE: 1258 1260 /* FIXME: Handle this */ 1259 1261 break;
+35
drivers/gpu/drm/xe/xe_guc_log.c
··· 337 337 338 338 return offset; 339 339 } 340 + 341 + /** 342 + * xe_guc_check_log_buf_overflow - Check if log buffer overflowed 343 + * @log: The log object. 344 + * @type: The log buffer type 345 + * @full_cnt: The count of buffer full 346 + * 347 + * This function will check count of buffer full against previous, mismatch 348 + * indicate overflowed. 349 + * Update the sampled_overflow counter, if the 4 bit counter overflowed, add 350 + * up 16 to correct the value. 351 + * 352 + * Return: True if overflowed. 353 + */ 354 + bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, enum guc_log_buffer_type type, 355 + unsigned int full_cnt) 356 + { 357 + unsigned int prev_full_cnt = log->stats[type].sampled_overflow; 358 + bool overflow = false; 359 + 360 + if (full_cnt != prev_full_cnt) { 361 + overflow = true; 362 + 363 + log->stats[type].overflow = full_cnt; 364 + log->stats[type].sampled_overflow += full_cnt - prev_full_cnt; 365 + 366 + if (full_cnt < prev_full_cnt) { 367 + /* buffer_full_cnt is a 4 bit counter */ 368 + log->stats[type].sampled_overflow += 16; 369 + } 370 + xe_gt_notice(log_to_gt(log), "log buffer overflow\n"); 371 + } 372 + 373 + return overflow; 374 + }
+3
drivers/gpu/drm/xe/xe_guc_log.h
··· 54 54 u32 xe_guc_log_section_size_capture(struct xe_guc_log *log); 55 55 u32 xe_guc_get_log_buffer_size(struct xe_guc_log *log, enum guc_log_buffer_type type); 56 56 u32 xe_guc_get_log_buffer_offset(struct xe_guc_log *log, enum guc_log_buffer_type type); 57 + bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, 58 + enum guc_log_buffer_type type, 59 + unsigned int full_cnt); 57 60 58 61 #endif
+7
drivers/gpu/drm/xe/xe_guc_log_types.h
··· 7 7 #define _XE_GUC_LOG_TYPES_H_ 8 8 9 9 #include <linux/types.h> 10 + #include "abi/guc_log_abi.h" 10 11 11 12 #include "xe_uc_fw_types.h" 12 13 ··· 46 45 u32 level; 47 46 /** @bo: XE BO for GuC log */ 48 47 struct xe_bo *bo; 48 + /** @stats: logging related stats */ 49 + struct { 50 + u32 sampled_overflow; 51 + u32 overflow; 52 + u32 flush; 53 + } stats[GUC_LOG_BUFFER_TYPE_MAX]; 49 54 }; 50 55 51 56 #endif
+48 -17
drivers/gpu/drm/xe/xe_guc_submit.c
··· 27 27 #include "xe_gt_clock.h" 28 28 #include "xe_gt_printk.h" 29 29 #include "xe_guc.h" 30 + #include "xe_guc_capture.h" 30 31 #include "xe_guc_ct.h" 31 32 #include "xe_guc_exec_queue_types.h" 32 33 #include "xe_guc_id_mgr.h" ··· 825 824 xe_sched_job_put(job); 826 825 } 827 826 828 - static int guc_read_stopped(struct xe_guc *guc) 827 + int xe_guc_read_stopped(struct xe_guc *guc) 829 828 { 830 829 return atomic_read(&guc->submission_state.stopped); 831 830 } ··· 847 846 set_min_preemption_timeout(guc, q); 848 847 smp_rmb(); 849 848 ret = wait_event_timeout(guc->ct.wq, !exec_queue_pending_enable(q) || 850 - guc_read_stopped(guc), HZ * 5); 849 + xe_guc_read_stopped(guc), HZ * 5); 851 850 if (!ret) { 852 851 struct xe_gpu_scheduler *sched = &q->guc->sched; 853 852 ··· 973 972 */ 974 973 ret = wait_event_timeout(guc->ct.wq, 975 974 !exec_queue_pending_disable(q) || 976 - guc_read_stopped(guc), HZ * 5); 975 + xe_guc_read_stopped(guc), HZ * 5); 977 976 if (!ret) { 978 977 drm_warn(&xe->drm, "Schedule disable failed to respond"); 979 978 xe_sched_submission_start(sched); ··· 1041 1040 1042 1041 ret = wait_event_timeout(guc->ct.wq, 1043 1042 !exec_queue_pending_enable(q) || 1044 - guc_read_stopped(guc), HZ * 5); 1045 - if (!ret || guc_read_stopped(guc)) { 1043 + xe_guc_read_stopped(guc), HZ * 5); 1044 + if (!ret || xe_guc_read_stopped(guc)) { 1046 1045 xe_gt_warn(guc_to_gt(guc), "Schedule enable failed to respond"); 1047 1046 set_exec_queue_banned(q); 1048 1047 xe_gt_reset_async(q->gt); ··· 1147 1146 */ 1148 1147 ret = wait_event_timeout(guc->ct.wq, 1149 1148 !exec_queue_pending_enable(q) || 1150 - guc_read_stopped(guc), HZ * 5); 1151 - if (!ret || guc_read_stopped(guc)) 1149 + xe_guc_read_stopped(guc), HZ * 5); 1150 + if (!ret || xe_guc_read_stopped(guc)) 1152 1151 goto trigger_reset; 1153 1152 1154 1153 /* ··· 1172 1171 smp_rmb(); 1173 1172 ret = wait_event_timeout(guc->ct.wq, 1174 1173 !exec_queue_pending_disable(q) || 1175 - guc_read_stopped(guc), HZ * 5); 1176 - if (!ret || guc_read_stopped(guc)) { 1174 + xe_guc_read_stopped(guc), HZ * 5); 1175 + if (!ret || xe_guc_read_stopped(guc)) { 1177 1176 trigger_reset: 1178 1177 if (!ret) 1179 1178 xe_gt_warn(guc_to_gt(guc), "Schedule disable failed to respond"); ··· 1362 1361 struct xe_device *xe = guc_to_xe(guc); 1363 1362 1364 1363 xe_assert(xe, exec_queue_suspended(q) || exec_queue_killed(q) || 1365 - guc_read_stopped(guc)); 1364 + xe_guc_read_stopped(guc)); 1366 1365 xe_assert(xe, q->guc->suspend_pending); 1367 1366 1368 1367 __suspend_fence_signal(q); ··· 1376 1375 if (guc_exec_queue_allowed_to_change_state(q) && !exec_queue_suspended(q) && 1377 1376 exec_queue_enabled(q)) { 1378 1377 wait_event(guc->ct.wq, q->guc->resume_time != RESUME_PENDING || 1379 - guc_read_stopped(guc)); 1378 + xe_guc_read_stopped(guc)); 1380 1379 1381 - if (!guc_read_stopped(guc)) { 1380 + if (!xe_guc_read_stopped(guc)) { 1382 1381 s64 since_resume_ms = 1383 1382 ktime_ms_delta(ktime_get(), 1384 1383 q->guc->resume_time); ··· 1503 1502 1504 1503 q->entity = &ge->entity; 1505 1504 1506 - if (guc_read_stopped(guc)) 1505 + if (xe_guc_read_stopped(guc)) 1507 1506 xe_sched_stop(sched); 1508 1507 1509 1508 mutex_unlock(&guc->submission_state.lock); ··· 1659 1658 ret = wait_event_interruptible_timeout(q->guc->suspend_wait, 1660 1659 !READ_ONCE(q->guc->suspend_pending) || 1661 1660 exec_queue_killed(q) || 1662 - guc_read_stopped(guc), 1661 + xe_guc_read_stopped(guc), 1663 1662 HZ * 5); 1664 1663 1665 1664 if (!ret) { ··· 1785 1784 void xe_guc_submit_reset_wait(struct xe_guc *guc) 1786 1785 { 1787 1786 wait_event(guc->ct.wq, xe_device_wedged(guc_to_xe(guc)) || 1788 - !guc_read_stopped(guc)); 1787 + !xe_guc_read_stopped(guc)); 1789 1788 } 1790 1789 1791 1790 void xe_guc_submit_stop(struct xe_guc *guc) ··· 1794 1793 unsigned long index; 1795 1794 struct xe_device *xe = guc_to_xe(guc); 1796 1795 1797 - xe_assert(xe, guc_read_stopped(guc) == 1); 1796 + xe_assert(xe, xe_guc_read_stopped(guc) == 1); 1798 1797 1799 1798 mutex_lock(&guc->submission_state.lock); 1800 1799 ··· 1833 1832 unsigned long index; 1834 1833 struct xe_device *xe = guc_to_xe(guc); 1835 1834 1836 - xe_assert(xe, guc_read_stopped(guc) == 1); 1835 + xe_assert(xe, xe_guc_read_stopped(guc) == 1); 1837 1836 1838 1837 mutex_lock(&guc->submission_state.lock); 1839 1838 atomic_dec(&guc->submission_state.stopped); ··· 2020 2019 set_exec_queue_reset(q); 2021 2020 if (!exec_queue_banned(q) && !exec_queue_check_timeout(q)) 2022 2021 xe_guc_exec_queue_trigger_cleanup(q); 2022 + 2023 + return 0; 2024 + } 2025 + 2026 + /* 2027 + * xe_guc_error_capture_handler - Handler of GuC captured message 2028 + * @guc: The GuC object 2029 + * @msg: Point to the message 2030 + * @len: The message length 2031 + * 2032 + * When GuC captured data is ready, GuC will send message 2033 + * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be 2034 + * called 1st to check status before process the data comes with the message. 2035 + * 2036 + * Returns: None 2037 + */ 2038 + int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len) 2039 + { 2040 + u32 status; 2041 + 2042 + if (unlikely(len != XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION_DATA_LEN)) { 2043 + xe_gt_dbg(guc_to_gt(guc), "Invalid length %u", len); 2044 + return -EPROTO; 2045 + } 2046 + 2047 + status = msg[0] & XE_GUC_STATE_CAPTURE_EVENT_STATUS_MASK; 2048 + if (status == XE_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE) 2049 + xe_gt_warn(guc_to_gt(guc), "G2H-Error capture no space"); 2050 + 2051 + xe_guc_capture_process(guc); 2023 2052 2024 2053 return 0; 2025 2054 }
+2
drivers/gpu/drm/xe/xe_guc_submit.h
··· 20 20 int xe_guc_submit_start(struct xe_guc *guc); 21 21 void xe_guc_submit_wedge(struct xe_guc *guc); 22 22 23 + int xe_guc_read_stopped(struct xe_guc *guc); 23 24 int xe_guc_sched_done_handler(struct xe_guc *guc, u32 *msg, u32 len); 24 25 int xe_guc_deregister_done_handler(struct xe_guc *guc, u32 *msg, u32 len); 25 26 int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len); 26 27 int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, 27 28 u32 len); 28 29 int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 len); 30 + int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len); 29 31 30 32 struct xe_guc_submit_exec_queue_snapshot * 31 33 xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q);