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

gpu: host1x: Implement syncpoint wait using DMA fences

In anticipation of removal of the intr API, move host1x_syncpt_wait
to use DMA fences instead. As of this patch, this means that waits
have a 30 second maximum timeout because of the implicit timeout
we have with fences, but that will be lifted in a follow-up patch.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Mikko Perttunen and committed by
Thierry Reding
f0fb260a 1b5c09de

+20 -76
+20 -76
drivers/gpu/host1x/syncpt.c
··· 7 7 8 8 #include <linux/module.h> 9 9 #include <linux/device.h> 10 + #include <linux/dma-fence.h> 10 11 #include <linux/slab.h> 11 12 12 13 #include <trace/events/host1x.h> ··· 210 209 } 211 210 EXPORT_SYMBOL(host1x_syncpt_incr); 212 211 213 - /* 214 - * Updated sync point form hardware, and returns true if syncpoint is expired, 215 - * false if we may need to wait 216 - */ 217 - static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh) 218 - { 219 - host1x_hw_syncpt_load(sp->host, sp); 220 - 221 - return host1x_syncpt_is_expired(sp, thresh); 222 - } 223 - 224 212 /** 225 213 * host1x_syncpt_wait() - wait for a syncpoint to reach a given value 226 214 * @sp: host1x syncpoint ··· 220 230 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, 221 231 u32 *value) 222 232 { 223 - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 224 - void *ref; 225 - struct host1x_waitlist *waiter; 226 - int err = 0, check_count = 0; 233 + struct dma_fence *fence; 234 + long wait_err; 235 + 236 + host1x_hw_syncpt_load(sp->host, sp); 227 237 228 238 if (value) 229 239 *value = host1x_syncpt_load(sp); ··· 231 241 if (host1x_syncpt_is_expired(sp, thresh)) 232 242 return 0; 233 243 234 - if (!timeout) { 235 - err = -EAGAIN; 236 - goto done; 237 - } 238 - 239 - /* allocate a waiter */ 240 - waiter = kzalloc(sizeof(*waiter), GFP_KERNEL); 241 - if (!waiter) { 242 - err = -ENOMEM; 243 - goto done; 244 - } 245 - 246 - /* schedule a wakeup when the syncpoint value is reached */ 247 - err = host1x_intr_add_action(sp->host, sp, thresh, 248 - HOST1X_INTR_ACTION_WAKEUP_INTERRUPTIBLE, 249 - &wq, waiter, &ref); 250 - if (err) 251 - goto done; 252 - 253 - err = -EAGAIN; 254 - /* Caller-specified timeout may be impractically low */ 255 244 if (timeout < 0) 256 245 timeout = LONG_MAX; 246 + else if (timeout == 0) 247 + return -EAGAIN; 257 248 258 - /* wait for the syncpoint, or timeout, or signal */ 259 - while (timeout) { 260 - long check = min_t(long, SYNCPT_CHECK_PERIOD, timeout); 261 - int remain; 249 + fence = host1x_fence_create(sp, thresh); 250 + if (IS_ERR(fence)) 251 + return PTR_ERR(fence); 262 252 263 - remain = wait_event_interruptible_timeout(wq, 264 - syncpt_load_min_is_expired(sp, thresh), 265 - check); 266 - if (remain > 0 || host1x_syncpt_is_expired(sp, thresh)) { 267 - if (value) 268 - *value = host1x_syncpt_load(sp); 253 + wait_err = dma_fence_wait_timeout(fence, true, timeout); 254 + dma_fence_put(fence); 269 255 270 - err = 0; 256 + if (value) 257 + *value = host1x_syncpt_load(sp); 271 258 272 - break; 273 - } 274 - 275 - if (remain < 0) { 276 - err = remain; 277 - break; 278 - } 279 - 280 - timeout -= check; 281 - 282 - if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) { 283 - dev_warn(sp->host->dev, 284 - "%s: syncpoint id %u (%s) stuck waiting %d, timeout=%ld\n", 285 - current->comm, sp->id, sp->name, 286 - thresh, timeout); 287 - 288 - host1x_debug_dump_syncpts(sp->host); 289 - 290 - if (check_count == MAX_STUCK_CHECK_COUNT) 291 - host1x_debug_dump(sp->host); 292 - 293 - check_count++; 294 - } 295 - } 296 - 297 - host1x_intr_put_ref(sp->host, sp->id, ref, true); 298 - 299 - done: 300 - return err; 259 + if (wait_err == 0) 260 + return -EAGAIN; 261 + else if (wait_err < 0) 262 + return wait_err; 263 + else 264 + return 0; 301 265 } 302 266 EXPORT_SYMBOL(host1x_syncpt_wait); 303 267