aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_10969_workaround.c
blob: f14f3be17e753c24f85b4830897b0138c5ecae30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 *
 * (C) COPYRIGHT 2013 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */



#include <kbase/src/common/mali_kbase.h>

/* This function is used to solve an HW issue with single iterator GPUs.
 * If a fragment job is soft-stopped on the edge of its bounding box, can happen that the
 * restart index is out of bounds and the rerun causes a tile range fault. If this happens
 * we try to clamp the restart index to a correct value and rerun the job.
 */
/* Mask of X and Y coordinates for the coordinates words in the descriptors*/
#define X_COORDINATE_MASK 0x00000FFF
#define Y_COORDINATE_MASK 0x0FFF0000
/* Max number of words needed from the fragment shader job descriptor */
#define JOB_HEADER_SIZE_IN_WORDS 10
#define JOB_HEADER_SIZE (JOB_HEADER_SIZE_IN_WORDS*sizeof(u32))

/* Word 0: Status Word */
#define JOB_DESC_STATUS_WORD 0
/* Word 1: Restart Index */
#define JOB_DESC_RESTART_INDEX_WORD 1
/* Word 2: Fault address low word */
#define JOB_DESC_FAULT_ADDR_LOW_WORD 2
/* Word 8: Minimum Tile Coordinates */
#define FRAG_JOB_DESC_MIN_TILE_COORD_WORD 8
/* Word 9: Maximum Tile Coordinates */
#define FRAG_JOB_DESC_MAX_TILE_COORD_WORD 9

int kbasep_10969_workaround_clamp_coordinates(kbase_jd_atom *katom)
{
	u32   clamped = 0;
	KBASE_DEBUG_PRINT_WARN(KBASE_JD,"Called TILE_RANGE_FAULT workaround clamping function. \n");
	if (katom->core_req & BASE_JD_REQ_FS){
		kbase_va_region * region = kbase_region_tracker_find_region_enclosing_address(katom->kctx, katom->jc );

		if (region){
			phys_addr_t * page_array = kbase_get_phy_pages(region);

			if (page_array){
				u64 page_index = (katom->jc >> PAGE_SHIFT) - region->start_pfn;
				u32 offset = katom->jc & (~PAGE_MASK);
				u32 * page_1 = NULL;
				u32 * page_2 = NULL;
				u32   job_header[JOB_HEADER_SIZE_IN_WORDS];
				void* dst = job_header;

				/* we need the first 10 words of the fragment shader job descriptor. We need to check
				 * that the offset + 10 words is less that the page size otherwise we need to load the next
				 * page. page_size_overflow will be equal to 0 in case the whole descriptor is within the page
				 * >0 otherwise.
				 */
				u32 copy_size = MIN(PAGE_SIZE - offset, JOB_HEADER_SIZE);

				page_1 = kmap_atomic(pfn_to_page(PFN_DOWN(page_array[page_index])));
				if (!page_1){
					KBASE_DEBUG_PRINT_WARN(KBASE_JD, "Restart Index clamping function not able to map page 1 \n");
					goto exit;
				}
				/* page_1 is a u32 pointer, offset is expressed in bytes */
				page_1 += offset>>2;
				kbase_sync_to_cpu(page_array[page_index] + offset, page_1, copy_size);
				memcpy(dst, page_1, copy_size);				

				/* The data needed overflows page the dimension, need to map the subsequent page */
				if (copy_size < JOB_HEADER_SIZE){
					page_2 = kmap_atomic(pfn_to_page(PFN_DOWN(page_array[page_index + 1])));
					if (!page_2){
						KBASE_DEBUG_PRINT_WARN(KBASE_JD, "Restart Index clamping function not able to map page 2 \n");
						kunmap_atomic(page_1);
						goto exit;
					}
					kbase_sync_to_cpu(page_array[page_index + 1], page_2, JOB_HEADER_SIZE - copy_size);
					memcpy(dst + copy_size, page_2, JOB_HEADER_SIZE - copy_size);
				}

				/* We managed to correctly map one or two pages (in case of overflow ) */
				{
					u32 minX,minY,maxX,maxY;
					u32 restartX,restartY;

					/* Get Bounding Box data and restart index from fault address low word*/
					minX     = job_header[FRAG_JOB_DESC_MIN_TILE_COORD_WORD] & X_COORDINATE_MASK;
					minY     = job_header[FRAG_JOB_DESC_MIN_TILE_COORD_WORD] & Y_COORDINATE_MASK;
					maxX     = job_header[FRAG_JOB_DESC_MAX_TILE_COORD_WORD] & X_COORDINATE_MASK;
					maxY     = job_header[FRAG_JOB_DESC_MAX_TILE_COORD_WORD] & Y_COORDINATE_MASK;
					restartX = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] & X_COORDINATE_MASK;
					restartY = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] & Y_COORDINATE_MASK;

					KBASE_DEBUG_PRINT_WARN(KBASE_JD, "Before Clamping: \n" \
							                 "Jobstatus: %08x  \n" \
							                 "restartIdx: %08x  \n" \
							                 "Fault_addr_low: %08x \n" \
							                 "minCoordsX: %08x minCoordsY: %08x \n" \
							                 "maxCoordsX: %08x maxCoordsY: %08x \n", 
							       job_header[JOB_DESC_STATUS_WORD],
							       job_header[JOB_DESC_RESTART_INDEX_WORD],
							       job_header[JOB_DESC_FAULT_ADDR_LOW_WORD],
							       minX,minY,
							       maxX,maxY );

					/* Set the restart index to the one which generated the fault*/
					job_header[JOB_DESC_RESTART_INDEX_WORD] = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD];

					if (restartX < minX){
						job_header[JOB_DESC_RESTART_INDEX_WORD] = (minX) | restartY;
						KBASE_DEBUG_PRINT_WARN(KBASE_JD,
								       "Clamping restart X index to minimum. %08x clamped to %08x \n",
								       restartX, minX );
						clamped =  1;
					}
					if (restartY < minY){
						job_header[JOB_DESC_RESTART_INDEX_WORD] = (minY) | restartX;
						KBASE_DEBUG_PRINT_WARN(KBASE_JD,
								       "Clamping restart Y index to minimum. %08x clamped to %08x \n",
									restartY, minY );
						clamped =  1;
					}
					if (restartX > maxX){
						job_header[JOB_DESC_RESTART_INDEX_WORD] = (maxX) | restartY;
						KBASE_DEBUG_PRINT_WARN(KBASE_JD,
								       "Clamping restart X index to maximum. %08x clamped to %08x \n",
									restartX, maxX );
						clamped =  1;
					}
					if (restartY > maxY){
						job_header[JOB_DESC_RESTART_INDEX_WORD] = (maxY) | restartX;
						KBASE_DEBUG_PRINT_WARN(KBASE_JD,"Clamping restart Y index to maximum. %08x clamped to %08x \n",
									restartY, maxY );
						clamped =  1;
					}

					if (clamped){
						/* Reset the fault address low word and set the job status to STOPPED */
						job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] = 0x0;
						job_header[JOB_DESC_STATUS_WORD] = BASE_JD_EVENT_STOPPED;
						KBASE_DEBUG_PRINT_WARN(KBASE_JD, "After Clamping: \n"                   \
							                         "Jobstatus: %08x  \n"                  \
							                         "restartIdx: %08x  \n"                 \
							                         "Fault_addr_low: %08x \n"              \
							                         "minCoordsX: %08x minCoordsY: %08x \n" \
							                         "maxCoordsX: %08x maxCoordsY: %08x \n", 
							               job_header[JOB_DESC_STATUS_WORD],
							               job_header[JOB_DESC_RESTART_INDEX_WORD],
							               job_header[JOB_DESC_FAULT_ADDR_LOW_WORD],
							               minX,minY,
							               maxX,maxY );

						/* Flush CPU cache to update memory for future GPU reads*/
						memcpy(page_1, dst, copy_size);
						kbase_sync_to_memory(page_array[page_index] + offset, page_1, copy_size);

						if (copy_size < JOB_HEADER_SIZE){
							 memcpy(page_2, dst + copy_size, JOB_HEADER_SIZE - copy_size);
							 kbase_sync_to_memory(page_array[page_index + 1], page_2, JOB_HEADER_SIZE - copy_size);
						}

					}
				}
				if (copy_size < JOB_HEADER_SIZE) 
					kunmap_atomic(page_2);

				kunmap_atomic(page_1);
			}
		}
	}
exit:
	return clamped;
}