aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-06-19 21:07:03 -0400
committerDave Airlie <airlied@redhat.com>2017-06-19 21:07:03 -0400
commit4a525bad68b424d167042342db19d0c0e80e8b29 (patch)
tree95cb33d8752caaa9117644b0dde5e51845e78773
parent925344ccc91d7a7fd84cab2dece1c34bbd86fd8c (diff)
parent43240bbd871e2c8f89584d369278a3d18680d9ea (diff)
Merge tag 'drm/tegra/for-4.13-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Changes for v4.13-rc1 This starts off with the addition of more documentation for the host1x and DRM drivers and finishes with a slew of fixes and enhancements for the staging IOCTLs as a result of the awesome work done by Dmitry and Erik on the grate reverse-engineering effort. * tag 'drm/tegra/for-4.13-rc1' of git://anongit.freedesktop.org/tegra/linux: gpu: host1x: At first try a non-blocking allocation for the gather copy gpu: host1x: Refactor channel allocation code gpu: host1x: Remove unused host1x_cdma_stop() definition gpu: host1x: Remove unused 'struct host1x_cmdbuf' gpu: host1x: Check waits in the firewall gpu: host1x: Correct swapped arguments in the is_addr_reg() definition gpu: host1x: Forbid unrelated SETCLASS opcode in the firewall gpu: host1x: Forbid RESTART opcode in the firewall gpu: host1x: Forbid relocation address shifting in the firewall gpu: host1x: Do not leak BO's phys address to userspace gpu: host1x: Correct host1x_job_pin() error handling gpu: host1x: Initialize firewall class to the job's one drm/tegra: dc: Disable plane if it is invisible drm/tegra: dc: Apply clipping to the plane drm/tegra: dc: Avoid reset asserts on Tegra20 drm/tegra: Check syncpoint ID in the 'submit' IOCTL drm/tegra: Correct copying of waitchecks and disable them in the 'submit' IOCTL drm/tegra: Check for malformed offsets and sizes in the 'submit' IOCTL drm/tegra: Add driver documentation gpu: host1x: Flesh out kerneldoc
-rw-r--r--Documentation/gpu/index.rst1
-rw-r--r--Documentation/gpu/tegra.rst178
-rw-r--r--drivers/gpu/drm/tegra/dc.c92
-rw-r--r--drivers/gpu/drm/tegra/drm.c119
-rw-r--r--drivers/gpu/drm/tegra/drm.h1
-rw-r--r--drivers/gpu/drm/tegra/gem.c5
-rw-r--r--drivers/gpu/drm/tegra/gem.h5
-rw-r--r--drivers/gpu/drm/tegra/gr2d.c11
-rw-r--r--drivers/gpu/drm/tegra/gr3d.c4
-rw-r--r--drivers/gpu/drm/tegra/vic.c4
-rw-r--r--drivers/gpu/host1x/bus.c75
-rw-r--r--drivers/gpu/host1x/cdma.h1
-rw-r--r--drivers/gpu/host1x/channel.c147
-rw-r--r--drivers/gpu/host1x/channel.h21
-rw-r--r--drivers/gpu/host1x/debug.c47
-rw-r--r--drivers/gpu/host1x/dev.c7
-rw-r--r--drivers/gpu/host1x/dev.h6
-rw-r--r--drivers/gpu/host1x/hw/channel_hw.c4
-rw-r--r--drivers/gpu/host1x/job.c124
-rw-r--r--drivers/gpu/host1x/job.h14
-rw-r--r--drivers/gpu/host1x/syncpt.c81
-rw-r--r--include/linux/host1x.h38
22 files changed, 784 insertions, 201 deletions
diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst
index 037a39ac1807..35d673bf9b56 100644
--- a/Documentation/gpu/index.rst
+++ b/Documentation/gpu/index.rst
@@ -13,6 +13,7 @@ Linux GPU Driver Developer's Guide
13 i915 13 i915
14 meson 14 meson
15 pl111 15 pl111
16 tegra
16 tinydrm 17 tinydrm
17 vc4 18 vc4
18 vga-switcheroo 19 vga-switcheroo
diff --git a/Documentation/gpu/tegra.rst b/Documentation/gpu/tegra.rst
new file mode 100644
index 000000000000..d2ed8938ca43
--- /dev/null
+++ b/Documentation/gpu/tegra.rst
@@ -0,0 +1,178 @@
1===============================================
2 drm/tegra NVIDIA Tegra GPU and display driver
3===============================================
4
5NVIDIA Tegra SoCs support a set of display, graphics and video functions via
6the host1x controller. host1x supplies command streams, gathered from a push
7buffer provided directly by the CPU, to its clients via channels. Software,
8or blocks amongst themselves, can use syncpoints for synchronization.
9
10Up until, but not including, Tegra124 (aka Tegra K1) the drm/tegra driver
11supports the built-in GPU, comprised of the gr2d and gr3d engines. Starting
12with Tegra124 the GPU is based on the NVIDIA desktop GPU architecture and
13supported by the drm/nouveau driver.
14
15The drm/tegra driver supports NVIDIA Tegra SoC generations since Tegra20. It
16has three parts:
17
18 - A host1x driver that provides infrastructure and access to the host1x
19 services.
20
21 - A KMS driver that supports the display controllers as well as a number of
22 outputs, such as RGB, HDMI, DSI, and DisplayPort.
23
24 - A set of custom userspace IOCTLs that can be used to submit jobs to the
25 GPU and video engines via host1x.
26
27Driver Infrastructure
28=====================
29
30The various host1x clients need to be bound together into a logical device in
31order to expose their functionality to users. The infrastructure that supports
32this is implemented in the host1x driver. When a driver is registered with the
33infrastructure it provides a list of compatible strings specifying the devices
34that it needs. The infrastructure creates a logical device and scan the device
35tree for matching device nodes, adding the required clients to a list. Drivers
36for individual clients register with the infrastructure as well and are added
37to the logical host1x device.
38
39Once all clients are available, the infrastructure will initialize the logical
40device using a driver-provided function which will set up the bits specific to
41the subsystem and in turn initialize each of its clients.
42
43Similarly, when one of the clients is unregistered, the infrastructure will
44destroy the logical device by calling back into the driver, which ensures that
45the subsystem specific bits are torn down and the clients destroyed in turn.
46
47Host1x Infrastructure Reference
48-------------------------------
49
50.. kernel-doc:: include/linux/host1x.h
51
52.. kernel-doc:: drivers/gpu/host1x/bus.c
53 :export:
54
55Host1x Syncpoint Reference
56--------------------------
57
58.. kernel-doc:: drivers/gpu/host1x/syncpt.c
59 :export:
60
61KMS driver
62==========
63
64The display hardware has remained mostly backwards compatible over the various
65Tegra SoC generations, up until Tegra186 which introduces several changes that
66make it difficult to support with a parameterized driver.
67
68Display Controllers
69-------------------
70
71Tegra SoCs have two display controllers, each of which can be associated with
72zero or more outputs. Outputs can also share a single display controller, but
73only if they run with compatible display timings. Two display controllers can
74also share a single framebuffer, allowing cloned configurations even if modes
75on two outputs don't match. A display controller is modelled as a CRTC in KMS
76terms.
77
78On Tegra186, the number of display controllers has been increased to three. A
79display controller can no longer drive all of the outputs. While two of these
80controllers can drive both DSI outputs and both SOR outputs, the third cannot
81drive any DSI.
82
83Windows
84~~~~~~~
85
86A display controller controls a set of windows that can be used to composite
87multiple buffers onto the screen. While it is possible to assign arbitrary Z
88ordering to individual windows (by programming the corresponding blending
89registers), this is currently not supported by the driver. Instead, it will
90assume a fixed Z ordering of the windows (window A is the root window, that
91is, the lowest, while windows B and C are overlaid on top of window A). The
92overlay windows support multiple pixel formats and can automatically convert
93from YUV to RGB at scanout time. This makes them useful for displaying video
94content. In KMS, each window is modelled as a plane. Each display controller
95has a hardware cursor that is exposed as a cursor plane.
96
97Outputs
98-------
99
100The type and number of supported outputs varies between Tegra SoC generations.
101All generations support at least HDMI. While earlier generations supported the
102very simple RGB interfaces (one per display controller), recent generations no
103longer do and instead provide standard interfaces such as DSI and eDP/DP.
104
105Outputs are modelled as a composite encoder/connector pair.
106
107RGB/LVDS
108~~~~~~~~
109
110This interface is no longer available since Tegra124. It has been replaced by
111the more standard DSI and eDP interfaces.
112
113HDMI
114~~~~
115
116HDMI is supported on all Tegra SoCs. Starting with Tegra210, HDMI is provided
117by the versatile SOR output, which supports eDP, DP and HDMI. The SOR is able
118to support HDMI 2.0, though support for this is currently not merged.
119
120DSI
121~~~
122
123Although Tegra has supported DSI since Tegra30, the controller has changed in
124several ways in Tegra114. Since none of the publicly available development
125boards prior to Dalmore (Tegra114) have made use of DSI, only Tegra114 and
126later are supported by the drm/tegra driver.
127
128eDP/DP
129~~~~~~
130
131eDP was first introduced in Tegra124 where it was used to drive the display
132panel for notebook form factors. Tegra210 added support for full DisplayPort
133support, though this is currently not implemented in the drm/tegra driver.
134
135Userspace Interface
136===================
137
138The userspace interface provided by drm/tegra allows applications to create
139GEM buffers, access and control syncpoints as well as submit command streams
140to host1x.
141
142GEM Buffers
143-----------
144
145The ``DRM_IOCTL_TEGRA_GEM_CREATE`` IOCTL is used to create a GEM buffer object
146with Tegra-specific flags. This is useful for buffers that should be tiled, or
147that are to be scanned out upside down (useful for 3D content).
148
149After a GEM buffer object has been created, its memory can be mapped by an
150application using the mmap offset returned by the ``DRM_IOCTL_TEGRA_GEM_MMAP``
151IOCTL.
152
153Syncpoints
154----------
155
156The current value of a syncpoint can be obtained by executing the
157``DRM_IOCTL_TEGRA_SYNCPT_READ`` IOCTL. Incrementing the syncpoint is achieved
158using the ``DRM_IOCTL_TEGRA_SYNCPT_INCR`` IOCTL.
159
160Userspace can also request blocking on a syncpoint. To do so, it needs to
161execute the ``DRM_IOCTL_TEGRA_SYNCPT_WAIT`` IOCTL, specifying the value of
162the syncpoint to wait for. The kernel will release the application when the
163syncpoint reaches that value or after a specified timeout.
164
165Command Stream Submission
166-------------------------
167
168Before an application can submit command streams to host1x it needs to open a
169channel to an engine using the ``DRM_IOCTL_TEGRA_OPEN_CHANNEL`` IOCTL. Client
170IDs are used to identify the target of the channel. When a channel is no
171longer needed, it can be closed using the ``DRM_IOCTL_TEGRA_CLOSE_CHANNEL``
172IOCTL. To retrieve the syncpoint associated with a channel, an application
173can use the ``DRM_IOCTL_TEGRA_GET_SYNCPT``.
174
175After opening a channel, submitting command streams is easy. The application
176writes commands into the memory backing a GEM buffer object and passes these
177to the ``DRM_IOCTL_TEGRA_SUBMIT`` IOCTL along with various other parameters,
178such as the syncpoints or relocations used in the job submission.
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 95b373f739f2..c875f11786b9 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -30,6 +30,7 @@ struct tegra_dc_soc_info {
30 bool supports_block_linear; 30 bool supports_block_linear;
31 unsigned int pitch_align; 31 unsigned int pitch_align;
32 bool has_powergate; 32 bool has_powergate;
33 bool broken_reset;
33}; 34};
34 35
35struct tegra_plane { 36struct tegra_plane {
@@ -485,12 +486,25 @@ static int tegra_plane_state_add(struct tegra_plane *plane,
485{ 486{
486 struct drm_crtc_state *crtc_state; 487 struct drm_crtc_state *crtc_state;
487 struct tegra_dc_state *tegra; 488 struct tegra_dc_state *tegra;
489 struct drm_rect clip;
490 int err;
488 491
489 /* Propagate errors from allocation or locking failures. */ 492 /* Propagate errors from allocation or locking failures. */
490 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 493 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
491 if (IS_ERR(crtc_state)) 494 if (IS_ERR(crtc_state))
492 return PTR_ERR(crtc_state); 495 return PTR_ERR(crtc_state);
493 496
497 clip.x1 = 0;
498 clip.y1 = 0;
499 clip.x2 = crtc_state->mode.hdisplay;
500 clip.y2 = crtc_state->mode.vdisplay;
501
502 /* Check plane state for visibility and calculate clipping bounds */
503 err = drm_plane_helper_check_state(state, &clip, 0, INT_MAX,
504 true, true);
505 if (err < 0)
506 return err;
507
494 tegra = to_dc_state(crtc_state); 508 tegra = to_dc_state(crtc_state);
495 509
496 tegra->planes |= WIN_A_ACT_REQ << plane->index; 510 tegra->planes |= WIN_A_ACT_REQ << plane->index;
@@ -545,6 +559,23 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
545 return 0; 559 return 0;
546} 560}
547 561
562static void tegra_dc_disable_window(struct tegra_dc *dc, int index)
563{
564 unsigned long flags;
565 u32 value;
566
567 spin_lock_irqsave(&dc->lock, flags);
568
569 value = WINDOW_A_SELECT << index;
570 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
571
572 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
573 value &= ~WIN_ENABLE;
574 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
575
576 spin_unlock_irqrestore(&dc->lock, flags);
577}
578
548static void tegra_plane_atomic_update(struct drm_plane *plane, 579static void tegra_plane_atomic_update(struct drm_plane *plane,
549 struct drm_plane_state *old_state) 580 struct drm_plane_state *old_state)
550{ 581{
@@ -559,15 +590,18 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
559 if (!plane->state->crtc || !plane->state->fb) 590 if (!plane->state->crtc || !plane->state->fb)
560 return; 591 return;
561 592
593 if (!plane->state->visible)
594 return tegra_dc_disable_window(dc, p->index);
595
562 memset(&window, 0, sizeof(window)); 596 memset(&window, 0, sizeof(window));
563 window.src.x = plane->state->src_x >> 16; 597 window.src.x = plane->state->src.x1 >> 16;
564 window.src.y = plane->state->src_y >> 16; 598 window.src.y = plane->state->src.y1 >> 16;
565 window.src.w = plane->state->src_w >> 16; 599 window.src.w = drm_rect_width(&plane->state->src) >> 16;
566 window.src.h = plane->state->src_h >> 16; 600 window.src.h = drm_rect_height(&plane->state->src) >> 16;
567 window.dst.x = plane->state->crtc_x; 601 window.dst.x = plane->state->dst.x1;
568 window.dst.y = plane->state->crtc_y; 602 window.dst.y = plane->state->dst.y1;
569 window.dst.w = plane->state->crtc_w; 603 window.dst.w = drm_rect_width(&plane->state->dst);
570 window.dst.h = plane->state->crtc_h; 604 window.dst.h = drm_rect_height(&plane->state->dst);
571 window.bits_per_pixel = fb->format->cpp[0] * 8; 605 window.bits_per_pixel = fb->format->cpp[0] * 8;
572 window.bottom_up = tegra_fb_is_bottom_up(fb); 606 window.bottom_up = tegra_fb_is_bottom_up(fb);
573 607
@@ -598,8 +632,6 @@ static void tegra_plane_atomic_disable(struct drm_plane *plane,
598{ 632{
599 struct tegra_plane *p = to_tegra_plane(plane); 633 struct tegra_plane *p = to_tegra_plane(plane);
600 struct tegra_dc *dc; 634 struct tegra_dc *dc;
601 unsigned long flags;
602 u32 value;
603 635
604 /* rien ne va plus */ 636 /* rien ne va plus */
605 if (!old_state || !old_state->crtc) 637 if (!old_state || !old_state->crtc)
@@ -607,16 +639,7 @@ static void tegra_plane_atomic_disable(struct drm_plane *plane,
607 639
608 dc = to_tegra_dc(old_state->crtc); 640 dc = to_tegra_dc(old_state->crtc);
609 641
610 spin_lock_irqsave(&dc->lock, flags); 642 tegra_dc_disable_window(dc, p->index);
611
612 value = WINDOW_A_SELECT << p->index;
613 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
614
615 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
616 value &= ~WIN_ENABLE;
617 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
618
619 spin_unlock_irqrestore(&dc->lock, flags);
620} 643}
621 644
622static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = { 645static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
@@ -1856,6 +1879,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
1856 .supports_block_linear = false, 1879 .supports_block_linear = false,
1857 .pitch_align = 8, 1880 .pitch_align = 8,
1858 .has_powergate = false, 1881 .has_powergate = false,
1882 .broken_reset = true,
1859}; 1883};
1860 1884
1861static const struct tegra_dc_soc_info tegra30_dc_soc_info = { 1885static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
@@ -1865,6 +1889,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
1865 .supports_block_linear = false, 1889 .supports_block_linear = false,
1866 .pitch_align = 8, 1890 .pitch_align = 8,
1867 .has_powergate = false, 1891 .has_powergate = false,
1892 .broken_reset = false,
1868}; 1893};
1869 1894
1870static const struct tegra_dc_soc_info tegra114_dc_soc_info = { 1895static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
@@ -1874,6 +1899,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
1874 .supports_block_linear = false, 1899 .supports_block_linear = false,
1875 .pitch_align = 64, 1900 .pitch_align = 64,
1876 .has_powergate = true, 1901 .has_powergate = true,
1902 .broken_reset = false,
1877}; 1903};
1878 1904
1879static const struct tegra_dc_soc_info tegra124_dc_soc_info = { 1905static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
@@ -1883,6 +1909,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
1883 .supports_block_linear = true, 1909 .supports_block_linear = true,
1884 .pitch_align = 64, 1910 .pitch_align = 64,
1885 .has_powergate = true, 1911 .has_powergate = true,
1912 .broken_reset = false,
1886}; 1913};
1887 1914
1888static const struct tegra_dc_soc_info tegra210_dc_soc_info = { 1915static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
@@ -1892,6 +1919,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
1892 .supports_block_linear = true, 1919 .supports_block_linear = true,
1893 .pitch_align = 64, 1920 .pitch_align = 64,
1894 .has_powergate = true, 1921 .has_powergate = true,
1922 .broken_reset = false,
1895}; 1923};
1896 1924
1897static const struct of_device_id tegra_dc_of_match[] = { 1925static const struct of_device_id tegra_dc_of_match[] = {
@@ -1989,7 +2017,8 @@ static int tegra_dc_probe(struct platform_device *pdev)
1989 return PTR_ERR(dc->rst); 2017 return PTR_ERR(dc->rst);
1990 } 2018 }
1991 2019
1992 reset_control_assert(dc->rst); 2020 if (!dc->soc->broken_reset)
2021 reset_control_assert(dc->rst);
1993 2022
1994 if (dc->soc->has_powergate) { 2023 if (dc->soc->has_powergate) {
1995 if (dc->pipe == 0) 2024 if (dc->pipe == 0)
@@ -2063,10 +2092,12 @@ static int tegra_dc_suspend(struct device *dev)
2063 struct tegra_dc *dc = dev_get_drvdata(dev); 2092 struct tegra_dc *dc = dev_get_drvdata(dev);
2064 int err; 2093 int err;
2065 2094
2066 err = reset_control_assert(dc->rst); 2095 if (!dc->soc->broken_reset) {
2067 if (err < 0) { 2096 err = reset_control_assert(dc->rst);
2068 dev_err(dev, "failed to assert reset: %d\n", err); 2097 if (err < 0) {
2069 return err; 2098 dev_err(dev, "failed to assert reset: %d\n", err);
2099 return err;
2100 }
2070 } 2101 }
2071 2102
2072 if (dc->soc->has_powergate) 2103 if (dc->soc->has_powergate)
@@ -2096,10 +2127,13 @@ static int tegra_dc_resume(struct device *dev)
2096 return err; 2127 return err;
2097 } 2128 }
2098 2129
2099 err = reset_control_deassert(dc->rst); 2130 if (!dc->soc->broken_reset) {
2100 if (err < 0) { 2131 err = reset_control_deassert(dc->rst);
2101 dev_err(dev, "failed to deassert reset: %d\n", err); 2132 if (err < 0) {
2102 return err; 2133 dev_err(dev,
2134 "failed to deassert reset: %d\n", err);
2135 return err;
2136 }
2103 } 2137 }
2104 } 2138 }
2105 2139
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 51c48a8e00ec..ac15cc65af36 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -26,6 +26,7 @@
26#define DRIVER_PATCHLEVEL 0 26#define DRIVER_PATCHLEVEL 0
27 27
28#define CARVEOUT_SZ SZ_64M 28#define CARVEOUT_SZ SZ_64M
29#define CDMA_GATHER_FETCHES_MAX_NB 16383
29 30
30struct tegra_drm_file { 31struct tegra_drm_file {
31 struct idr contexts; 32 struct idr contexts;
@@ -348,6 +349,36 @@ static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
348 return 0; 349 return 0;
349} 350}
350 351
352static int host1x_waitchk_copy_from_user(struct host1x_waitchk *dest,
353 struct drm_tegra_waitchk __user *src,
354 struct drm_file *file)
355{
356 u32 cmdbuf;
357 int err;
358
359 err = get_user(cmdbuf, &src->handle);
360 if (err < 0)
361 return err;
362
363 err = get_user(dest->offset, &src->offset);
364 if (err < 0)
365 return err;
366
367 err = get_user(dest->syncpt_id, &src->syncpt);
368 if (err < 0)
369 return err;
370
371 err = get_user(dest->thresh, &src->thresh);
372 if (err < 0)
373 return err;
374
375 dest->bo = host1x_bo_lookup(file, cmdbuf);
376 if (!dest->bo)
377 return -ENOENT;
378
379 return 0;
380}
381
351int tegra_drm_submit(struct tegra_drm_context *context, 382int tegra_drm_submit(struct tegra_drm_context *context,
352 struct drm_tegra_submit *args, struct drm_device *drm, 383 struct drm_tegra_submit *args, struct drm_device *drm,
353 struct drm_file *file) 384 struct drm_file *file)
@@ -362,6 +393,8 @@ int tegra_drm_submit(struct tegra_drm_context *context,
362 struct drm_tegra_waitchk __user *waitchks = 393 struct drm_tegra_waitchk __user *waitchks =
363 (void __user *)(uintptr_t)args->waitchks; 394 (void __user *)(uintptr_t)args->waitchks;
364 struct drm_tegra_syncpt syncpt; 395 struct drm_tegra_syncpt syncpt;
396 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
397 struct host1x_syncpt *sp;
365 struct host1x_job *job; 398 struct host1x_job *job;
366 int err; 399 int err;
367 400
@@ -369,6 +402,10 @@ int tegra_drm_submit(struct tegra_drm_context *context,
369 if (args->num_syncpts != 1) 402 if (args->num_syncpts != 1)
370 return -EINVAL; 403 return -EINVAL;
371 404
405 /* We don't yet support waitchks */
406 if (args->num_waitchks != 0)
407 return -EINVAL;
408
372 job = host1x_job_alloc(context->channel, args->num_cmdbufs, 409 job = host1x_job_alloc(context->channel, args->num_cmdbufs,
373 args->num_relocs, args->num_waitchks); 410 args->num_relocs, args->num_waitchks);
374 if (!job) 411 if (!job)
@@ -383,18 +420,42 @@ int tegra_drm_submit(struct tegra_drm_context *context,
383 while (num_cmdbufs) { 420 while (num_cmdbufs) {
384 struct drm_tegra_cmdbuf cmdbuf; 421 struct drm_tegra_cmdbuf cmdbuf;
385 struct host1x_bo *bo; 422 struct host1x_bo *bo;
423 struct tegra_bo *obj;
424 u64 offset;
386 425
387 if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) { 426 if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) {
388 err = -EFAULT; 427 err = -EFAULT;
389 goto fail; 428 goto fail;
390 } 429 }
391 430
431 /*
432 * The maximum number of CDMA gather fetches is 16383, a higher
433 * value means the words count is malformed.
434 */
435 if (cmdbuf.words > CDMA_GATHER_FETCHES_MAX_NB) {
436 err = -EINVAL;
437 goto fail;
438 }
439
392 bo = host1x_bo_lookup(file, cmdbuf.handle); 440 bo = host1x_bo_lookup(file, cmdbuf.handle);
393 if (!bo) { 441 if (!bo) {
394 err = -ENOENT; 442 err = -ENOENT;
395 goto fail; 443 goto fail;
396 } 444 }
397 445
446 offset = (u64)cmdbuf.offset + (u64)cmdbuf.words * sizeof(u32);
447 obj = host1x_to_tegra_bo(bo);
448
449 /*
450 * Gather buffer base address must be 4-bytes aligned,
451 * unaligned offset is malformed and cause commands stream
452 * corruption on the buffer address relocation.
453 */
454 if (offset & 3 || offset >= obj->gem.size) {
455 err = -EINVAL;
456 goto fail;
457 }
458
398 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); 459 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
399 num_cmdbufs--; 460 num_cmdbufs--;
400 cmdbufs++; 461 cmdbufs++;
@@ -402,17 +463,59 @@ int tegra_drm_submit(struct tegra_drm_context *context,
402 463
403 /* copy and resolve relocations from submit */ 464 /* copy and resolve relocations from submit */
404 while (num_relocs--) { 465 while (num_relocs--) {
466 struct host1x_reloc *reloc;
467 struct tegra_bo *obj;
468
405 err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs], 469 err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
406 &relocs[num_relocs], drm, 470 &relocs[num_relocs], drm,
407 file); 471 file);
408 if (err < 0) 472 if (err < 0)
409 goto fail; 473 goto fail;
474
475 reloc = &job->relocarray[num_relocs];
476 obj = host1x_to_tegra_bo(reloc->cmdbuf.bo);
477
478 /*
479 * The unaligned cmdbuf offset will cause an unaligned write
480 * during of the relocations patching, corrupting the commands
481 * stream.
482 */
483 if (reloc->cmdbuf.offset & 3 ||
484 reloc->cmdbuf.offset >= obj->gem.size) {
485 err = -EINVAL;
486 goto fail;
487 }
488
489 obj = host1x_to_tegra_bo(reloc->target.bo);
490
491 if (reloc->target.offset >= obj->gem.size) {
492 err = -EINVAL;
493 goto fail;
494 }
410 } 495 }
411 496
412 if (copy_from_user(job->waitchk, waitchks, 497 /* copy and resolve waitchks from submit */
413 sizeof(*waitchks) * num_waitchks)) { 498 while (num_waitchks--) {
414 err = -EFAULT; 499 struct host1x_waitchk *wait = &job->waitchk[num_waitchks];
415 goto fail; 500 struct tegra_bo *obj;
501
502 err = host1x_waitchk_copy_from_user(wait,
503 &waitchks[num_waitchks],
504 file);
505 if (err < 0)
506 goto fail;
507
508 obj = host1x_to_tegra_bo(wait->bo);
509
510 /*
511 * The unaligned offset will cause an unaligned write during
512 * of the waitchks patching, corrupting the commands stream.
513 */
514 if (wait->offset & 3 ||
515 wait->offset >= obj->gem.size) {
516 err = -EINVAL;
517 goto fail;
518 }
416 } 519 }
417 520
418 if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts, 521 if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts,
@@ -421,7 +524,15 @@ int tegra_drm_submit(struct tegra_drm_context *context,
421 goto fail; 524 goto fail;
422 } 525 }
423 526
527 /* check whether syncpoint ID is valid */
528 sp = host1x_syncpt_get(host1x, syncpt.id);
529 if (!sp) {
530 err = -ENOENT;
531 goto fail;
532 }
533
424 job->is_addr_reg = context->client->ops->is_addr_reg; 534 job->is_addr_reg = context->client->ops->is_addr_reg;
535 job->is_valid_class = context->client->ops->is_valid_class;
425 job->syncpt_incrs = syncpt.incrs; 536 job->syncpt_incrs = syncpt.incrs;
426 job->syncpt_id = syncpt.id; 537 job->syncpt_id = syncpt.id;
427 job->timeout = 10000; 538 job->timeout = 10000;
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 85aa2e3d9d4e..6d6da01282f3 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -83,6 +83,7 @@ struct tegra_drm_client_ops {
83 struct tegra_drm_context *context); 83 struct tegra_drm_context *context);
84 void (*close_channel)(struct tegra_drm_context *context); 84 void (*close_channel)(struct tegra_drm_context *context);
85 int (*is_addr_reg)(struct device *dev, u32 class, u32 offset); 85 int (*is_addr_reg)(struct device *dev, u32 class, u32 offset);
86 int (*is_valid_class)(u32 class);
86 int (*submit)(struct tegra_drm_context *context, 87 int (*submit)(struct tegra_drm_context *context,
87 struct drm_tegra_submit *args, struct drm_device *drm, 88 struct drm_tegra_submit *args, struct drm_device *drm,
88 struct drm_file *file); 89 struct drm_file *file);
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 424569b53e57..7a39a355678a 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -20,11 +20,6 @@
20#include "drm.h" 20#include "drm.h"
21#include "gem.h" 21#include "gem.h"
22 22
23static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo)
24{
25 return container_of(bo, struct tegra_bo, base);
26}
27
28static void tegra_bo_put(struct host1x_bo *bo) 23static void tegra_bo_put(struct host1x_bo *bo)
29{ 24{
30 struct tegra_bo *obj = host1x_to_tegra_bo(bo); 25 struct tegra_bo *obj = host1x_to_tegra_bo(bo);
diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h
index 6c5f12ac0087..8b32a6fd586d 100644
--- a/drivers/gpu/drm/tegra/gem.h
+++ b/drivers/gpu/drm/tegra/gem.h
@@ -52,6 +52,11 @@ static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem)
52 return container_of(gem, struct tegra_bo, gem); 52 return container_of(gem, struct tegra_bo, gem);
53} 53}
54 54
55static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo)
56{
57 return container_of(bo, struct tegra_bo, base);
58}
59
55struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size, 60struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size,
56 unsigned long flags); 61 unsigned long flags);
57struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, 62struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c
index 02cd3e37a6ec..6ea070da7718 100644
--- a/drivers/gpu/drm/tegra/gr2d.c
+++ b/drivers/gpu/drm/tegra/gr2d.c
@@ -38,7 +38,7 @@ static int gr2d_init(struct host1x_client *client)
38 38
39 client->syncpts[0] = host1x_syncpt_request(client->dev, flags); 39 client->syncpts[0] = host1x_syncpt_request(client->dev, flags);
40 if (!client->syncpts[0]) { 40 if (!client->syncpts[0]) {
41 host1x_channel_free(gr2d->channel); 41 host1x_channel_put(gr2d->channel);
42 return -ENOMEM; 42 return -ENOMEM;
43 } 43 }
44 44
@@ -57,7 +57,7 @@ static int gr2d_exit(struct host1x_client *client)
57 return err; 57 return err;
58 58
59 host1x_syncpt_free(client->syncpts[0]); 59 host1x_syncpt_free(client->syncpts[0]);
60 host1x_channel_free(gr2d->channel); 60 host1x_channel_put(gr2d->channel);
61 61
62 return 0; 62 return 0;
63} 63}
@@ -109,10 +109,17 @@ static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset)
109 return 0; 109 return 0;
110} 110}
111 111
112static int gr2d_is_valid_class(u32 class)
113{
114 return (class == HOST1X_CLASS_GR2D ||
115 class == HOST1X_CLASS_GR2D_SB);
116}
117
112static const struct tegra_drm_client_ops gr2d_ops = { 118static const struct tegra_drm_client_ops gr2d_ops = {
113 .open_channel = gr2d_open_channel, 119 .open_channel = gr2d_open_channel,
114 .close_channel = gr2d_close_channel, 120 .close_channel = gr2d_close_channel,
115 .is_addr_reg = gr2d_is_addr_reg, 121 .is_addr_reg = gr2d_is_addr_reg,
122 .is_valid_class = gr2d_is_valid_class,
116 .submit = tegra_drm_submit, 123 .submit = tegra_drm_submit,
117}; 124};
118 125
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 13f0d1b7cd98..cee2ab645cde 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -48,7 +48,7 @@ static int gr3d_init(struct host1x_client *client)
48 48
49 client->syncpts[0] = host1x_syncpt_request(client->dev, flags); 49 client->syncpts[0] = host1x_syncpt_request(client->dev, flags);
50 if (!client->syncpts[0]) { 50 if (!client->syncpts[0]) {
51 host1x_channel_free(gr3d->channel); 51 host1x_channel_put(gr3d->channel);
52 return -ENOMEM; 52 return -ENOMEM;
53 } 53 }
54 54
@@ -67,7 +67,7 @@ static int gr3d_exit(struct host1x_client *client)
67 return err; 67 return err;
68 68
69 host1x_syncpt_free(client->syncpts[0]); 69 host1x_syncpt_free(client->syncpts[0]);
70 host1x_channel_free(gr3d->channel); 70 host1x_channel_put(gr3d->channel);
71 71
72 return 0; 72 return 0;
73} 73}
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
index cd804e404a11..47cb1aaa58b1 100644
--- a/drivers/gpu/drm/tegra/vic.c
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -182,7 +182,7 @@ static int vic_init(struct host1x_client *client)
182free_syncpt: 182free_syncpt:
183 host1x_syncpt_free(client->syncpts[0]); 183 host1x_syncpt_free(client->syncpts[0]);
184free_channel: 184free_channel:
185 host1x_channel_free(vic->channel); 185 host1x_channel_put(vic->channel);
186detach_device: 186detach_device:
187 if (tegra->domain) 187 if (tegra->domain)
188 iommu_detach_device(tegra->domain, vic->dev); 188 iommu_detach_device(tegra->domain, vic->dev);
@@ -203,7 +203,7 @@ static int vic_exit(struct host1x_client *client)
203 return err; 203 return err;
204 204
205 host1x_syncpt_free(client->syncpts[0]); 205 host1x_syncpt_free(client->syncpts[0]);
206 host1x_channel_free(vic->channel); 206 host1x_channel_put(vic->channel);
207 207
208 if (vic->domain) { 208 if (vic->domain) {
209 iommu_detach_device(vic->domain, vic->dev); 209 iommu_detach_device(vic->domain, vic->dev);
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index 561831e1ae2c..a048e3ac523d 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -40,6 +40,9 @@ struct host1x_subdev {
40 40
41/** 41/**
42 * host1x_subdev_add() - add a new subdevice with an associated device node 42 * host1x_subdev_add() - add a new subdevice with an associated device node
43 * @device: host1x device to add the subdevice to
44 * @driver: host1x driver
45 * @np: device node
43 */ 46 */
44static int host1x_subdev_add(struct host1x_device *device, 47static int host1x_subdev_add(struct host1x_device *device,
45 struct device_node *np) 48 struct device_node *np)
@@ -62,6 +65,7 @@ static int host1x_subdev_add(struct host1x_device *device,
62 65
63/** 66/**
64 * host1x_subdev_del() - remove subdevice 67 * host1x_subdev_del() - remove subdevice
68 * @subdev: subdevice to remove
65 */ 69 */
66static void host1x_subdev_del(struct host1x_subdev *subdev) 70static void host1x_subdev_del(struct host1x_subdev *subdev)
67{ 71{
@@ -72,6 +76,8 @@ static void host1x_subdev_del(struct host1x_subdev *subdev)
72 76
73/** 77/**
74 * host1x_device_parse_dt() - scan device tree and add matching subdevices 78 * host1x_device_parse_dt() - scan device tree and add matching subdevices
79 * @device: host1x logical device
80 * @driver: host1x driver
75 */ 81 */
76static int host1x_device_parse_dt(struct host1x_device *device, 82static int host1x_device_parse_dt(struct host1x_device *device,
77 struct host1x_driver *driver) 83 struct host1x_driver *driver)
@@ -166,6 +172,16 @@ static void host1x_subdev_unregister(struct host1x_device *device,
166 mutex_unlock(&device->subdevs_lock); 172 mutex_unlock(&device->subdevs_lock);
167} 173}
168 174
175/**
176 * host1x_device_init() - initialize a host1x logical device
177 * @device: host1x logical device
178 *
179 * The driver for the host1x logical device can call this during execution of
180 * its &host1x_driver.probe implementation to initialize each of its clients.
181 * The client drivers access the subsystem specific driver data using the
182 * &host1x_client.parent field and driver data associated with it (usually by
183 * calling dev_get_drvdata()).
184 */
169int host1x_device_init(struct host1x_device *device) 185int host1x_device_init(struct host1x_device *device)
170{ 186{
171 struct host1x_client *client; 187 struct host1x_client *client;
@@ -192,6 +208,15 @@ int host1x_device_init(struct host1x_device *device)
192} 208}
193EXPORT_SYMBOL(host1x_device_init); 209EXPORT_SYMBOL(host1x_device_init);
194 210
211/**
212 * host1x_device_exit() - uninitialize host1x logical device
213 * @device: host1x logical device
214 *
215 * When the driver for a host1x logical device is unloaded, it can call this
216 * function to tear down each of its clients. Typically this is done after a
217 * subsystem-specific data structure is removed and the functionality can no
218 * longer be used.
219 */
195int host1x_device_exit(struct host1x_device *device) 220int host1x_device_exit(struct host1x_device *device)
196{ 221{
197 struct host1x_client *client; 222 struct host1x_client *client;
@@ -446,6 +471,14 @@ static void host1x_detach_driver(struct host1x *host1x,
446 mutex_unlock(&host1x->devices_lock); 471 mutex_unlock(&host1x->devices_lock);
447} 472}
448 473
474/**
475 * host1x_register() - register a host1x controller
476 * @host1x: host1x controller
477 *
478 * The host1x controller driver uses this to register a host1x controller with
479 * the infrastructure. Note that all Tegra SoC generations have only ever come
480 * with a single host1x instance, so this function is somewhat academic.
481 */
449int host1x_register(struct host1x *host1x) 482int host1x_register(struct host1x *host1x)
450{ 483{
451 struct host1x_driver *driver; 484 struct host1x_driver *driver;
@@ -464,6 +497,13 @@ int host1x_register(struct host1x *host1x)
464 return 0; 497 return 0;
465} 498}
466 499
500/**
501 * host1x_unregister() - unregister a host1x controller
502 * @host1x: host1x controller
503 *
504 * The host1x controller driver uses this to remove a host1x controller from
505 * the infrastructure.
506 */
467int host1x_unregister(struct host1x *host1x) 507int host1x_unregister(struct host1x *host1x)
468{ 508{
469 struct host1x_driver *driver; 509 struct host1x_driver *driver;
@@ -513,6 +553,16 @@ static void host1x_device_shutdown(struct device *dev)
513 driver->shutdown(device); 553 driver->shutdown(device);
514} 554}
515 555
556/**
557 * host1x_driver_register_full() - register a host1x driver
558 * @driver: host1x driver
559 * @owner: owner module
560 *
561 * Drivers for host1x logical devices call this function to register a driver
562 * with the infrastructure. Note that since these drive logical devices, the
563 * registration of the driver actually triggers tho logical device creation.
564 * A logical device will be created for each host1x instance.
565 */
516int host1x_driver_register_full(struct host1x_driver *driver, 566int host1x_driver_register_full(struct host1x_driver *driver,
517 struct module *owner) 567 struct module *owner)
518{ 568{
@@ -541,6 +591,13 @@ int host1x_driver_register_full(struct host1x_driver *driver,
541} 591}
542EXPORT_SYMBOL(host1x_driver_register_full); 592EXPORT_SYMBOL(host1x_driver_register_full);
543 593
594/**
595 * host1x_driver_unregister() - unregister a host1x driver
596 * @driver: host1x driver
597 *
598 * Unbinds the driver from each of the host1x logical devices that it is
599 * bound to, effectively removing the subsystem devices that they represent.
600 */
544void host1x_driver_unregister(struct host1x_driver *driver) 601void host1x_driver_unregister(struct host1x_driver *driver)
545{ 602{
546 driver_unregister(&driver->driver); 603 driver_unregister(&driver->driver);
@@ -551,6 +608,17 @@ void host1x_driver_unregister(struct host1x_driver *driver)
551} 608}
552EXPORT_SYMBOL(host1x_driver_unregister); 609EXPORT_SYMBOL(host1x_driver_unregister);
553 610
611/**
612 * host1x_client_register() - register a host1x client
613 * @client: host1x client
614 *
615 * Registers a host1x client with each host1x controller instance. Note that
616 * each client will only match their parent host1x controller and will only be
617 * associated with that instance. Once all clients have been registered with
618 * their parent host1x controller, the infrastructure will set up the logical
619 * device and call host1x_device_init(), which will in turn call each client's
620 * &host1x_client_ops.init implementation.
621 */
554int host1x_client_register(struct host1x_client *client) 622int host1x_client_register(struct host1x_client *client)
555{ 623{
556 struct host1x *host1x; 624 struct host1x *host1x;
@@ -576,6 +644,13 @@ int host1x_client_register(struct host1x_client *client)
576} 644}
577EXPORT_SYMBOL(host1x_client_register); 645EXPORT_SYMBOL(host1x_client_register);
578 646
647/**
648 * host1x_client_unregister() - unregister a host1x client
649 * @client: host1x client
650 *
651 * Removes a host1x client from its host1x controller instance. If a logical
652 * device has already been initialized, it will be torn down.
653 */
579int host1x_client_unregister(struct host1x_client *client) 654int host1x_client_unregister(struct host1x_client *client)
580{ 655{
581 struct host1x_client *c; 656 struct host1x_client *c;
diff --git a/drivers/gpu/host1x/cdma.h b/drivers/gpu/host1x/cdma.h
index ec170a78f4e1..286d49386be9 100644
--- a/drivers/gpu/host1x/cdma.h
+++ b/drivers/gpu/host1x/cdma.h
@@ -88,7 +88,6 @@ struct host1x_cdma {
88 88
89int host1x_cdma_init(struct host1x_cdma *cdma); 89int host1x_cdma_init(struct host1x_cdma *cdma);
90int host1x_cdma_deinit(struct host1x_cdma *cdma); 90int host1x_cdma_deinit(struct host1x_cdma *cdma);
91void host1x_cdma_stop(struct host1x_cdma *cdma);
92int host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job); 91int host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job);
93void host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2); 92void host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2);
94void host1x_cdma_end(struct host1x_cdma *cdma, struct host1x_job *job); 93void host1x_cdma_end(struct host1x_cdma *cdma, struct host1x_job *job);
diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c
index 8f437d924c10..db9b91d1384c 100644
--- a/drivers/gpu/host1x/channel.c
+++ b/drivers/gpu/host1x/channel.c
@@ -24,19 +24,33 @@
24#include "job.h" 24#include "job.h"
25 25
26/* Constructor for the host1x device list */ 26/* Constructor for the host1x device list */
27int host1x_channel_list_init(struct host1x *host) 27int host1x_channel_list_init(struct host1x_channel_list *chlist,
28 unsigned int num_channels)
28{ 29{
29 INIT_LIST_HEAD(&host->chlist.list); 30 chlist->channels = kcalloc(num_channels, sizeof(struct host1x_channel),
30 mutex_init(&host->chlist_mutex); 31 GFP_KERNEL);
31 32 if (!chlist->channels)
32 if (host->info->nb_channels > BITS_PER_LONG) { 33 return -ENOMEM;
33 WARN(1, "host1x hardware has more channels than supported by the driver\n"); 34
34 return -ENOSYS; 35 chlist->allocated_channels =
36 kcalloc(BITS_TO_LONGS(num_channels), sizeof(unsigned long),
37 GFP_KERNEL);
38 if (!chlist->allocated_channels) {
39 kfree(chlist->channels);
40 return -ENOMEM;
35 } 41 }
36 42
43 bitmap_zero(chlist->allocated_channels, num_channels);
44
37 return 0; 45 return 0;
38} 46}
39 47
48void host1x_channel_list_free(struct host1x_channel_list *chlist)
49{
50 kfree(chlist->allocated_channels);
51 kfree(chlist->channels);
52}
53
40int host1x_job_submit(struct host1x_job *job) 54int host1x_job_submit(struct host1x_job *job)
41{ 55{
42 struct host1x *host = dev_get_drvdata(job->channel->dev->parent); 56 struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
@@ -47,86 +61,107 @@ EXPORT_SYMBOL(host1x_job_submit);
47 61
48struct host1x_channel *host1x_channel_get(struct host1x_channel *channel) 62struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
49{ 63{
50 int err = 0; 64 kref_get(&channel->refcount);
51 65
52 mutex_lock(&channel->reflock); 66 return channel;
67}
68EXPORT_SYMBOL(host1x_channel_get);
53 69
54 if (channel->refcount == 0) 70/**
55 err = host1x_cdma_init(&channel->cdma); 71 * host1x_channel_get_index() - Attempt to get channel reference by index
72 * @host: Host1x device object
73 * @index: Index of channel
74 *
75 * If channel number @index is currently allocated, increase its refcount
76 * and return a pointer to it. Otherwise, return NULL.
77 */
78struct host1x_channel *host1x_channel_get_index(struct host1x *host,
79 unsigned int index)
80{
81 struct host1x_channel *ch = &host->channel_list.channels[index];
56 82
57 if (!err) 83 if (!kref_get_unless_zero(&ch->refcount))
58 channel->refcount++; 84 return NULL;
59 85
60 mutex_unlock(&channel->reflock); 86 return ch;
87}
88
89static void release_channel(struct kref *kref)
90{
91 struct host1x_channel *channel =
92 container_of(kref, struct host1x_channel, refcount);
93 struct host1x *host = dev_get_drvdata(channel->dev->parent);
94 struct host1x_channel_list *chlist = &host->channel_list;
95
96 host1x_hw_cdma_stop(host, &channel->cdma);
97 host1x_cdma_deinit(&channel->cdma);
61 98
62 return err ? NULL : channel; 99 clear_bit(channel->id, chlist->allocated_channels);
63} 100}
64EXPORT_SYMBOL(host1x_channel_get);
65 101
66void host1x_channel_put(struct host1x_channel *channel) 102void host1x_channel_put(struct host1x_channel *channel)
67{ 103{
68 mutex_lock(&channel->reflock); 104 kref_put(&channel->refcount, release_channel);
105}
106EXPORT_SYMBOL(host1x_channel_put);
69 107
70 if (channel->refcount == 1) { 108static struct host1x_channel *acquire_unused_channel(struct host1x *host)
71 struct host1x *host = dev_get_drvdata(channel->dev->parent); 109{
110 struct host1x_channel_list *chlist = &host->channel_list;
111 unsigned int max_channels = host->info->nb_channels;
112 unsigned int index;
72 113
73 host1x_hw_cdma_stop(host, &channel->cdma); 114 index = find_first_zero_bit(chlist->allocated_channels, max_channels);
74 host1x_cdma_deinit(&channel->cdma); 115 if (index >= max_channels) {
116 dev_err(host->dev, "failed to find free channel\n");
117 return NULL;
75 } 118 }
76 119
77 channel->refcount--; 120 chlist->channels[index].id = index;
78 121
79 mutex_unlock(&channel->reflock); 122 set_bit(index, chlist->allocated_channels);
123
124 return &chlist->channels[index];
80} 125}
81EXPORT_SYMBOL(host1x_channel_put);
82 126
127/**
128 * host1x_channel_request() - Allocate a channel
129 * @device: Host1x unit this channel will be used to send commands to
130 *
131 * Allocates a new host1x channel for @device. If there are no free channels,
132 * this will sleep until one becomes available. May return NULL if CDMA
133 * initialization fails.
134 */
83struct host1x_channel *host1x_channel_request(struct device *dev) 135struct host1x_channel *host1x_channel_request(struct device *dev)
84{ 136{
85 struct host1x *host = dev_get_drvdata(dev->parent); 137 struct host1x *host = dev_get_drvdata(dev->parent);
86 unsigned int max_channels = host->info->nb_channels; 138 struct host1x_channel_list *chlist = &host->channel_list;
87 struct host1x_channel *channel = NULL; 139 struct host1x_channel *channel;
88 unsigned long index;
89 int err; 140 int err;
90 141
91 mutex_lock(&host->chlist_mutex); 142 channel = acquire_unused_channel(host);
143 if (!channel)
144 return NULL;
92 145
93 index = find_first_zero_bit(&host->allocated_channels, max_channels); 146 kref_init(&channel->refcount);
94 if (index >= max_channels) 147 mutex_init(&channel->submitlock);
95 goto fail; 148 channel->dev = dev;
96 149
97 channel = kzalloc(sizeof(*channel), GFP_KERNEL); 150 err = host1x_hw_channel_init(host, channel, channel->id);
98 if (!channel) 151 if (err < 0)
99 goto fail; 152 goto fail;
100 153
101 err = host1x_hw_channel_init(host, channel, index); 154 err = host1x_cdma_init(&channel->cdma);
102 if (err < 0) 155 if (err < 0)
103 goto fail; 156 goto fail;
104 157
105 /* Link device to host1x_channel */
106 channel->dev = dev;
107
108 /* Add to channel list */
109 list_add_tail(&channel->list, &host->chlist.list);
110
111 host->allocated_channels |= BIT(index);
112
113 mutex_unlock(&host->chlist_mutex);
114 return channel; 158 return channel;
115 159
116fail: 160fail:
117 dev_err(dev, "failed to init channel\n"); 161 clear_bit(channel->id, chlist->allocated_channels);
118 kfree(channel);
119 mutex_unlock(&host->chlist_mutex);
120 return NULL;
121}
122EXPORT_SYMBOL(host1x_channel_request);
123 162
124void host1x_channel_free(struct host1x_channel *channel) 163 dev_err(dev, "failed to initialize channel\n");
125{
126 struct host1x *host = dev_get_drvdata(channel->dev->parent);
127 164
128 host->allocated_channels &= ~BIT(channel->id); 165 return NULL;
129 list_del(&channel->list);
130 kfree(channel);
131} 166}
132EXPORT_SYMBOL(host1x_channel_free); 167EXPORT_SYMBOL(host1x_channel_request);
diff --git a/drivers/gpu/host1x/channel.h b/drivers/gpu/host1x/channel.h
index df767cf90d51..7068e42d42df 100644
--- a/drivers/gpu/host1x/channel.h
+++ b/drivers/gpu/host1x/channel.h
@@ -20,17 +20,21 @@
20#define __HOST1X_CHANNEL_H 20#define __HOST1X_CHANNEL_H
21 21
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/kref.h>
23 24
24#include "cdma.h" 25#include "cdma.h"
25 26
26struct host1x; 27struct host1x;
28struct host1x_channel;
27 29
28struct host1x_channel { 30struct host1x_channel_list {
29 struct list_head list; 31 struct host1x_channel *channels;
32 unsigned long *allocated_channels;
33};
30 34
31 unsigned int refcount; 35struct host1x_channel {
36 struct kref refcount;
32 unsigned int id; 37 unsigned int id;
33 struct mutex reflock;
34 struct mutex submitlock; 38 struct mutex submitlock;
35 void __iomem *regs; 39 void __iomem *regs;
36 struct device *dev; 40 struct device *dev;
@@ -38,9 +42,10 @@ struct host1x_channel {
38}; 42};
39 43
40/* channel list operations */ 44/* channel list operations */
41int host1x_channel_list_init(struct host1x *host); 45int host1x_channel_list_init(struct host1x_channel_list *chlist,
42 46 unsigned int num_channels);
43#define host1x_for_each_channel(host, channel) \ 47void host1x_channel_list_free(struct host1x_channel_list *chlist);
44 list_for_each_entry(channel, &host->chlist.list, list) 48struct host1x_channel *host1x_channel_get_index(struct host1x *host,
49 unsigned int index);
45 50
46#endif 51#endif
diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c
index d9330fcc62ad..2aae0e63214c 100644
--- a/drivers/gpu/host1x/debug.c
+++ b/drivers/gpu/host1x/debug.c
@@ -43,24 +43,19 @@ void host1x_debug_output(struct output *o, const char *fmt, ...)
43 o->fn(o->ctx, o->buf, len); 43 o->fn(o->ctx, o->buf, len);
44} 44}
45 45
46static int show_channels(struct host1x_channel *ch, void *data, bool show_fifo) 46static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
47{ 47{
48 struct host1x *m = dev_get_drvdata(ch->dev->parent); 48 struct host1x *m = dev_get_drvdata(ch->dev->parent);
49 struct output *o = data; 49 struct output *o = data;
50 50
51 mutex_lock(&ch->reflock); 51 mutex_lock(&ch->cdma.lock);
52 52
53 if (ch->refcount) { 53 if (show_fifo)
54 mutex_lock(&ch->cdma.lock); 54 host1x_hw_show_channel_fifo(m, ch, o);
55 55
56 if (show_fifo) 56 host1x_hw_show_channel_cdma(m, ch, o);
57 host1x_hw_show_channel_fifo(m, ch, o);
58 57
59 host1x_hw_show_channel_cdma(m, ch, o); 58 mutex_unlock(&ch->cdma.lock);
60 mutex_unlock(&ch->cdma.lock);
61 }
62
63 mutex_unlock(&ch->reflock);
64 59
65 return 0; 60 return 0;
66} 61}
@@ -94,28 +89,22 @@ static void show_syncpts(struct host1x *m, struct output *o)
94 host1x_debug_output(o, "\n"); 89 host1x_debug_output(o, "\n");
95} 90}
96 91
97static void show_all(struct host1x *m, struct output *o) 92static void show_all(struct host1x *m, struct output *o, bool show_fifo)
98{ 93{
99 struct host1x_channel *ch; 94 int i;
100 95
101 host1x_hw_show_mlocks(m, o); 96 host1x_hw_show_mlocks(m, o);
102 show_syncpts(m, o); 97 show_syncpts(m, o);
103 host1x_debug_output(o, "---- channels ----\n"); 98 host1x_debug_output(o, "---- channels ----\n");
104 99
105 host1x_for_each_channel(m, ch) 100 for (i = 0; i < m->info->nb_channels; ++i) {
106 show_channels(ch, o, true); 101 struct host1x_channel *ch = host1x_channel_get_index(m, i);
107}
108
109static void show_all_no_fifo(struct host1x *host1x, struct output *o)
110{
111 struct host1x_channel *ch;
112
113 host1x_hw_show_mlocks(host1x, o);
114 show_syncpts(host1x, o);
115 host1x_debug_output(o, "---- channels ----\n");
116 102
117 host1x_for_each_channel(host1x, ch) 103 if (ch) {
118 show_channels(ch, o, false); 104 show_channel(ch, o, show_fifo);
105 host1x_channel_put(ch);
106 }
107 }
119} 108}
120 109
121static int host1x_debug_show_all(struct seq_file *s, void *unused) 110static int host1x_debug_show_all(struct seq_file *s, void *unused)
@@ -125,7 +114,7 @@ static int host1x_debug_show_all(struct seq_file *s, void *unused)
125 .ctx = s 114 .ctx = s
126 }; 115 };
127 116
128 show_all(s->private, &o); 117 show_all(s->private, &o, true);
129 118
130 return 0; 119 return 0;
131} 120}
@@ -137,7 +126,7 @@ static int host1x_debug_show(struct seq_file *s, void *unused)
137 .ctx = s 126 .ctx = s
138 }; 127 };
139 128
140 show_all_no_fifo(s->private, &o); 129 show_all(s->private, &o, false);
141 130
142 return 0; 131 return 0;
143} 132}
@@ -216,7 +205,7 @@ void host1x_debug_dump(struct host1x *host1x)
216 .fn = write_to_printk 205 .fn = write_to_printk
217 }; 206 };
218 207
219 show_all(host1x, &o); 208 show_all(host1x, &o, true);
220} 209}
221 210
222void host1x_debug_dump_syncpts(struct host1x *host1x) 211void host1x_debug_dump_syncpts(struct host1x *host1x)
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index f05ebb14fa63..5c1c711a21af 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -198,7 +198,8 @@ static int host1x_probe(struct platform_device *pdev)
198 host->iova_end = geometry->aperture_end; 198 host->iova_end = geometry->aperture_end;
199 } 199 }
200 200
201 err = host1x_channel_list_init(host); 201 err = host1x_channel_list_init(&host->channel_list,
202 host->info->nb_channels);
202 if (err) { 203 if (err) {
203 dev_err(&pdev->dev, "failed to initialize channel list\n"); 204 dev_err(&pdev->dev, "failed to initialize channel list\n");
204 goto fail_detach_device; 205 goto fail_detach_device;
@@ -207,7 +208,7 @@ static int host1x_probe(struct platform_device *pdev)
207 err = clk_prepare_enable(host->clk); 208 err = clk_prepare_enable(host->clk);
208 if (err < 0) { 209 if (err < 0) {
209 dev_err(&pdev->dev, "failed to enable clock\n"); 210 dev_err(&pdev->dev, "failed to enable clock\n");
210 goto fail_detach_device; 211 goto fail_free_channels;
211 } 212 }
212 213
213 err = reset_control_deassert(host->rst); 214 err = reset_control_deassert(host->rst);
@@ -244,6 +245,8 @@ fail_reset_assert:
244 reset_control_assert(host->rst); 245 reset_control_assert(host->rst);
245fail_unprepare_disable: 246fail_unprepare_disable:
246 clk_disable_unprepare(host->clk); 247 clk_disable_unprepare(host->clk);
248fail_free_channels:
249 host1x_channel_list_free(&host->channel_list);
247fail_detach_device: 250fail_detach_device:
248 if (host->domain) { 251 if (host->domain) {
249 put_iova_domain(&host->iova); 252 put_iova_domain(&host->iova);
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index 229d08b6a45e..ffdbc15b749b 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -129,10 +129,8 @@ struct host1x {
129 struct host1x_syncpt *nop_sp; 129 struct host1x_syncpt *nop_sp;
130 130
131 struct mutex syncpt_mutex; 131 struct mutex syncpt_mutex;
132 struct mutex chlist_mutex; 132
133 struct host1x_channel chlist; 133 struct host1x_channel_list channel_list;
134 unsigned long allocated_channels;
135 unsigned int num_allocated_channels;
136 134
137 struct dentry *debugfs; 135 struct dentry *debugfs;
138 136
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c
index 5e8df78b7acd..8447a56c41ca 100644
--- a/drivers/gpu/host1x/hw/channel_hw.c
+++ b/drivers/gpu/host1x/hw/channel_hw.c
@@ -181,10 +181,6 @@ error:
181static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, 181static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
182 unsigned int index) 182 unsigned int index)
183{ 183{
184 ch->id = index;
185 mutex_init(&ch->reflock);
186 mutex_init(&ch->submitlock);
187
188 ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE; 184 ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE;
189 return 0; 185 return 0;
190} 186}
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 5f5f8ee6143d..bee504406cfc 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
34struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, 36struct 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)
@@ -137,8 +139,9 @@ static void host1x_syncpt_patch_offset(struct host1x_syncpt *sp,
137 * avoid a wrap condition in the HW). 139 * avoid a wrap condition in the HW).
138 */ 140 */
139static int do_waitchks(struct host1x_job *job, struct host1x *host, 141static int do_waitchks(struct host1x_job *job, struct host1x *host,
140 struct host1x_bo *patch) 142 struct host1x_job_gather *g)
141{ 143{
144 struct host1x_bo *patch = g->bo;
142 int i; 145 int i;
143 146
144 /* compare syncpt vs wait threshold */ 147 /* compare syncpt vs wait threshold */
@@ -165,7 +168,8 @@ static int do_waitchks(struct host1x_job *job, struct host1x *host,
165 wait->syncpt_id, sp->name, wait->thresh, 168 wait->syncpt_id, sp->name, wait->thresh,
166 host1x_syncpt_read_min(sp)); 169 host1x_syncpt_read_min(sp));
167 170
168 host1x_syncpt_patch_offset(sp, patch, wait->offset); 171 host1x_syncpt_patch_offset(sp, patch,
172 g->offset + wait->offset);
169 } 173 }
170 174
171 wait->bo = NULL; 175 wait->bo = NULL;
@@ -269,11 +273,12 @@ unpin:
269 return err; 273 return err;
270} 274}
271 275
272static int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) 276static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g)
273{ 277{
274 int i = 0; 278 int i = 0;
275 u32 last_page = ~0; 279 u32 last_page = ~0;
276 void *cmdbuf_page_addr = NULL; 280 void *cmdbuf_page_addr = NULL;
281 struct host1x_bo *cmdbuf = g->bo;
277 282
278 /* pin & patch the relocs for one gather */ 283 /* pin & patch the relocs for one gather */
279 for (i = 0; i < job->num_relocs; i++) { 284 for (i = 0; i < job->num_relocs; i++) {
@@ -286,6 +291,13 @@ static int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
286 if (cmdbuf != reloc->cmdbuf.bo) 291 if (cmdbuf != reloc->cmdbuf.bo)
287 continue; 292 continue;
288 293
294 if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) {
295 target = (u32 *)job->gather_copy_mapped +
296 reloc->cmdbuf.offset / sizeof(u32) +
297 g->offset / sizeof(u32);
298 goto patch_reloc;
299 }
300
289 if (last_page != reloc->cmdbuf.offset >> PAGE_SHIFT) { 301 if (last_page != reloc->cmdbuf.offset >> PAGE_SHIFT) {
290 if (cmdbuf_page_addr) 302 if (cmdbuf_page_addr)
291 host1x_bo_kunmap(cmdbuf, last_page, 303 host1x_bo_kunmap(cmdbuf, last_page,
@@ -302,6 +314,7 @@ static int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
302 } 314 }
303 315
304 target = cmdbuf_page_addr + (reloc->cmdbuf.offset & ~PAGE_MASK); 316 target = cmdbuf_page_addr + (reloc->cmdbuf.offset & ~PAGE_MASK);
317patch_reloc:
305 *target = reloc_addr; 318 *target = reloc_addr;
306 } 319 }
307 320
@@ -319,6 +332,21 @@ static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
319 if (reloc->cmdbuf.bo != cmdbuf || reloc->cmdbuf.offset != offset) 332 if (reloc->cmdbuf.bo != cmdbuf || reloc->cmdbuf.offset != offset)
320 return false; 333 return false;
321 334
335 /* relocation shift value validation isn't implemented yet */
336 if (reloc->shift)
337 return false;
338
339 return true;
340}
341
342static 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
322 return true; 350 return true;
323} 351}
324 352
@@ -329,6 +357,9 @@ struct host1x_firewall {
329 unsigned int num_relocs; 357 unsigned int num_relocs;
330 struct host1x_reloc *reloc; 358 struct host1x_reloc *reloc;
331 359
360 unsigned int num_waitchks;
361 struct host1x_waitchk *waitchk;
362
332 struct host1x_bo *cmdbuf; 363 struct host1x_bo *cmdbuf;
333 unsigned int offset; 364 unsigned int offset;
334 365
@@ -341,6 +372,9 @@ struct host1x_firewall {
341 372
342static int check_register(struct host1x_firewall *fw, unsigned long offset) 373static int check_register(struct host1x_firewall *fw, unsigned long offset)
343{ 374{
375 if (!fw->job->is_addr_reg)
376 return 0;
377
344 if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) { 378 if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) {
345 if (!fw->num_relocs) 379 if (!fw->num_relocs)
346 return -EINVAL; 380 return -EINVAL;
@@ -352,6 +386,33 @@ static int check_register(struct host1x_firewall *fw, unsigned long offset)
352 fw->reloc++; 386 fw->reloc++;
353 } 387 }
354 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
403 return 0;
404}
405
406static int check_class(struct host1x_firewall *fw, u32 class)
407{
408 if (!fw->job->is_valid_class) {
409 if (fw->class != class)
410 return -EINVAL;
411 } else {
412 if (!fw->job->is_valid_class(fw->class))
413 return -EINVAL;
414 }
415
355 return 0; 416 return 0;
356} 417}
357 418
@@ -428,11 +489,9 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
428{ 489{
429 u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped + 490 u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped +
430 (g->offset / sizeof(u32)); 491 (g->offset / sizeof(u32));
492 u32 job_class = fw->class;
431 int err = 0; 493 int err = 0;
432 494
433 if (!fw->job->is_addr_reg)
434 return 0;
435
436 fw->words = g->words; 495 fw->words = g->words;
437 fw->cmdbuf = g->bo; 496 fw->cmdbuf = g->bo;
438 fw->offset = 0; 497 fw->offset = 0;
@@ -452,7 +511,9 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
452 fw->class = word >> 6 & 0x3ff; 511 fw->class = word >> 6 & 0x3ff;
453 fw->mask = word & 0x3f; 512 fw->mask = word & 0x3f;
454 fw->reg = word >> 16 & 0xfff; 513 fw->reg = word >> 16 & 0xfff;
455 err = check_mask(fw); 514 err = check_class(fw, job_class);
515 if (!err)
516 err = check_mask(fw);
456 if (err) 517 if (err)
457 goto out; 518 goto out;
458 break; 519 break;
@@ -480,7 +541,6 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
480 goto out; 541 goto out;
481 break; 542 break;
482 case 4: 543 case 4:
483 case 5:
484 case 14: 544 case 14:
485 break; 545 break;
486 default: 546 default:
@@ -504,7 +564,9 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
504 fw.dev = dev; 564 fw.dev = dev;
505 fw.reloc = job->relocarray; 565 fw.reloc = job->relocarray;
506 fw.num_relocs = job->num_relocs; 566 fw.num_relocs = job->num_relocs;
507 fw.class = 0; 567 fw.waitchk = job->waitchk;
568 fw.num_waitchks = job->num_waitchk;
569 fw.class = job->class;
508 570
509 for (i = 0; i < job->num_gathers; i++) { 571 for (i = 0; i < job->num_gathers; i++) {
510 struct host1x_job_gather *g = &job->gathers[i]; 572 struct host1x_job_gather *g = &job->gathers[i];
@@ -512,12 +574,20 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
512 size += g->words * sizeof(u32); 574 size += g->words * sizeof(u32);
513 } 575 }
514 576
577 /*
578 * Try a non-blocking allocation from a higher priority pools first,
579 * as awaiting for the allocation here is a major performance hit.
580 */
515 job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy, 581 job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy,
516 GFP_KERNEL); 582 GFP_NOWAIT);
517 if (!job->gather_copy_mapped) { 583
518 job->gather_copy_mapped = NULL; 584 /* the higher priority allocation failed, try the generic-blocking */
585 if (!job->gather_copy_mapped)
586 job->gather_copy_mapped = dma_alloc_wc(dev, size,
587 &job->gather_copy,
588 GFP_KERNEL);
589 if (!job->gather_copy_mapped)
519 return -ENOMEM; 590 return -ENOMEM;
520 }
521 591
522 job->gather_copy_size = size; 592 job->gather_copy_size = size;
523 593
@@ -542,8 +612,8 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
542 offset += g->words * sizeof(u32); 612 offset += g->words * sizeof(u32);
543 } 613 }
544 614
545 /* No relocs should remain at this point */ 615 /* No relocs and waitchks should remain at this point */
546 if (fw.num_relocs) 616 if (fw.num_relocs || fw.num_waitchks)
547 return -EINVAL; 617 return -EINVAL;
548 618
549 return 0; 619 return 0;
@@ -573,6 +643,12 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
573 if (err) 643 if (err)
574 goto out; 644 goto out;
575 645
646 if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) {
647 err = copy_gathers(job, dev);
648 if (err)
649 goto out;
650 }
651
576 /* patch gathers */ 652 /* patch gathers */
577 for (i = 0; i < job->num_gathers; i++) { 653 for (i = 0; i < job->num_gathers; i++) {
578 struct host1x_job_gather *g = &job->gathers[i]; 654 struct host1x_job_gather *g = &job->gathers[i];
@@ -581,7 +657,9 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
581 if (g->handled) 657 if (g->handled)
582 continue; 658 continue;
583 659
584 g->base = job->gather_addr_phys[i]; 660 /* copy_gathers() sets gathers base if firewall is enabled */
661 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
662 g->base = job->gather_addr_phys[i];
585 663
586 for (j = i + 1; j < job->num_gathers; j++) { 664 for (j = i + 1; j < job->num_gathers; j++) {
587 if (job->gathers[j].bo == g->bo) { 665 if (job->gathers[j].bo == g->bo) {
@@ -590,24 +668,18 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
590 } 668 }
591 } 669 }
592 670
593 err = do_relocs(job, g->bo); 671 err = do_relocs(job, g);
594 if (err) 672 if (err)
595 break; 673 break;
596 674
597 err = do_waitchks(job, host, g->bo); 675 err = do_waitchks(job, host, g);
598 if (err) 676 if (err)
599 break; 677 break;
600 } 678 }
601 679
602 if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && !err) {
603 err = copy_gathers(job, dev);
604 if (err) {
605 host1x_job_unpin(job);
606 return err;
607 }
608 }
609
610out: 680out:
681 if (err)
682 host1x_job_unpin(job);
611 wmb(); 683 wmb();
612 684
613 return err; 685 return err;
diff --git a/drivers/gpu/host1x/job.h b/drivers/gpu/host1x/job.h
index 878239c476d2..4bda51d503ec 100644
--- a/drivers/gpu/host1x/job.h
+++ b/drivers/gpu/host1x/job.h
@@ -27,20 +27,6 @@ struct host1x_job_gather {
27 bool handled; 27 bool handled;
28}; 28};
29 29
30struct host1x_cmdbuf {
31 u32 handle;
32 u32 offset;
33 u32 words;
34 u32 pad;
35};
36
37struct host1x_waitchk {
38 struct host1x_bo *bo;
39 u32 offset;
40 u32 syncpt_id;
41 u32 thresh;
42};
43
44struct host1x_job_unpin_data { 30struct host1x_job_unpin_data {
45 struct host1x_bo *bo; 31 struct host1x_bo *bo;
46 struct sg_table *sgt; 32 struct sg_table *sgt;
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index 0ac026cdc30c..048ac9e344ce 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -99,14 +99,24 @@ unlock:
99 return NULL; 99 return NULL;
100} 100}
101 101
102/**
103 * host1x_syncpt_id() - retrieve syncpoint ID
104 * @sp: host1x syncpoint
105 *
106 * Given a pointer to a struct host1x_syncpt, retrieves its ID. This ID is
107 * often used as a value to program into registers that control how hardware
108 * blocks interact with syncpoints.
109 */
102u32 host1x_syncpt_id(struct host1x_syncpt *sp) 110u32 host1x_syncpt_id(struct host1x_syncpt *sp)
103{ 111{
104 return sp->id; 112 return sp->id;
105} 113}
106EXPORT_SYMBOL(host1x_syncpt_id); 114EXPORT_SYMBOL(host1x_syncpt_id);
107 115
108/* 116/**
109 * Updates the value sent to hardware. 117 * host1x_syncpt_incr_max() - update the value sent to hardware
118 * @sp: host1x syncpoint
119 * @incrs: number of increments
110 */ 120 */
111u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs) 121u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
112{ 122{
@@ -175,8 +185,9 @@ u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
175 return sp->base_val; 185 return sp->base_val;
176} 186}
177 187
178/* 188/**
179 * Increment syncpoint value from cpu, updating cache 189 * host1x_syncpt_incr() - increment syncpoint value from CPU, updating cache
190 * @sp: host1x syncpoint
180 */ 191 */
181int host1x_syncpt_incr(struct host1x_syncpt *sp) 192int host1x_syncpt_incr(struct host1x_syncpt *sp)
182{ 193{
@@ -195,8 +206,12 @@ static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh)
195 return host1x_syncpt_is_expired(sp, thresh); 206 return host1x_syncpt_is_expired(sp, thresh);
196} 207}
197 208
198/* 209/**
199 * Main entrypoint for syncpoint value waits. 210 * host1x_syncpt_wait() - wait for a syncpoint to reach a given value
211 * @sp: host1x syncpoint
212 * @thresh: threshold
213 * @timeout: maximum time to wait for the syncpoint to reach the given value
214 * @value: return location for the syncpoint value
200 */ 215 */
201int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, 216int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
202 u32 *value) 217 u32 *value)
@@ -402,6 +417,16 @@ int host1x_syncpt_init(struct host1x *host)
402 return 0; 417 return 0;
403} 418}
404 419
420/**
421 * host1x_syncpt_request() - request a syncpoint
422 * @dev: device requesting the syncpoint
423 * @flags: flags
424 *
425 * host1x client drivers can use this function to allocate a syncpoint for
426 * subsequent use. A syncpoint returned by this function will be reserved for
427 * use by the client exclusively. When no longer using a syncpoint, a host1x
428 * client driver needs to release it using host1x_syncpt_free().
429 */
405struct host1x_syncpt *host1x_syncpt_request(struct device *dev, 430struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
406 unsigned long flags) 431 unsigned long flags)
407{ 432{
@@ -411,6 +436,16 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
411} 436}
412EXPORT_SYMBOL(host1x_syncpt_request); 437EXPORT_SYMBOL(host1x_syncpt_request);
413 438
439/**
440 * host1x_syncpt_free() - free a requested syncpoint
441 * @sp: host1x syncpoint
442 *
443 * Release a syncpoint previously allocated using host1x_syncpt_request(). A
444 * host1x client driver should call this when the syncpoint is no longer in
445 * use. Note that client drivers must ensure that the syncpoint doesn't remain
446 * under the control of hardware after calling this function, otherwise two
447 * clients may end up trying to access the same syncpoint concurrently.
448 */
414void host1x_syncpt_free(struct host1x_syncpt *sp) 449void host1x_syncpt_free(struct host1x_syncpt *sp)
415{ 450{
416 if (!sp) 451 if (!sp)
@@ -438,9 +473,12 @@ void host1x_syncpt_deinit(struct host1x *host)
438 kfree(sp->name); 473 kfree(sp->name);
439} 474}
440 475
441/* 476/**
442 * Read max. It indicates how many operations there are in queue, either in 477 * host1x_syncpt_read_max() - read maximum syncpoint value
443 * channel or in a software thread. 478 * @sp: host1x syncpoint
479 *
480 * The maximum syncpoint value indicates how many operations there are in
481 * queue, either in channel or in a software thread.
444 */ 482 */
445u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) 483u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
446{ 484{
@@ -450,8 +488,12 @@ u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
450} 488}
451EXPORT_SYMBOL(host1x_syncpt_read_max); 489EXPORT_SYMBOL(host1x_syncpt_read_max);
452 490
453/* 491/**
454 * Read min, which is a shadow of the current sync point value in hardware. 492 * host1x_syncpt_read_min() - read minimum syncpoint value
493 * @sp: host1x syncpoint
494 *
495 * The minimum syncpoint value is a shadow of the current sync point value in
496 * hardware.
455 */ 497 */
456u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) 498u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
457{ 499{
@@ -461,6 +503,10 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
461} 503}
462EXPORT_SYMBOL(host1x_syncpt_read_min); 504EXPORT_SYMBOL(host1x_syncpt_read_min);
463 505
506/**
507 * host1x_syncpt_read() - read the current syncpoint value
508 * @sp: host1x syncpoint
509 */
464u32 host1x_syncpt_read(struct host1x_syncpt *sp) 510u32 host1x_syncpt_read(struct host1x_syncpt *sp)
465{ 511{
466 return host1x_syncpt_load(sp); 512 return host1x_syncpt_load(sp);
@@ -482,6 +528,11 @@ unsigned int host1x_syncpt_nb_mlocks(struct host1x *host)
482 return host->info->nb_mlocks; 528 return host->info->nb_mlocks;
483} 529}
484 530
531/**
532 * host1x_syncpt_get() - obtain a syncpoint by ID
533 * @host: host1x controller
534 * @id: syncpoint ID
535 */
485struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id) 536struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id)
486{ 537{
487 if (id >= host->info->nb_pts) 538 if (id >= host->info->nb_pts)
@@ -491,12 +542,20 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id)
491} 542}
492EXPORT_SYMBOL(host1x_syncpt_get); 543EXPORT_SYMBOL(host1x_syncpt_get);
493 544
545/**
546 * host1x_syncpt_get_base() - obtain the wait base associated with a syncpoint
547 * @sp: host1x syncpoint
548 */
494struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp) 549struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
495{ 550{
496 return sp ? sp->base : NULL; 551 return sp ? sp->base : NULL;
497} 552}
498EXPORT_SYMBOL(host1x_syncpt_get_base); 553EXPORT_SYMBOL(host1x_syncpt_get_base);
499 554
555/**
556 * host1x_syncpt_base_id() - retrieve the ID of a syncpoint wait base
557 * @base: host1x syncpoint wait base
558 */
500u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base) 559u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
501{ 560{
502 return base->id; 561 return base->id;
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 3d04aa1dc83e..630b1a98ab58 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -32,11 +32,27 @@ enum host1x_class {
32 32
33struct host1x_client; 33struct host1x_client;
34 34
35/**
36 * struct host1x_client_ops - host1x client operations
37 * @init: host1x client initialization code
38 * @exit: host1x client tear down code
39 */
35struct host1x_client_ops { 40struct host1x_client_ops {
36 int (*init)(struct host1x_client *client); 41 int (*init)(struct host1x_client *client);
37 int (*exit)(struct host1x_client *client); 42 int (*exit)(struct host1x_client *client);
38}; 43};
39 44
45/**
46 * struct host1x_client - host1x client structure
47 * @list: list node for the host1x client
48 * @parent: pointer to struct device representing the host1x controller
49 * @dev: pointer to struct device backing this host1x client
50 * @ops: host1x client operations
51 * @class: host1x class represented by this client
52 * @channel: host1x channel associated with this client
53 * @syncpts: array of syncpoints requested for this client
54 * @num_syncpts: number of syncpoints requested for this client
55 */
40struct host1x_client { 56struct host1x_client {
41 struct list_head list; 57 struct list_head list;
42 struct device *parent; 58 struct device *parent;
@@ -156,7 +172,6 @@ struct host1x_channel;
156struct host1x_job; 172struct host1x_job;
157 173
158struct host1x_channel *host1x_channel_request(struct device *dev); 174struct host1x_channel *host1x_channel_request(struct device *dev);
159void host1x_channel_free(struct host1x_channel *channel);
160struct host1x_channel *host1x_channel_get(struct host1x_channel *channel); 175struct host1x_channel *host1x_channel_get(struct host1x_channel *channel);
161void host1x_channel_put(struct host1x_channel *channel); 176void host1x_channel_put(struct host1x_channel *channel);
162int host1x_job_submit(struct host1x_job *job); 177int host1x_job_submit(struct host1x_job *job);
@@ -177,6 +192,13 @@ struct host1x_reloc {
177 unsigned long shift; 192 unsigned long shift;
178}; 193};
179 194
195struct host1x_waitchk {
196 struct host1x_bo *bo;
197 u32 offset;
198 u32 syncpt_id;
199 u32 thresh;
200};
201
180struct host1x_job { 202struct host1x_job {
181 /* When refcount goes to zero, job can be freed */ 203 /* When refcount goes to zero, job can be freed */
182 struct kref ref; 204 struct kref ref;
@@ -226,7 +248,10 @@ struct host1x_job {
226 u8 *gather_copy_mapped; 248 u8 *gather_copy_mapped;
227 249
228 /* Check if register is marked as an address reg */ 250 /* Check if register is marked as an address reg */
229 int (*is_addr_reg)(struct device *dev, u32 reg, u32 class); 251 int (*is_addr_reg)(struct device *dev, u32 class, u32 reg);
252
253 /* Check if class belongs to the unit */
254 int (*is_valid_class)(u32 class);
230 255
231 /* Request a SETCLASS to this class */ 256 /* Request a SETCLASS to this class */
232 u32 class; 257 u32 class;
@@ -251,6 +276,15 @@ void host1x_job_unpin(struct host1x_job *job);
251 276
252struct host1x_device; 277struct host1x_device;
253 278
279/**
280 * struct host1x_driver - host1x logical device driver
281 * @driver: core driver
282 * @subdevs: table of OF device IDs matching subdevices for this driver
283 * @list: list node for the driver
284 * @probe: called when the host1x logical device is probed
285 * @remove: called when the host1x logical device is removed
286 * @shutdown: called when the host1x logical device is shut down
287 */
254struct host1x_driver { 288struct host1x_driver {
255 struct device_driver driver; 289 struct device_driver driver;
256 290