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

drm/amdkfd: Fix kernel-queue wrapping bugs

Avoid intermediate negative numbers when doing calculations with a mix
of signed and unsigned variables where implicit conversions can lead
to unexpected results.

When kernel queue buffer wraps around to 0, we need to check that rptr
won't be overwritten by the new packet.

Signed-off-by: Yong Zhao <yong.zhao@amd.com>
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>

authored by

Yong Zhao and committed by
Oded Gabbay
cb1d9967 b22666fe

+15 -3
+15 -3
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
··· 210 210 uint32_t wptr, rptr; 211 211 unsigned int *queue_address; 212 212 213 + /* When rptr == wptr, the buffer is empty. 214 + * When rptr == wptr + 1, the buffer is full. 215 + * It is always rptr that advances to the position of wptr, rather than 216 + * the opposite. So we can only use up to queue_size_dwords - 1 dwords. 217 + */ 213 218 rptr = *kq->rptr_kernel; 214 219 wptr = *kq->wptr_kernel; 215 220 queue_address = (unsigned int *)kq->pq_kernel_addr; ··· 224 219 pr_debug("wptr: %d\n", wptr); 225 220 pr_debug("queue_address 0x%p\n", queue_address); 226 221 227 - available_size = (rptr - 1 - wptr + queue_size_dwords) % 222 + available_size = (rptr + queue_size_dwords - 1 - wptr) % 228 223 queue_size_dwords; 229 224 230 - if (packet_size_in_dwords >= queue_size_dwords || 231 - packet_size_in_dwords >= available_size) { 225 + if (packet_size_in_dwords > available_size) { 232 226 /* 233 227 * make sure calling functions know 234 228 * acquire_packet_buffer() failed ··· 237 233 } 238 234 239 235 if (wptr + packet_size_in_dwords >= queue_size_dwords) { 236 + /* make sure after rolling back to position 0, there is 237 + * still enough space. 238 + */ 239 + if (packet_size_in_dwords >= rptr) { 240 + *buffer_ptr = NULL; 241 + return -ENOMEM; 242 + } 243 + /* fill nops, roll back and start at position 0 */ 240 244 while (wptr > 0) { 241 245 queue_address[wptr] = kq->nop_packet; 242 246 wptr = (wptr + 1) % queue_size_dwords;