diff options
author | Alex Waterman <alexw@nvidia.com> | 2015-06-05 17:04:12 -0400 |
---|---|---|
committer | Terje Bergstrom <tbergstrom@nvidia.com> | 2015-06-11 13:16:25 -0400 |
commit | 00721d4cb879c1d0a7b80375be2f7ce7c4e4a6d8 (patch) | |
tree | 913001120bd8d6f98378e099b32f092356540e47 /drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |
parent | 9e83f881b7fd796dd9319a6a88253e4166dbd830 (diff) |
gpu: nvgpu: WAR for bad GPFIFO entries from userspace
Userspace sometimes sends GPFIFO entries with a zero length. This
is a problem when the address of the pushbuffer of zero length is
larger than 32 bits. The high bits are interpreted as an opcode and
either triggers an operation that should not happen or is trated as
invalid.
Oddly, this WAR is only necessary on simulation.
Change-Id: I8be007c50f46d3e35c6a0e8512be88a8e68ee739
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: http://git-master/r/753379
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/755814
Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/channel_gk20a.c')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 52 |
1 files changed, 40 insertions, 12 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 8ad1dcca..2ba160dd 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -1790,23 +1790,51 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, | |||
1790 | start = c->gpfifo.put; | 1790 | start = c->gpfifo.put; |
1791 | end = start + num_entries; | 1791 | end = start + num_entries; |
1792 | 1792 | ||
1793 | if (end > c->gpfifo.entry_num) { | 1793 | /* |
1794 | int length0 = c->gpfifo.entry_num - start; | 1794 | * This WAR is in place for handling invalid simulation GPFIFO entries |
1795 | int length1 = num_entries - length0; | 1795 | * passed to us from userspace. This will be removed once these invalid |
1796 | * GPFIFO entries are handled in userspace. | ||
1797 | */ | ||
1798 | if (tegra_platform_is_linsim()) { | ||
1799 | int i; | ||
1800 | struct gpfifo *gpfifo_entries = c->gpfifo.mem.cpu_va; | ||
1796 | 1801 | ||
1797 | memcpy((struct gpfifo *)c->gpfifo.mem.cpu_va + start, gpfifo, | 1802 | for (i = 0; i < num_entries; i++) { |
1798 | length0 * sizeof(*gpfifo)); | 1803 | int index = (start + i) & (c->gpfifo.entry_num - 1); |
1799 | 1804 | ||
1800 | memcpy((struct gpfifo *)c->gpfifo.mem.cpu_va, gpfifo + length0, | 1805 | /* Copy the entry... */ |
1801 | length1 * sizeof(*gpfifo)); | 1806 | gpfifo_entries[index].entry0 = gpfifo[i].entry0; |
1807 | gpfifo_entries[index].entry1 = gpfifo[i].entry1; | ||
1802 | 1808 | ||
1803 | trace_write_pushbuffer_range(c, gpfifo, length0); | 1809 | /* |
1804 | trace_write_pushbuffer_range(c, gpfifo + length0, length1); | 1810 | * And here's the WAR: if the length is 0 clear the |
1811 | * opcode field (bottom 8 bits). | ||
1812 | */ | ||
1813 | if (!pbdma_gp_entry1_length_v(gpfifo[i].entry1)) | ||
1814 | gpfifo_entries[index].entry1 &= ~0xff; | ||
1815 | |||
1816 | trace_write_pushbuffer_range(c, gpfifo, num_entries); | ||
1817 | } | ||
1805 | } else { | 1818 | } else { |
1806 | memcpy((struct gpfifo *)c->gpfifo.mem.cpu_va + start, gpfifo, | 1819 | if (end > c->gpfifo.entry_num) { |
1807 | num_entries * sizeof(*gpfifo)); | 1820 | int length0 = c->gpfifo.entry_num - start; |
1821 | int length1 = num_entries - length0; | ||
1808 | 1822 | ||
1809 | trace_write_pushbuffer_range(c, gpfifo, num_entries); | 1823 | memcpy((struct gpfifo *)c->gpfifo.mem.cpu_va + start, |
1824 | gpfifo, length0 * sizeof(*gpfifo)); | ||
1825 | |||
1826 | memcpy((struct gpfifo *)c->gpfifo.mem.cpu_va, | ||
1827 | gpfifo + length0, length1 * sizeof(*gpfifo)); | ||
1828 | |||
1829 | trace_write_pushbuffer_range(c, gpfifo, length0); | ||
1830 | trace_write_pushbuffer_range(c, gpfifo + length0, | ||
1831 | length1); | ||
1832 | } else { | ||
1833 | memcpy((struct gpfifo *)c->gpfifo.mem.cpu_va + start, | ||
1834 | gpfifo, num_entries * sizeof(*gpfifo)); | ||
1835 | |||
1836 | trace_write_pushbuffer_range(c, gpfifo, num_entries); | ||
1837 | } | ||
1810 | } | 1838 | } |
1811 | c->gpfifo.put = (c->gpfifo.put + num_entries) & | 1839 | c->gpfifo.put = (c->gpfifo.put + num_entries) & |
1812 | (c->gpfifo.entry_num - 1); | 1840 | (c->gpfifo.entry_num - 1); |