diff options
| -rw-r--r-- | drivers/gpu/host1x/job.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index ef746f7afb88..f32ae69a68c7 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c | |||
| @@ -31,6 +31,8 @@ | |||
| 31 | #include "job.h" | 31 | #include "job.h" |
| 32 | #include "syncpt.h" | 32 | #include "syncpt.h" |
| 33 | 33 | ||
| 34 | #define HOST1X_WAIT_SYNCPT_OFFSET 0x8 | ||
| 35 | |||
| 34 | struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, | 36 | struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, |
| 35 | u32 num_cmdbufs, u32 num_relocs, | 37 | u32 num_cmdbufs, u32 num_relocs, |
| 36 | u32 num_waitchks) | 38 | u32 num_waitchks) |
| @@ -337,6 +339,17 @@ static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, | |||
| 337 | return true; | 339 | return true; |
| 338 | } | 340 | } |
| 339 | 341 | ||
| 342 | static bool check_wait(struct host1x_waitchk *wait, struct host1x_bo *cmdbuf, | ||
| 343 | unsigned int offset) | ||
| 344 | { | ||
| 345 | offset *= sizeof(u32); | ||
| 346 | |||
| 347 | if (wait->bo != cmdbuf || wait->offset != offset) | ||
| 348 | return false; | ||
| 349 | |||
| 350 | return true; | ||
| 351 | } | ||
| 352 | |||
| 340 | struct host1x_firewall { | 353 | struct host1x_firewall { |
| 341 | struct host1x_job *job; | 354 | struct host1x_job *job; |
| 342 | struct device *dev; | 355 | struct device *dev; |
| @@ -344,6 +357,9 @@ struct host1x_firewall { | |||
| 344 | unsigned int num_relocs; | 357 | unsigned int num_relocs; |
| 345 | struct host1x_reloc *reloc; | 358 | struct host1x_reloc *reloc; |
| 346 | 359 | ||
| 360 | unsigned int num_waitchks; | ||
| 361 | struct host1x_waitchk *waitchk; | ||
| 362 | |||
| 347 | struct host1x_bo *cmdbuf; | 363 | struct host1x_bo *cmdbuf; |
| 348 | unsigned int offset; | 364 | unsigned int offset; |
| 349 | 365 | ||
| @@ -370,6 +386,20 @@ static int check_register(struct host1x_firewall *fw, unsigned long offset) | |||
| 370 | fw->reloc++; | 386 | fw->reloc++; |
| 371 | } | 387 | } |
| 372 | 388 | ||
| 389 | if (offset == HOST1X_WAIT_SYNCPT_OFFSET) { | ||
| 390 | if (fw->class != HOST1X_CLASS_HOST1X) | ||
| 391 | return -EINVAL; | ||
| 392 | |||
| 393 | if (!fw->num_waitchks) | ||
| 394 | return -EINVAL; | ||
| 395 | |||
| 396 | if (!check_wait(fw->waitchk, fw->cmdbuf, fw->offset)) | ||
| 397 | return -EINVAL; | ||
| 398 | |||
| 399 | fw->num_waitchks--; | ||
| 400 | fw->waitchk++; | ||
| 401 | } | ||
| 402 | |||
| 373 | return 0; | 403 | return 0; |
| 374 | } | 404 | } |
| 375 | 405 | ||
| @@ -534,6 +564,8 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev) | |||
| 534 | fw.dev = dev; | 564 | fw.dev = dev; |
| 535 | fw.reloc = job->relocarray; | 565 | fw.reloc = job->relocarray; |
| 536 | fw.num_relocs = job->num_relocs; | 566 | fw.num_relocs = job->num_relocs; |
| 567 | fw.waitchk = job->waitchk; | ||
| 568 | fw.num_waitchks = job->num_waitchk; | ||
| 537 | fw.class = job->class; | 569 | fw.class = job->class; |
| 538 | 570 | ||
| 539 | for (i = 0; i < job->num_gathers; i++) { | 571 | for (i = 0; i < job->num_gathers; i++) { |
| @@ -572,8 +604,8 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev) | |||
| 572 | offset += g->words * sizeof(u32); | 604 | offset += g->words * sizeof(u32); |
| 573 | } | 605 | } |
| 574 | 606 | ||
| 575 | /* No relocs should remain at this point */ | 607 | /* No relocs and waitchks should remain at this point */ |
| 576 | if (fw.num_relocs) | 608 | if (fw.num_relocs || fw.num_waitchks) |
| 577 | return -EINVAL; | 609 | return -EINVAL; |
| 578 | 610 | ||
| 579 | return 0; | 611 | return 0; |
