提交 796e1c55 编写于 作者: L Linus Torvalds

Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux

Pull drm updates from Dave Airlie:
 "This is the main drm pull, it has a shared branch with some alsa
  crossover but everything should be acked by relevant people.

  New drivers:
     - ATMEL HLCDC driver
     - designware HDMI core support (used in multiple SoCs).

  core:
     - lots more atomic modesetting work, properties and atomic ioctl
       (hidden under option)
     - bridge rework allows support for Samsung exynos chromebooks to
       work finally.
     - some more panels supported

  i915:
     - atomic plane update support
     - DSI uses shared DSI infrastructure
     - Skylake basic support is all merged now
     - component framework used for i915/snd-hda interactions
     - write-combine cpu memory mappings
     - engine init code refactored
     - full ppgtt enabled where execlists are enabled.
     - cherryview rps/gpu turbo and pipe CRC support.

  radeon:
     - indirect draw support for evergreen/cayman
     - SMC and manual fan control for SI/CI
     - Displayport audio support

  amdkfd:
     - SDMA usermode queue support
     - replace suballocator usage with more suitable one
     - rework for allowing interfacing to more than radeon

  nouveau:
     - major renaming in prep for later splitting work
     - merge arm platform driver into nouveau
     - GK20A reclocking support

  msm:
     - conversion to atomic modesetting
     - YUV support for mdp4/5
     - eDP support
     - hw cursor for mdp5

  tegra:
     - conversion to atomic modesetting
     - better suspend/resume support for child devices

  rcar-du:
     - interlaced support

  imx:
     - move to using dw_hdmi shared support
     - mode_fixup support

  sti:
     - DVO support
     - HDMI infoframe support

  exynos:
     - refactoring and cleanup, removed lots of internal unnecessary
       abstraction
     - exynos7 DECON display controller support

  Along with the usual bunch of fixes, cleanups etc"

* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (724 commits)
  drm/radeon: fix voltage setup on hawaii
  drm/radeon/dp: Set EDP_CONFIGURATION_SET for bridge chips if necessary
  drm/radeon: only enable kv/kb dpm interrupts once v3
  drm/radeon: workaround for CP HW bug on CIK
  drm/radeon: Don't try to enable write-combining without PAT
  drm/radeon: use 0-255 rather than 0-100 for pwm fan range
  drm/i915: Clamp efficient frequency to valid range
  drm/i915: Really ignore long HPD pulses on eDP
  drm/exynos: Add DECON driver
  drm/i915: Correct the base value while updating LP_OUTPUT_HOLD in MIPI_PORT_CTRL
  drm/i915: Insert a command barrier on BLT/BSD cache flushes
  drm/i915: Drop vblank wait from intel_dp_link_down
  drm/exynos: fix NULL pointer reference
  drm/exynos: remove exynos_plane_dpms
  drm/exynos: remove mode property of exynos crtc
  drm/exynos: Remove exynos_plane_dpms() call with no effect
  drm/i915: Squelch overzealous uncore reset WARN_ON
  drm/i915: Take runtime pm reference on hangcheck_info
  drm/i915: Correct the IOSF Dev_FN field for IOSF transfers
  drm/exynos: fix DMA_ATTR_NO_KERNEL_MAPPING usage
  ...

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
...@@ -239,6 +239,14 @@ ...@@ -239,6 +239,14 @@
Driver supports dedicated render nodes. Driver supports dedicated render nodes.
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>DRIVER_ATOMIC</term>
<listitem><para>
Driver supports atomic properties. In this case the driver
must implement appropriate obj->atomic_get_property() vfuncs
for any modeset objects with driver specific properties.
</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</sect3> </sect3>
<sect3> <sect3>
...@@ -1377,7 +1385,7 @@ int max_width, max_height;</synopsis> ...@@ -1377,7 +1385,7 @@ int max_width, max_height;</synopsis>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC. Primary DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC. Primary
planes are the planes operated upon by by CRTC modesetting and flipping planes are the planes operated upon by CRTC modesetting and flipping
operations described in <xref linkend="drm-kms-crtcops"/>. operations described in <xref linkend="drm-kms-crtcops"/>.
</listitem> </listitem>
<listitem> <listitem>
...@@ -2362,6 +2370,7 @@ void intel_crt_init(struct drm_device *dev) ...@@ -2362,6 +2370,7 @@ void intel_crt_init(struct drm_device *dev)
</sect2> </sect2>
<sect2> <sect2>
<title>Modeset Helper Functions Reference</title> <title>Modeset Helper Functions Reference</title>
!Iinclude/drm/drm_crtc_helper.h
!Edrivers/gpu/drm/drm_crtc_helper.c !Edrivers/gpu/drm/drm_crtc_helper.c
!Pdrivers/gpu/drm/drm_crtc_helper.c overview !Pdrivers/gpu/drm/drm_crtc_helper.c overview
</sect2> </sect2>
...@@ -2564,8 +2573,8 @@ void intel_crt_init(struct drm_device *dev) ...@@ -2564,8 +2573,8 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Description/Restrictions</td> <td valign="top" >Description/Restrictions</td>
</tr> </tr>
<tr> <tr>
<td rowspan="25" valign="top" >DRM</td> <td rowspan="36" valign="top" >DRM</td>
<td rowspan="4" valign="top" >Generic</td> <td rowspan="5" valign="top" >Connector</td>
<td valign="top" >“EDID”</td> <td valign="top" >“EDID”</td>
<td valign="top" >BLOB | IMMUTABLE</td> <td valign="top" >BLOB | IMMUTABLE</td>
<td valign="top" >0</td> <td valign="top" >0</td>
...@@ -2594,7 +2603,14 @@ void intel_crt_init(struct drm_device *dev) ...@@ -2594,7 +2603,14 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Contains tiling information for a connector.</td> <td valign="top" >Contains tiling information for a connector.</td>
</tr> </tr>
<tr> <tr>
<td rowspan="1" valign="top" >Plane</td> <td valign="top" >“CRTC_ID”</td>
<td valign="top" >OBJECT</td>
<td valign="top" >DRM_MODE_OBJECT_CRTC</td>
<td valign="top" >Connector</td>
<td valign="top" >CRTC that connector is attached to (atomic)</td>
</tr>
<tr>
<td rowspan="11" valign="top" >Plane</td>
<td valign="top" >“type”</td> <td valign="top" >“type”</td>
<td valign="top" >ENUM | IMMUTABLE</td> <td valign="top" >ENUM | IMMUTABLE</td>
<td valign="top" >{ "Overlay", "Primary", "Cursor" }</td> <td valign="top" >{ "Overlay", "Primary", "Cursor" }</td>
...@@ -2602,6 +2618,76 @@ void intel_crt_init(struct drm_device *dev) ...@@ -2602,6 +2618,76 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Plane type</td> <td valign="top" >Plane type</td>
</tr> </tr>
<tr> <tr>
<td valign="top" >“SRC_X”</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout source x coordinate in 16.16 fixed point (atomic)</td>
</tr>
<tr>
<td valign="top" >“SRC_Y”</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout source y coordinate in 16.16 fixed point (atomic)</td>
</tr>
<tr>
<td valign="top" >“SRC_W”</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout source width in 16.16 fixed point (atomic)</td>
</tr>
<tr>
<td valign="top" >“SRC_H”</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout source height in 16.16 fixed point (atomic)</td>
</tr>
<tr>
<td valign="top" >“CRTC_X”</td>
<td valign="top" >SIGNED_RANGE</td>
<td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout CRTC (destination) x coordinate (atomic)</td>
</tr>
<tr>
<td valign="top" >“CRTC_Y”</td>
<td valign="top" >SIGNED_RANGE</td>
<td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout CRTC (destination) y coordinate (atomic)</td>
</tr>
<tr>
<td valign="top" >“CRTC_W”</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout CRTC (destination) width (atomic)</td>
</tr>
<tr>
<td valign="top" >“CRTC_H”</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=UINT_MAX</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout CRTC (destination) height (atomic)</td>
</tr>
<tr>
<td valign="top" >“FB_ID”</td>
<td valign="top" >OBJECT</td>
<td valign="top" >DRM_MODE_OBJECT_FB</td>
<td valign="top" >Plane</td>
<td valign="top" >Scanout framebuffer (atomic)</td>
</tr>
<tr>
<td valign="top" >“CRTC_ID”</td>
<td valign="top" >OBJECT</td>
<td valign="top" >DRM_MODE_OBJECT_CRTC</td>
<td valign="top" >Plane</td>
<td valign="top" >CRTC that plane is attached to (atomic)</td>
</tr>
<tr>
<td rowspan="2" valign="top" >DVI-I</td> <td rowspan="2" valign="top" >DVI-I</td>
<td valign="top" >“subconnector”</td> <td valign="top" >“subconnector”</td>
<td valign="top" >ENUM</td> <td valign="top" >ENUM</td>
...@@ -3883,6 +3969,7 @@ int num_ioctls;</synopsis> ...@@ -3883,6 +3969,7 @@ int num_ioctls;</synopsis>
<title>Runtime Power Management</title> <title>Runtime Power Management</title>
!Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm !Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
!Idrivers/gpu/drm/i915/intel_runtime_pm.c !Idrivers/gpu/drm/i915/intel_runtime_pm.c
!Idrivers/gpu/drm/i915/intel_uncore.c
</sect2> </sect2>
<sect2> <sect2>
<title>Interrupt Handling</title> <title>Interrupt Handling</title>
...@@ -3931,6 +4018,11 @@ int num_ioctls;</synopsis> ...@@ -3931,6 +4018,11 @@ int num_ioctls;</synopsis>
framebuffer compression and panel self refresh. framebuffer compression and panel self refresh.
</para> </para>
</sect2> </sect2>
<sect2>
<title>Atomic Plane Helpers</title>
!Pdrivers/gpu/drm/i915/intel_atomic_plane.c atomic plane helpers
!Idrivers/gpu/drm/i915/intel_atomic_plane.c
</sect2>
<sect2> <sect2>
<title>Output Probing</title> <title>Output Probing</title>
<para> <para>
...@@ -3949,6 +4041,11 @@ int num_ioctls;</synopsis> ...@@ -3949,6 +4041,11 @@ int num_ioctls;</synopsis>
<title>Panel Self Refresh PSR (PSR/SRD)</title> <title>Panel Self Refresh PSR (PSR/SRD)</title>
!Pdrivers/gpu/drm/i915/intel_psr.c Panel Self Refresh (PSR/SRD) !Pdrivers/gpu/drm/i915/intel_psr.c Panel Self Refresh (PSR/SRD)
!Idrivers/gpu/drm/i915/intel_psr.c !Idrivers/gpu/drm/i915/intel_psr.c
</sect2>
<sect2>
<title>Frame Buffer Compression (FBC)</title>
!Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC)
!Idrivers/gpu/drm/i915/intel_fbc.c
</sect2> </sect2>
<sect2> <sect2>
<title>DPIO</title> <title>DPIO</title>
...@@ -4052,12 +4149,33 @@ int num_ioctls;</synopsis> ...@@ -4052,12 +4149,33 @@ int num_ioctls;</synopsis>
<title>Batchbuffer Parsing</title> <title>Batchbuffer Parsing</title>
!Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser !Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser
!Idrivers/gpu/drm/i915/i915_cmd_parser.c !Idrivers/gpu/drm/i915/i915_cmd_parser.c
</sect2>
<sect2>
<title>Batchbuffer Pools</title>
!Pdrivers/gpu/drm/i915/i915_gem_batch_pool.c batch pool
!Idrivers/gpu/drm/i915/i915_gem_batch_pool.c
</sect2> </sect2>
<sect2> <sect2>
<title>Logical Rings, Logical Ring Contexts and Execlists</title> <title>Logical Rings, Logical Ring Contexts and Execlists</title>
!Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists
!Idrivers/gpu/drm/i915/intel_lrc.c !Idrivers/gpu/drm/i915/intel_lrc.c
</sect2> </sect2>
<sect2>
<title>Global GTT views</title>
!Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views
!Idrivers/gpu/drm/i915/i915_gem_gtt.c
</sect2>
<sect2>
<title>Buffer Object Eviction</title>
<para>
This section documents the interface function for evicting buffer
objects to make space available in the virtual gpu address spaces.
Note that this is mostly orthogonal to shrinking buffer objects
caches, which has the goal to make main memory (shared with the gpu
through the unified memory architecture) available.
</para>
!Idrivers/gpu/drm/i915/i915_gem_evict.c
</sect2>
</sect1> </sect1>
<sect1> <sect1>
......
Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
See ../mfd/atmel-hlcdc.txt for more details.
Required properties:
- compatible: value should be "atmel,hlcdc-display-controller"
- pinctrl-names: the pin control state names. Should contain "default".
- pinctrl-0: should contain the default pinctrl states.
- #address-cells: should be set to 1.
- #size-cells: should be set to 0.
Required children nodes:
Children nodes are encoding available output ports and their connections
to external devices using the OF graph reprensentation (see ../graph.txt).
At least one port node is required.
Example:
hlcdc: hlcdc@f0030000 {
compatible = "atmel,sama5d3-hlcdc";
reg = <0xf0030000 0x2000>;
interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
clock-names = "periph_clk","sys_clk", "slow_clk";
status = "disabled";
hlcdc-display-controller {
compatible = "atmel,hlcdc-display-controller";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
#address-cells = <1>;
#size-cells = <0>;
port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
hlcdc_panel_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&panel_input>;
};
};
};
hlcdc_pwm: hlcdc-pwm {
compatible = "atmel,hlcdc-pwm";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcd_pwm>;
#pwm-cells = <3>;
};
};
DesignWare HDMI bridge bindings
Required properties:
- compatible: platform specific such as:
* "snps,dw-hdmi-tx"
* "fsl,imx6q-hdmi"
* "fsl,imx6dl-hdmi"
* "rockchip,rk3288-dw-hdmi"
- reg: Physical base address and length of the controller's registers.
- interrupts: The HDMI interrupt number
- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
as described in Documentation/devicetree/bindings/clock/clock-bindings.txt,
the clocks are soc specific, the clock-names should be "iahb", "isfr"
-port@[X]: SoC specific port nodes with endpoint definitions as defined
in Documentation/devicetree/bindings/media/video-interfaces.txt,
please refer to the SoC specific binding document:
* Documentation/devicetree/bindings/drm/imx/hdmi.txt
* Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
Optional properties
- reg-io-width: the width of the reg:1,4, default set to 1 if not present
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
Example:
hdmi: hdmi@0120000 {
compatible = "fsl,imx6q-hdmi";
reg = <0x00120000 0x9000>;
interrupts = <0 115 0x04>;
gpr = <&gpr>;
clocks = <&clks 123>, <&clks 124>;
clock-names = "iahb", "isfr";
ddc-i2c-bus = <&i2c2>;
port@0 {
reg = <0>;
hdmi_mux_0: endpoint {
remote-endpoint = <&ipu1_di0_hdmi>;
};
};
port@1 {
reg = <1>;
hdmi_mux_1: endpoint {
remote-endpoint = <&ipu1_di1_hdmi>;
};
};
};
ptn3460 bridge bindings
Required properties:
- compatible: "nxp,ptn3460"
- reg: i2c address of the bridge
- powerdown-gpio: OF device-tree gpio specification
- reset-gpio: OF device-tree gpio specification
- edid-emulation: The EDID emulation entry to use
+-------+------------+------------------+
| Value | Resolution | Description |
| 0 | 1024x768 | NXP Generic |
| 1 | 1920x1080 | NXP Generic |
| 2 | 1920x1080 | NXP Generic |
| 3 | 1600x900 | Samsung LTM200KT |
| 4 | 1920x1080 | Samsung LTM230HT |
| 5 | 1366x768 | NXP Generic |
| 6 | 1600x900 | ChiMei M215HGE |
+-------+------------+------------------+
Example:
lvds-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
powerdown-gpio = <&gpy2 5 1 0 0>;
reset-gpio = <&gpx1 5 1 0 0>;
edid-emulation = <5>;
};
...@@ -2,6 +2,8 @@ Qualcomm adreno/snapdragon hdmi output ...@@ -2,6 +2,8 @@ Qualcomm adreno/snapdragon hdmi output
Required properties: Required properties:
- compatible: one of the following - compatible: one of the following
* "qcom,hdmi-tx-8084"
* "qcom,hdmi-tx-8074"
* "qcom,hdmi-tx-8660" * "qcom,hdmi-tx-8660"
* "qcom,hdmi-tx-8960" * "qcom,hdmi-tx-8960"
- reg: Physical base address and length of the controller's registers - reg: Physical base address and length of the controller's registers
......
...@@ -83,6 +83,22 @@ sti-hda: ...@@ -83,6 +83,22 @@ sti-hda:
- clock-names: names of the clocks listed in clocks property in the same - clock-names: names of the clocks listed in clocks property in the same
order. order.
sti-dvo:
Required properties:
must be a child of sti-tvout
- compatible: "st,stih<chip>-dvo"
- reg: Physical base address of the IP registers and length of memory mapped region.
- reg-names: names of the mapped memory regions listed in regs property in
the same order.
- clocks: from common clock binding: handle hardware IP needed clocks, the
number of clocks may depend of the SoC type.
See ../clocks/clock-bindings.txt for details.
- clock-names: names of the clocks listed in clocks property in the same
order.
- pinctrl-0: pin control handle
- pinctrl-name: names of the pin control to use
- sti,panel: phandle of the panel connected to the DVO output
sti-hqvdp: sti-hqvdp:
must be a child of sti-display-subsystem must be a child of sti-display-subsystem
Required properties: Required properties:
...@@ -198,6 +214,19 @@ Example: ...@@ -198,6 +214,19 @@ Example:
clock-names = "pix", "hddac"; clock-names = "pix", "hddac";
clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>; clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
}; };
sti-dvo@8d00400 {
compatible = "st,stih407-dvo";
reg = <0x8d00400 0x200>;
reg-names = "dvo-reg";
clock-names = "dvo_pix", "dvo",
"main_parent", "aux_parent";
clocks = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
<&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dvo>;
sti,panel = <&panel_dvo>;
};
}; };
sti-hqvdp@9c000000 { sti-hqvdp@9c000000 {
......
Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
Required properties:
- compatible: should be "avic,tm070ddh03"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
Required properties:
- compatible: should be "giantplus,gpg48273qs5"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
...@@ -25,6 +25,7 @@ asahi-kasei Asahi Kasei Corp. ...@@ -25,6 +25,7 @@ asahi-kasei Asahi Kasei Corp.
atmel Atmel Corporation atmel Atmel Corporation
auo AU Optronics Corporation auo AU Optronics Corporation
avago Avago Technologies avago Avago Technologies
avic Shanghai AVIC Optoelectronics Co., Ltd.
bosch Bosch Sensortec GmbH bosch Bosch Sensortec GmbH
brcm Broadcom Corporation brcm Broadcom Corporation
buffalo Buffalo, Inc. buffalo Buffalo, Inc.
...@@ -68,6 +69,7 @@ fsl Freescale Semiconductor ...@@ -68,6 +69,7 @@ fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
geniatech Geniatech, Inc. geniatech Geniatech, Inc.
giantplus Giantplus Technology Co., Ltd.
globalscale Globalscale Technologies, Inc. globalscale Globalscale Technologies, Inc.
gmt Global Mixed-mode Technology, Inc. gmt Global Mixed-mode Technology, Inc.
google Google, Inc. google Google, Inc.
...@@ -126,6 +128,7 @@ onnn ON Semiconductor Corp. ...@@ -126,6 +128,7 @@ onnn ON Semiconductor Corp.
opencores OpenCores.org opencores OpenCores.org
ovti OmniVision Technologies ovti OmniVision Technologies
panasonic Panasonic Corporation panasonic Panasonic Corporation
parade Parade Technologies Inc.
pericom Pericom Technology Inc. pericom Pericom Technology Inc.
phytec PHYTEC Messtechnik GmbH phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd picochip Picochip Ltd
......
ps8622-bridge bindings
Required properties:
- compatible: "parade,ps8622" or "parade,ps8625"
- reg: first i2c address of the bridge
- sleep-gpios: OF device-tree gpio specification for PD_ pin.
- reset-gpios: OF device-tree gpio specification for RST_ pin.
Optional properties:
- lane-count: number of DP lanes to use
- use-external-pwm: backlight will be controlled by an external PWM
- video interfaces: Device node can contain video interface port
nodes for panel according to [1].
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
lvds-bridge@48 {
compatible = "parade,ps8622";
reg = <0x48>;
sleep-gpios = <&gpc3 6 1 0 0>;
reset-gpios = <&gpc3 1 1 0 0>;
lane-count = <1>;
ports {
port@0 {
bridge_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
ptn3460 bridge bindings
Required properties:
- compatible: "nxp,ptn3460"
- reg: i2c address of the bridge
- powerdown-gpio: OF device-tree gpio specification for PD_N pin.
- reset-gpio: OF device-tree gpio specification for RST_N pin.
- edid-emulation: The EDID emulation entry to use
+-------+------------+------------------+
| Value | Resolution | Description |
| 0 | 1024x768 | NXP Generic |
| 1 | 1920x1080 | NXP Generic |
| 2 | 1920x1080 | NXP Generic |
| 3 | 1600x900 | Samsung LTM200KT |
| 4 | 1920x1080 | Samsung LTM230HT |
| 5 | 1366x768 | NXP Generic |
| 6 | 1600x900 | ChiMei M215HGE |
+-------+------------+------------------+
- video interfaces: Device node can contain video interface port
nodes for panel according to [1].
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
lvds-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
powerdown-gpio = <&gpy2 5 1 0 0>;
reset-gpio = <&gpx1 5 1 0 0>;
edid-emulation = <5>;
ports {
port@0 {
bridge_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
Rockchip specific extensions to the Synopsys Designware HDMI
================================
Required properties:
- compatible: "rockchip,rk3288-dw-hdmi";
- reg: Physical base address and length of the controller's registers.
- clocks: phandle to hdmi iahb and isfr clocks.
- clock-names: should be "iahb" "isfr"
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- interrupts: HDMI interrupt number
- ports: contain a port node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. For
vopb,set the reg = <0> and set the reg = <1> for vopl.
- reg-io-width: the width of the reg:1,4, the value should be 4 on
rk3288 platform
Optional properties
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
Example:
hdmi: hdmi@ff980000 {
compatible = "rockchip,rk3288-dw-hdmi";
reg = <0xff980000 0x20000>;
reg-io-width = <4>;
ddc-i2c-bus = <&i2c5>;
rockchip,grf = <&grf>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
clock-names = "iahb", "isfr";
status = "disabled";
ports {
hdmi_in: port {
#address-cells = <1>;
#size-cells = <0>;
hdmi_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_hdmi>;
};
hdmi_in_vopl: endpoint@1 {
reg = <1>;
remote-endpoint = <&vopl_out_hdmi>;
};
};
};
};
Device-Tree bindings for Samsung Exynos7 SoC display controller (DECON)
DECON (Display and Enhancement Controller) is the Display Controller for the
Exynos7 series of SoCs which transfers the image data from a video memory
buffer to an external LCD interface.
Required properties:
- compatible: value should be "samsung,exynos7-decon";
- reg: physical base address and length of the DECON registers set.
- interrupt-parent: should be the phandle of the decon controller's
parent interrupt controller.
- interrupts: should contain a list of all DECON IP block interrupts in the
order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
format depends on the interrupt controller used.
- interrupt-names: should contain the interrupt names: "fifo", "vsync",
"lcd_sys", in the same order as they were listed in the interrupts
property.
- pinctrl-0: pin control group to be used for this controller.
- pinctrl-names: must contain a "default" entry.
- clocks: must include clock specifiers corresponding to entries in the
clock-names property.
- clock-names: list of clock names sorted in the same order as the clocks
property. Must contain "pclk_decon0", "aclk_decon0",
"decon0_eclk", "decon0_vclk".
- i80-if-timings: timing configuration for lcd i80 interface support.
Optional Properties:
- samsung,power-domain: a phandle to DECON power domain node.
- display-timings: timing settings for DECON, as described in document [1].
Can be used in case timings cannot be provided otherwise
or to override timings provided by the panel.
[1]: Documentation/devicetree/bindings/video/display-timing.txt
Example:
SoC specific DT entry:
decon@13930000 {
compatible = "samsung,exynos7-decon";
interrupt-parent = <&combiner>;
reg = <0x13930000 0x1000>;
interrupt-names = "lcd_sys", "vsync", "fifo";
interrupts = <0 188 0>, <0 189 0>, <0 190 0>;
clocks = <&clock_disp PCLK_DECON_INT>,
<&clock_disp ACLK_DECON_INT>,
<&clock_disp SCLK_DECON_INT_ECLK>,
<&clock_disp SCLK_DECON_INT_EXTCLKPLL>;
clock-names = "pclk_decon0", "aclk_decon0", "decon0_eclk",
"decon0_vclk";
status = "disabled";
};
Board specific DT entry:
decon@13930000 {
pinctrl-0 = <&lcd_clk &pwm1_out>;
pinctrl-names = "default";
status = "okay";
};
...@@ -66,6 +66,10 @@ Optional properties for dp-controller: ...@@ -66,6 +66,10 @@ Optional properties for dp-controller:
Hotplug detect GPIO. Hotplug detect GPIO.
Indicates which GPIO should be used for hotplug Indicates which GPIO should be used for hotplug
detection detection
-video interfaces: Device node can contain video interface port
nodes according to [1].
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example: Example:
...@@ -105,4 +109,12 @@ Board Specific portion: ...@@ -105,4 +109,12 @@ Board Specific portion:
vsync-len = <6>; vsync-len = <6>;
}; };
}; };
ports {
port@0 {
dp_out: endpoint {
remote-endpoint = <&bridge_in>;
};
};
};
}; };
...@@ -15,6 +15,7 @@ Required properties: ...@@ -15,6 +15,7 @@ Required properties:
a) mixer: Gate of Mixer IP bus clock. a) mixer: Gate of Mixer IP bus clock.
b) sclk_hdmi: HDMI Special clock, one of the two possible inputs of b) sclk_hdmi: HDMI Special clock, one of the two possible inputs of
mixer mux. mixer mux.
c) hdmi: Gate of HDMI IP bus clock, needed together with sclk_hdmi.
Example: Example:
......
...@@ -26,6 +26,10 @@ Required Properties: ...@@ -26,6 +26,10 @@ Required Properties:
per LVDS encoder. The functional clocks must be named "du.x" with "x" per LVDS encoder. The functional clocks must be named "du.x" with "x"
being the channel numerical index. The LVDS clocks must be named being the channel numerical index. The LVDS clocks must be named
"lvds.x" with "x" being the LVDS encoder numerical index. "lvds.x" with "x" being the LVDS encoder numerical index.
- In addition to the functional and encoder clocks, all DU versions also
support externally supplied pixel clocks. Those clocks are optional.
When supplied they must be named "dclkin.x" with "x" being the input
clock numerical index.
Required nodes: Required nodes:
......
...@@ -630,6 +630,8 @@ L: dri-devel@lists.freedesktop.org ...@@ -630,6 +630,8 @@ L: dri-devel@lists.freedesktop.org
T: git git://people.freedesktop.org/~gabbayo/linux.git T: git git://people.freedesktop.org/~gabbayo/linux.git
S: Supported S: Supported
F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/amdkfd/
F: drivers/gpu/drm/amd/include/cik_structs.h
F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h
F: drivers/gpu/drm/radeon/radeon_kfd.c F: drivers/gpu/drm/radeon/radeon_kfd.c
F: drivers/gpu/drm/radeon/radeon_kfd.h F: drivers/gpu/drm/radeon/radeon_kfd.h
F: include/uapi/linux/kfd_ioctl.h F: include/uapi/linux/kfd_ioctl.h
......
...@@ -219,7 +219,10 @@ struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev); ...@@ -219,7 +219,10 @@ struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
/* generic functions for user-populated AGP memory types */ /* generic functions for user-populated AGP memory types */
struct agp_memory *agp_generic_alloc_user(size_t page_count, int type); struct agp_memory *agp_generic_alloc_user(size_t page_count, int type);
void agp_alloc_page_array(size_t size, struct agp_memory *mem); void agp_alloc_page_array(size_t size, struct agp_memory *mem);
void agp_free_page_array(struct agp_memory *mem); static inline void agp_free_page_array(struct agp_memory *mem)
{
kvfree(mem->pages);
}
/* generic routines for agp>=3 */ /* generic routines for agp>=3 */
......
...@@ -98,17 +98,6 @@ void agp_alloc_page_array(size_t size, struct agp_memory *mem) ...@@ -98,17 +98,6 @@ void agp_alloc_page_array(size_t size, struct agp_memory *mem)
} }
EXPORT_SYMBOL(agp_alloc_page_array); EXPORT_SYMBOL(agp_alloc_page_array);
void agp_free_page_array(struct agp_memory *mem)
{
if (is_vmalloc_addr(mem->pages)) {
vfree(mem->pages);
} else {
kfree(mem->pages);
}
}
EXPORT_SYMBOL(agp_free_page_array);
static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
{ {
struct agp_memory *new; struct agp_memory *new;
......
...@@ -225,7 +225,7 @@ static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, ...@@ -225,7 +225,7 @@ static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start,
intel_private.driver->write_entry(addr, intel_private.driver->write_entry(addr,
i, type); i, type);
} }
readl(intel_private.gtt+i-1); wmb();
return 0; return 0;
} }
...@@ -329,7 +329,7 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry, ...@@ -329,7 +329,7 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry,
break; break;
} }
writel(addr | pte_flags, intel_private.gtt + entry); writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
} }
static const struct aper_size_info_fixed intel_fake_agp_sizes[] = { static const struct aper_size_info_fixed intel_fake_agp_sizes[] = {
...@@ -735,7 +735,7 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, ...@@ -735,7 +735,7 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry,
if (flags == AGP_USER_CACHED_MEMORY) if (flags == AGP_USER_CACHED_MEMORY)
pte_flags |= I830_PTE_SYSTEM_CACHED; pte_flags |= I830_PTE_SYSTEM_CACHED;
writel(addr | pte_flags, intel_private.gtt + entry); writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
} }
bool intel_enable_gtt(void) bool intel_enable_gtt(void)
...@@ -858,7 +858,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, ...@@ -858,7 +858,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,
j++; j++;
} }
} }
readl(intel_private.gtt+j-1); wmb();
} }
EXPORT_SYMBOL(intel_gtt_insert_sg_entries); EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
...@@ -875,7 +875,7 @@ static void intel_gtt_insert_pages(unsigned int first_entry, ...@@ -875,7 +875,7 @@ static void intel_gtt_insert_pages(unsigned int first_entry,
intel_private.driver->write_entry(addr, intel_private.driver->write_entry(addr,
j, flags); j, flags);
} }
readl(intel_private.gtt+j-1); wmb();
} }
static int intel_fake_agp_insert_entries(struct agp_memory *mem, static int intel_fake_agp_insert_entries(struct agp_memory *mem,
...@@ -938,7 +938,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) ...@@ -938,7 +938,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
intel_private.driver->write_entry(intel_private.scratch_page_dma, intel_private.driver->write_entry(intel_private.scratch_page_dma,
i, 0); i, 0);
} }
readl(intel_private.gtt+i-1); wmb();
} }
EXPORT_SYMBOL(intel_gtt_clear_range); EXPORT_SYMBOL(intel_gtt_clear_range);
...@@ -1106,7 +1106,7 @@ static void i965_write_entry(dma_addr_t addr, ...@@ -1106,7 +1106,7 @@ static void i965_write_entry(dma_addr_t addr,
/* Shift high bits down */ /* Shift high bits down */
addr |= (addr >> 28) & 0xf0; addr |= (addr >> 28) & 0xf0;
writel(addr | pte_flags, intel_private.gtt + entry); writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
} }
static int i9xx_setup(void) static int i9xx_setup(void)
......
obj-y += drm/ vga/ # drm/tegra depends on host1x, so if both drivers are built-in care must be
# taken to initialize them in the correct order. Link order is the only way
# to ensure this currently.
obj-$(CONFIG_TEGRA_HOST1X) += host1x/ obj-$(CONFIG_TEGRA_HOST1X) += host1x/
obj-y += drm/ vga/
obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
...@@ -62,12 +62,13 @@ config DRM_TTM ...@@ -62,12 +62,13 @@ config DRM_TTM
config DRM_GEM_CMA_HELPER config DRM_GEM_CMA_HELPER
bool bool
depends on DRM depends on DRM && HAVE_DMA_ATTRS
help help
Choose this if you need the GEM CMA helper functions Choose this if you need the GEM CMA helper functions
config DRM_KMS_CMA_HELPER config DRM_KMS_CMA_HELPER
bool bool
depends on DRM && HAVE_DMA_ATTRS
select DRM_GEM_CMA_HELPER select DRM_GEM_CMA_HELPER
select DRM_KMS_FB_HELPER select DRM_KMS_FB_HELPER
select FB_SYS_FILLRECT select FB_SYS_FILLRECT
...@@ -110,7 +111,6 @@ config DRM_RADEON ...@@ -110,7 +111,6 @@ config DRM_RADEON
select HWMON select HWMON
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE select INTERVAL_TREE
select MMU_NOTIFIER
help help
Choose this option if you have an ATI Radeon graphics card. There Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to are both PCI and AGP versions. You don't need to choose this to
...@@ -183,6 +183,8 @@ source "drivers/gpu/drm/cirrus/Kconfig" ...@@ -183,6 +183,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
source "drivers/gpu/drm/armada/Kconfig" source "drivers/gpu/drm/armada/Kconfig"
source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
source "drivers/gpu/drm/rcar-du/Kconfig" source "drivers/gpu/drm/rcar-du/Kconfig"
source "drivers/gpu/drm/shmobile/Kconfig" source "drivers/gpu/drm/shmobile/Kconfig"
......
...@@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ ...@@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o drm_prime.o \ drm_trace_points.o drm_global.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \
drm_modeset_lock.o drm_atomic.o drm_modeset_lock.o drm_atomic.o drm_bridge.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
...@@ -55,6 +55,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/ ...@@ -55,6 +55,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
obj-$(CONFIG_DRM_UDL) += udl/ obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/ obj-$(CONFIG_DRM_AST) += ast/
obj-$(CONFIG_DRM_ARMADA) += armada/ obj-$(CONFIG_DRM_ARMADA) += armada/
obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_DRM_OMAP) += omapdrm/
......
...@@ -7,7 +7,10 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/ ...@@ -7,7 +7,10 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/
amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \
kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \ kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \
kfd_process.o kfd_queue.o kfd_mqd_manager.o \ kfd_process.o kfd_queue.o kfd_mqd_manager.o \
kfd_kernel_queue.o kfd_packet_manager.o \ kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \
kfd_process_queue_manager.o kfd_device_queue_manager.o kfd_kernel_queue.o kfd_kernel_queue_cik.o \
kfd_kernel_queue_vi.o kfd_packet_manager.o \
kfd_process_queue_manager.o kfd_device_queue_manager.o \
kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \
obj-$(CONFIG_HSA_AMD) += amdkfd.o obj-$(CONFIG_HSA_AMD) += amdkfd.o
...@@ -168,6 +168,8 @@ ...@@ -168,6 +168,8 @@
#define IB_ATC_EN (1U << 23) #define IB_ATC_EN (1U << 23)
#define DEFAULT_MIN_IB_AVAIL_SIZE (3U << 20) #define DEFAULT_MIN_IB_AVAIL_SIZE (3U << 20)
#define AQL_ENABLE 1
#define CP_HQD_DEQUEUE_REQUEST 0xC974 #define CP_HQD_DEQUEUE_REQUEST 0xC974
#define DEQUEUE_REQUEST_DRAIN 1 #define DEQUEUE_REQUEST_DRAIN 1
#define DEQUEUE_REQUEST_RESET 2 #define DEQUEUE_REQUEST_RESET 2
...@@ -188,6 +190,17 @@ ...@@ -188,6 +190,17 @@
#define MQD_VMID_MASK (0xf << 0) #define MQD_VMID_MASK (0xf << 0)
#define MQD_CONTROL_PRIV_STATE_EN (1U << 8) #define MQD_CONTROL_PRIV_STATE_EN (1U << 8)
#define SDMA_RB_VMID(x) (x << 24)
#define SDMA_RB_ENABLE (1 << 0)
#define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */
#define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12)
#define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */
#define SDMA_OFFSET(x) (x << 0)
#define SDMA_DB_ENABLE (1 << 28)
#define SDMA_ATC (1 << 0)
#define SDMA_VA_PTR32 (1 << 4)
#define SDMA_VA_SHARED_BASE(x) (x << 8)
#define GRBM_GFX_INDEX 0x30800 #define GRBM_GFX_INDEX 0x30800
#define INSTANCE_INDEX(x) ((x) << 0) #define INSTANCE_INDEX(x) ((x) << 0)
#define SH_INDEX(x) ((x) << 8) #define SH_INDEX(x) ((x) << 8)
......
...@@ -178,6 +178,22 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, ...@@ -178,6 +178,22 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
return -EFAULT; return -EFAULT;
} }
if (args->eop_buffer_address &&
!access_ok(VERIFY_WRITE,
(const void __user *) args->eop_buffer_address,
sizeof(uint32_t))) {
pr_debug("kfd: can't access eop buffer");
return -EFAULT;
}
if (args->ctx_save_restore_address &&
!access_ok(VERIFY_WRITE,
(const void __user *) args->ctx_save_restore_address,
sizeof(uint32_t))) {
pr_debug("kfd: can't access ctx save restore buffer");
return -EFAULT;
}
q_properties->is_interop = false; q_properties->is_interop = false;
q_properties->queue_percent = args->queue_percentage; q_properties->queue_percent = args->queue_percentage;
q_properties->priority = args->queue_priority; q_properties->priority = args->queue_priority;
...@@ -185,9 +201,16 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, ...@@ -185,9 +201,16 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
q_properties->queue_size = args->ring_size; q_properties->queue_size = args->ring_size;
q_properties->read_ptr = (uint32_t *) args->read_pointer_address; q_properties->read_ptr = (uint32_t *) args->read_pointer_address;
q_properties->write_ptr = (uint32_t *) args->write_pointer_address; q_properties->write_ptr = (uint32_t *) args->write_pointer_address;
q_properties->eop_ring_buffer_address = args->eop_buffer_address;
q_properties->eop_ring_buffer_size = args->eop_buffer_size;
q_properties->ctx_save_restore_area_address =
args->ctx_save_restore_address;
q_properties->ctx_save_restore_area_size = args->ctx_save_restore_size;
if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE || if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL) args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
q_properties->type = KFD_QUEUE_TYPE_COMPUTE; q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
else if (args->queue_type == KFD_IOC_QUEUE_TYPE_SDMA)
q_properties->type = KFD_QUEUE_TYPE_SDMA;
else else
return -ENOTSUPP; return -ENOTSUPP;
...@@ -214,6 +237,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, ...@@ -214,6 +237,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
pr_debug("Queue Format (%d)\n", q_properties->format); pr_debug("Queue Format (%d)\n", q_properties->format);
pr_debug("Queue EOP (0x%llX)\n", q_properties->eop_ring_buffer_address);
pr_debug("Queue CTX save arex (0x%llX)\n",
q_properties->ctx_save_restore_area_address);
return 0; return 0;
} }
...@@ -235,9 +263,12 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, ...@@ -235,9 +263,12 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
if (err) if (err)
return err; return err;
pr_debug("kfd: looking for gpu id 0x%x\n", args->gpu_id);
dev = kfd_device_by_id(args->gpu_id); dev = kfd_device_by_id(args->gpu_id);
if (dev == NULL) if (dev == NULL) {
pr_debug("kfd: gpu id 0x%x was not found\n", args->gpu_id);
return -EINVAL; return -EINVAL;
}
mutex_lock(&p->mutex); mutex_lock(&p->mutex);
...@@ -251,8 +282,8 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, ...@@ -251,8 +282,8 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
p->pasid, p->pasid,
dev->id); dev->id);
err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, 0, err = pqm_create_queue(&p->pqm, dev, filep, &q_properties,
KFD_QUEUE_TYPE_COMPUTE, &queue_id); 0, q_properties.type, &queue_id);
if (err != 0) if (err != 0)
goto err_create_queue; goto err_create_queue;
...@@ -385,7 +416,7 @@ static int kfd_ioctl_set_memory_policy(struct file *filep, ...@@ -385,7 +416,7 @@ static int kfd_ioctl_set_memory_policy(struct file *filep,
(args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT) (args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
? cache_policy_coherent : cache_policy_noncoherent; ? cache_policy_coherent : cache_policy_noncoherent;
if (!dev->dqm->set_cache_memory_policy(dev->dqm, if (!dev->dqm->ops.set_cache_memory_policy(dev->dqm,
&pdd->qpd, &pdd->qpd,
default_policy, default_policy,
alternate_policy, alternate_policy,
......
...@@ -31,11 +31,20 @@ ...@@ -31,11 +31,20 @@
#define MQD_SIZE_ALIGNED 768 #define MQD_SIZE_ALIGNED 768
static const struct kfd_device_info kaveri_device_info = { static const struct kfd_device_info kaveri_device_info = {
.asic_family = CHIP_KAVERI,
.max_pasid_bits = 16, .max_pasid_bits = 16,
.ih_ring_entry_size = 4 * sizeof(uint32_t), .ih_ring_entry_size = 4 * sizeof(uint32_t),
.mqd_size_aligned = MQD_SIZE_ALIGNED .mqd_size_aligned = MQD_SIZE_ALIGNED
}; };
static const struct kfd_device_info carrizo_device_info = {
.asic_family = CHIP_CARRIZO,
.max_pasid_bits = 16,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED
};
struct kfd_deviceid { struct kfd_deviceid {
unsigned short did; unsigned short did;
const struct kfd_device_info *device_info; const struct kfd_device_info *device_info;
...@@ -64,9 +73,13 @@ static const struct kfd_deviceid supported_devices[] = { ...@@ -64,9 +73,13 @@ static const struct kfd_deviceid supported_devices[] = {
{ 0x1318, &kaveri_device_info }, /* Kaveri */ { 0x1318, &kaveri_device_info }, /* Kaveri */
{ 0x131B, &kaveri_device_info }, /* Kaveri */ { 0x131B, &kaveri_device_info }, /* Kaveri */
{ 0x131C, &kaveri_device_info }, /* Kaveri */ { 0x131C, &kaveri_device_info }, /* Kaveri */
{ 0x131D, &kaveri_device_info }, /* Kaveri */ { 0x131D, &kaveri_device_info } /* Kaveri */
}; };
static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
unsigned int chunk_size);
static void kfd_gtt_sa_fini(struct kfd_dev *kfd);
static const struct kfd_device_info *lookup_device_info(unsigned short did) static const struct kfd_device_info *lookup_device_info(unsigned short did)
{ {
size_t i; size_t i;
...@@ -173,16 +186,39 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, ...@@ -173,16 +186,39 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
size = max_num_of_queues_per_device * size = max_num_of_queues_per_device *
kfd->device_info->mqd_size_aligned; kfd->device_info->mqd_size_aligned;
/* add another 512KB for all other allocations on gart */ /*
* calculate max size of runlist packet.
* There can be only 2 packets at once
*/
size += (KFD_MAX_NUM_OF_PROCESSES * sizeof(struct pm4_map_process) +
max_num_of_queues_per_device *
sizeof(struct pm4_map_queues) + sizeof(struct pm4_runlist)) * 2;
/* Add size of HIQ & DIQ */
size += KFD_KERNEL_QUEUE_SIZE * 2;
/* add another 512KB for all other allocations on gart (HPD, fences) */
size += 512 * 1024; size += 512 * 1024;
if (kfd2kgd->init_sa_manager(kfd->kgd, size)) { if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
&kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
dev_err(kfd_device, dev_err(kfd_device,
"Error initializing sa manager for device (%x:%x)\n", "Could not allocate %d bytes for device (%x:%x)\n",
kfd->pdev->vendor, kfd->pdev->device); size, kfd->pdev->vendor, kfd->pdev->device);
goto out; goto out;
} }
dev_info(kfd_device,
"Allocated %d bytes on gart for device(%x:%x)\n",
size, kfd->pdev->vendor, kfd->pdev->device);
/* Initialize GTT sa with 512 byte chunk size */
if (kfd_gtt_sa_init(kfd, size, 512) != 0) {
dev_err(kfd_device,
"Error initializing gtt sub-allocator\n");
goto kfd_gtt_sa_init_error;
}
kfd_doorbell_init(kfd); kfd_doorbell_init(kfd);
if (kfd_topology_add_device(kfd) != 0) { if (kfd_topology_add_device(kfd) != 0) {
...@@ -209,7 +245,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, ...@@ -209,7 +245,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
goto device_queue_manager_error; goto device_queue_manager_error;
} }
if (kfd->dqm->start(kfd->dqm) != 0) { if (kfd->dqm->ops.start(kfd->dqm) != 0) {
dev_err(kfd_device, dev_err(kfd_device,
"Error starting queuen manager for device (%x:%x)\n", "Error starting queuen manager for device (%x:%x)\n",
kfd->pdev->vendor, kfd->pdev->device); kfd->pdev->vendor, kfd->pdev->device);
...@@ -232,7 +268,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, ...@@ -232,7 +268,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
device_iommu_pasid_error: device_iommu_pasid_error:
kfd_topology_remove_device(kfd); kfd_topology_remove_device(kfd);
kfd_topology_add_device_error: kfd_topology_add_device_error:
kfd2kgd->fini_sa_manager(kfd->kgd); kfd_gtt_sa_fini(kfd);
kfd_gtt_sa_init_error:
kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
dev_err(kfd_device, dev_err(kfd_device,
"device (%x:%x) NOT added due to errors\n", "device (%x:%x) NOT added due to errors\n",
kfd->pdev->vendor, kfd->pdev->device); kfd->pdev->vendor, kfd->pdev->device);
...@@ -246,6 +284,8 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) ...@@ -246,6 +284,8 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
device_queue_manager_uninit(kfd->dqm); device_queue_manager_uninit(kfd->dqm);
amd_iommu_free_device(kfd->pdev); amd_iommu_free_device(kfd->pdev);
kfd_topology_remove_device(kfd); kfd_topology_remove_device(kfd);
kfd_gtt_sa_fini(kfd);
kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
} }
kfree(kfd); kfree(kfd);
...@@ -256,7 +296,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd) ...@@ -256,7 +296,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd)
BUG_ON(kfd == NULL); BUG_ON(kfd == NULL);
if (kfd->init_complete) { if (kfd->init_complete) {
kfd->dqm->stop(kfd->dqm); kfd->dqm->ops.stop(kfd->dqm);
amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
amd_iommu_free_device(kfd->pdev); amd_iommu_free_device(kfd->pdev);
} }
...@@ -277,7 +317,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd) ...@@ -277,7 +317,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd)
return -ENXIO; return -ENXIO;
amd_iommu_set_invalidate_ctx_cb(kfd->pdev, amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
iommu_pasid_shutdown_callback); iommu_pasid_shutdown_callback);
kfd->dqm->start(kfd->dqm); kfd->dqm->ops.start(kfd->dqm);
} }
return 0; return 0;
...@@ -288,3 +328,188 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry) ...@@ -288,3 +328,188 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
{ {
/* Process interrupts / schedule work as necessary */ /* Process interrupts / schedule work as necessary */
} }
static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
unsigned int chunk_size)
{
unsigned int num_of_bits;
BUG_ON(!kfd);
BUG_ON(!kfd->gtt_mem);
BUG_ON(buf_size < chunk_size);
BUG_ON(buf_size == 0);
BUG_ON(chunk_size == 0);
kfd->gtt_sa_chunk_size = chunk_size;
kfd->gtt_sa_num_of_chunks = buf_size / chunk_size;
num_of_bits = kfd->gtt_sa_num_of_chunks / BITS_PER_BYTE;
BUG_ON(num_of_bits == 0);
kfd->gtt_sa_bitmap = kzalloc(num_of_bits, GFP_KERNEL);
if (!kfd->gtt_sa_bitmap)
return -ENOMEM;
pr_debug("kfd: gtt_sa_num_of_chunks = %d, gtt_sa_bitmap = %p\n",
kfd->gtt_sa_num_of_chunks, kfd->gtt_sa_bitmap);
mutex_init(&kfd->gtt_sa_lock);
return 0;
}
static void kfd_gtt_sa_fini(struct kfd_dev *kfd)
{
mutex_destroy(&kfd->gtt_sa_lock);
kfree(kfd->gtt_sa_bitmap);
}
static inline uint64_t kfd_gtt_sa_calc_gpu_addr(uint64_t start_addr,
unsigned int bit_num,
unsigned int chunk_size)
{
return start_addr + bit_num * chunk_size;
}
static inline uint32_t *kfd_gtt_sa_calc_cpu_addr(void *start_addr,
unsigned int bit_num,
unsigned int chunk_size)
{
return (uint32_t *) ((uint64_t) start_addr + bit_num * chunk_size);
}
int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
struct kfd_mem_obj **mem_obj)
{
unsigned int found, start_search, cur_size;
BUG_ON(!kfd);
if (size == 0)
return -EINVAL;
if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size)
return -ENOMEM;
*mem_obj = kmalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
if ((*mem_obj) == NULL)
return -ENOMEM;
pr_debug("kfd: allocated mem_obj = %p for size = %d\n", *mem_obj, size);
start_search = 0;
mutex_lock(&kfd->gtt_sa_lock);
kfd_gtt_restart_search:
/* Find the first chunk that is free */
found = find_next_zero_bit(kfd->gtt_sa_bitmap,
kfd->gtt_sa_num_of_chunks,
start_search);
pr_debug("kfd: found = %d\n", found);
/* If there wasn't any free chunk, bail out */
if (found == kfd->gtt_sa_num_of_chunks)
goto kfd_gtt_no_free_chunk;
/* Update fields of mem_obj */
(*mem_obj)->range_start = found;
(*mem_obj)->range_end = found;
(*mem_obj)->gpu_addr = kfd_gtt_sa_calc_gpu_addr(
kfd->gtt_start_gpu_addr,
found,
kfd->gtt_sa_chunk_size);
(*mem_obj)->cpu_ptr = kfd_gtt_sa_calc_cpu_addr(
kfd->gtt_start_cpu_ptr,
found,
kfd->gtt_sa_chunk_size);
pr_debug("kfd: gpu_addr = %p, cpu_addr = %p\n",
(uint64_t *) (*mem_obj)->gpu_addr, (*mem_obj)->cpu_ptr);
/* If we need only one chunk, mark it as allocated and get out */
if (size <= kfd->gtt_sa_chunk_size) {
pr_debug("kfd: single bit\n");
set_bit(found, kfd->gtt_sa_bitmap);
goto kfd_gtt_out;
}
/* Otherwise, try to see if we have enough contiguous chunks */
cur_size = size - kfd->gtt_sa_chunk_size;
do {
(*mem_obj)->range_end =
find_next_zero_bit(kfd->gtt_sa_bitmap,
kfd->gtt_sa_num_of_chunks, ++found);
/*
* If next free chunk is not contiguous than we need to
* restart our search from the last free chunk we found (which
* wasn't contiguous to the previous ones
*/
if ((*mem_obj)->range_end != found) {
start_search = found;
goto kfd_gtt_restart_search;
}
/*
* If we reached end of buffer, bail out with error
*/
if (found == kfd->gtt_sa_num_of_chunks)
goto kfd_gtt_no_free_chunk;
/* Check if we don't need another chunk */
if (cur_size <= kfd->gtt_sa_chunk_size)
cur_size = 0;
else
cur_size -= kfd->gtt_sa_chunk_size;
} while (cur_size > 0);
pr_debug("kfd: range_start = %d, range_end = %d\n",
(*mem_obj)->range_start, (*mem_obj)->range_end);
/* Mark the chunks as allocated */
for (found = (*mem_obj)->range_start;
found <= (*mem_obj)->range_end;
found++)
set_bit(found, kfd->gtt_sa_bitmap);
kfd_gtt_out:
mutex_unlock(&kfd->gtt_sa_lock);
return 0;
kfd_gtt_no_free_chunk:
pr_debug("kfd: allocation failed with mem_obj = %p\n", mem_obj);
mutex_unlock(&kfd->gtt_sa_lock);
kfree(mem_obj);
return -ENOMEM;
}
int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj)
{
unsigned int bit;
BUG_ON(!kfd);
/* Act like kfree when trying to free a NULL object */
if (!mem_obj)
return 0;
pr_debug("kfd: free mem_obj = %p, range_start = %d, range_end = %d\n",
mem_obj, mem_obj->range_start, mem_obj->range_end);
mutex_lock(&kfd->gtt_sa_lock);
/* Mark the chunks as free */
for (bit = mem_obj->range_start;
bit <= mem_obj->range_end;
bit++)
clear_bit(bit, kfd->gtt_sa_bitmap);
mutex_unlock(&kfd->gtt_sa_lock);
kfree(mem_obj);
return 0;
}
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#define KFD_VMID_START_OFFSET (8) #define KFD_VMID_START_OFFSET (8)
#define VMID_PER_DEVICE CIK_VMID_NUM #define VMID_PER_DEVICE CIK_VMID_NUM
#define KFD_DQM_FIRST_PIPE (0) #define KFD_DQM_FIRST_PIPE (0)
#define CIK_SDMA_QUEUES (4)
#define CIK_SDMA_QUEUES_PER_ENGINE (2)
#define CIK_SDMA_ENGINE_NUM (2)
struct device_process_node { struct device_process_node {
struct qcm_process_device *qpd; struct qcm_process_device *qpd;
...@@ -43,7 +46,7 @@ struct device_process_node { ...@@ -43,7 +46,7 @@ struct device_process_node {
}; };
/** /**
* struct device_queue_manager * struct device_queue_manager_ops
* *
* @create_queue: Queue creation routine. * @create_queue: Queue creation routine.
* *
...@@ -78,15 +81,9 @@ struct device_process_node { ...@@ -78,15 +81,9 @@ struct device_process_node {
* @set_cache_memory_policy: Sets memory policy (cached/ non cached) for the * @set_cache_memory_policy: Sets memory policy (cached/ non cached) for the
* memory apertures. * memory apertures.
* *
* This struct is a base class for the kfd queues scheduler in the
* device level. The device base class should expose the basic operations
* for queue creation and queue destruction. This base class hides the
* scheduling mode of the driver and the specific implementation of the
* concrete device. This class is the only class in the queues scheduler
* that configures the H/W.
*/ */
struct device_queue_manager { struct device_queue_manager_ops {
int (*create_queue)(struct device_queue_manager *dqm, int (*create_queue)(struct device_queue_manager *dqm,
struct queue *q, struct queue *q,
struct qcm_process_device *qpd, struct qcm_process_device *qpd,
...@@ -121,7 +118,23 @@ struct device_queue_manager { ...@@ -121,7 +118,23 @@ struct device_queue_manager {
enum cache_policy alternate_policy, enum cache_policy alternate_policy,
void __user *alternate_aperture_base, void __user *alternate_aperture_base,
uint64_t alternate_aperture_size); uint64_t alternate_aperture_size);
};
/**
* struct device_queue_manager
*
* This struct is a base class for the kfd queues scheduler in the
* device level. The device base class should expose the basic operations
* for queue creation and queue destruction. This base class hides the
* scheduling mode of the driver and the specific implementation of the
* concrete device. This class is the only class in the queues scheduler
* that configures the H/W.
*
*/
struct device_queue_manager {
struct device_queue_manager_ops ops;
struct device_queue_manager_ops ops_asic_specific;
struct mqd_manager *mqds[KFD_MQD_TYPE_MAX]; struct mqd_manager *mqds[KFD_MQD_TYPE_MAX];
struct packet_manager packets; struct packet_manager packets;
...@@ -130,9 +143,11 @@ struct device_queue_manager { ...@@ -130,9 +143,11 @@ struct device_queue_manager {
struct list_head queues; struct list_head queues;
unsigned int processes_count; unsigned int processes_count;
unsigned int queue_count; unsigned int queue_count;
unsigned int sdma_queue_count;
unsigned int total_queue_count; unsigned int total_queue_count;
unsigned int next_pipe_to_allocate; unsigned int next_pipe_to_allocate;
unsigned int *allocated_queues; unsigned int *allocated_queues;
unsigned int sdma_bitmap;
unsigned int vmid_bitmap; unsigned int vmid_bitmap;
uint64_t pipelines_addr; uint64_t pipelines_addr;
struct kfd_mem_obj *pipeline_mem; struct kfd_mem_obj *pipeline_mem;
...@@ -142,6 +157,28 @@ struct device_queue_manager { ...@@ -142,6 +157,28 @@ struct device_queue_manager {
bool active_runlist; bool active_runlist;
}; };
void device_queue_manager_init_cik(struct device_queue_manager_ops *ops);
void device_queue_manager_init_vi(struct device_queue_manager_ops *ops);
void program_sh_mem_settings(struct device_queue_manager *dqm,
struct qcm_process_device *qpd);
int init_pipelines(struct device_queue_manager *dqm,
unsigned int pipes_num, unsigned int first_pipe);
extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
{
return (pdd->lds_base >> 16) & 0xFF;
}
extern inline unsigned int
get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
{
return (pdd->lds_base >> 60) & 0x0E;
}
extern inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
{
BUG_ON(!dqm || !dqm->dev);
return dqm->dev->shared_resources.compute_pipe_count;
}
#endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */ #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "kfd_device_queue_manager.h"
#include "cik_regs.h"
static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
struct qcm_process_device *qpd,
enum cache_policy default_policy,
enum cache_policy alternate_policy,
void __user *alternate_aperture_base,
uint64_t alternate_aperture_size);
static int register_process_cik(struct device_queue_manager *dqm,
struct qcm_process_device *qpd);
static int initialize_cpsch_cik(struct device_queue_manager *dqm);
void device_queue_manager_init_cik(struct device_queue_manager_ops *ops)
{
ops->set_cache_memory_policy = set_cache_memory_policy_cik;
ops->register_process = register_process_cik;
ops->initialize = initialize_cpsch_cik;
}
static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
{
/* In 64-bit mode, we can only control the top 3 bits of the LDS,
* scratch and GPUVM apertures.
* The hardware fills in the remaining 59 bits according to the
* following pattern:
* LDS: X0000000'00000000 - X0000001'00000000 (4GB)
* Scratch: X0000001'00000000 - X0000002'00000000 (4GB)
* GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB)
*
* (where X/Y is the configurable nybble with the low-bit 0)
*
* LDS and scratch will have the same top nybble programmed in the
* top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
* GPUVM can have a different top nybble programmed in the
* top 3 bits of SH_MEM_BASES.SHARED_BASE.
* We don't bother to support different top nybbles
* for LDS/Scratch and GPUVM.
*/
BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
top_address_nybble == 0);
return PRIVATE_BASE(top_address_nybble << 12) |
SHARED_BASE(top_address_nybble << 12);
}
static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
struct qcm_process_device *qpd,
enum cache_policy default_policy,
enum cache_policy alternate_policy,
void __user *alternate_aperture_base,
uint64_t alternate_aperture_size)
{
uint32_t default_mtype;
uint32_t ape1_mtype;
default_mtype = (default_policy == cache_policy_coherent) ?
MTYPE_NONCACHED :
MTYPE_CACHED;
ape1_mtype = (alternate_policy == cache_policy_coherent) ?
MTYPE_NONCACHED :
MTYPE_CACHED;
qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
| ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
| DEFAULT_MTYPE(default_mtype)
| APE1_MTYPE(ape1_mtype);
return true;
}
static int register_process_cik(struct device_queue_manager *dqm,
struct qcm_process_device *qpd)
{
struct kfd_process_device *pdd;
unsigned int temp;
BUG_ON(!dqm || !qpd);
pdd = qpd_to_pdd(qpd);
/* check if sh_mem_config register already configured */
if (qpd->sh_mem_config == 0) {
qpd->sh_mem_config =
ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
DEFAULT_MTYPE(MTYPE_NONCACHED) |
APE1_MTYPE(MTYPE_NONCACHED);
qpd->sh_mem_ape1_limit = 0;
qpd->sh_mem_ape1_base = 0;
}
if (qpd->pqm->process->is_32bit_user_mode) {
temp = get_sh_mem_bases_32(pdd);
qpd->sh_mem_bases = SHARED_BASE(temp);
qpd->sh_mem_config |= PTR32;
} else {
temp = get_sh_mem_bases_nybble_64(pdd);
qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
}
pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
return 0;
}
static int initialize_cpsch_cik(struct device_queue_manager *dqm)
{
return init_pipelines(dqm, get_pipes_num(dqm), 0);
}
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "kfd_device_queue_manager.h"
static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
struct qcm_process_device *qpd,
enum cache_policy default_policy,
enum cache_policy alternate_policy,
void __user *alternate_aperture_base,
uint64_t alternate_aperture_size);
static int register_process_vi(struct device_queue_manager *dqm,
struct qcm_process_device *qpd);
static int initialize_cpsch_vi(struct device_queue_manager *dqm);
void device_queue_manager_init_vi(struct device_queue_manager_ops *ops)
{
pr_warn("amdkfd: VI DQM is not currently supported\n");
ops->set_cache_memory_policy = set_cache_memory_policy_vi;
ops->register_process = register_process_vi;
ops->initialize = initialize_cpsch_vi;
}
static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
struct qcm_process_device *qpd,
enum cache_policy default_policy,
enum cache_policy alternate_policy,
void __user *alternate_aperture_base,
uint64_t alternate_aperture_size)
{
return false;
}
static int register_process_vi(struct device_queue_manager *dqm,
struct qcm_process_device *qpd)
{
return -1;
}
static int initialize_cpsch_vi(struct device_queue_manager *dqm)
{
return 0;
}
...@@ -137,10 +137,6 @@ int kfd_doorbell_mmap(struct kfd_process *process, struct vm_area_struct *vma) ...@@ -137,10 +137,6 @@ int kfd_doorbell_mmap(struct kfd_process *process, struct vm_area_struct *vma)
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
/* Find if pdd exists for combination of process and gpu id */
if (!kfd_get_process_device_data(dev, process, 0))
return -EINVAL;
/* Calculate physical address of doorbell */ /* Calculate physical address of doorbell */
address = kfd_get_process_doorbells(dev, process); address = kfd_get_process_doorbells(dev, process);
......
...@@ -303,10 +303,11 @@ int kfd_init_apertures(struct kfd_process *process) ...@@ -303,10 +303,11 @@ int kfd_init_apertures(struct kfd_process *process)
while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL && while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL &&
id < NUM_OF_SUPPORTED_GPUS) { id < NUM_OF_SUPPORTED_GPUS) {
pdd = kfd_get_process_device_data(dev, process, 1); pdd = kfd_create_process_device_data(dev, process);
if (!pdd) if (pdd == NULL) {
pr_err("Failed to create process device data\n");
return -1; return -1;
}
/* /*
* For 64 bit process aperture will be statically reserved in * For 64 bit process aperture will be statically reserved in
* the x86_64 non canonical process address space * the x86_64 non canonical process address space
......
...@@ -56,8 +56,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, ...@@ -56,8 +56,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
switch (type) { switch (type) {
case KFD_QUEUE_TYPE_DIQ: case KFD_QUEUE_TYPE_DIQ:
case KFD_QUEUE_TYPE_HIQ: case KFD_QUEUE_TYPE_HIQ:
kq->mqd = dev->dqm->get_mqd_manager(dev->dqm, kq->mqd = dev->dqm->ops.get_mqd_manager(dev->dqm,
KFD_MQD_TYPE_CIK_HIQ); KFD_MQD_TYPE_HIQ);
break; break;
default: default:
BUG(); BUG();
...@@ -72,23 +72,19 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, ...@@ -72,23 +72,19 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
if (prop.doorbell_ptr == NULL) if (prop.doorbell_ptr == NULL)
goto err_get_kernel_doorbell; goto err_get_kernel_doorbell;
retval = kfd2kgd->allocate_mem(dev->kgd, retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
queue_size,
PAGE_SIZE,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) &kq->pq);
if (retval != 0) if (retval != 0)
goto err_pq_allocate_vidmem; goto err_pq_allocate_vidmem;
kq->pq_kernel_addr = kq->pq->cpu_ptr; kq->pq_kernel_addr = kq->pq->cpu_ptr;
kq->pq_gpu_addr = kq->pq->gpu_addr; kq->pq_gpu_addr = kq->pq->gpu_addr;
retval = kfd2kgd->allocate_mem(dev->kgd, retval = kq->ops_asic_specific.initialize(kq, dev, type, queue_size);
sizeof(*kq->rptr_kernel), if (retval == false)
32, goto err_eop_allocate_vidmem;
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) &kq->rptr_mem); retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->rptr_kernel),
&kq->rptr_mem);
if (retval != 0) if (retval != 0)
goto err_rptr_allocate_vidmem; goto err_rptr_allocate_vidmem;
...@@ -96,11 +92,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, ...@@ -96,11 +92,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
kq->rptr_kernel = kq->rptr_mem->cpu_ptr; kq->rptr_kernel = kq->rptr_mem->cpu_ptr;
kq->rptr_gpu_addr = kq->rptr_mem->gpu_addr; kq->rptr_gpu_addr = kq->rptr_mem->gpu_addr;
retval = kfd2kgd->allocate_mem(dev->kgd, retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->wptr_kernel),
sizeof(*kq->wptr_kernel), &kq->wptr_mem);
32,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) &kq->wptr_mem);
if (retval != 0) if (retval != 0)
goto err_wptr_allocate_vidmem; goto err_wptr_allocate_vidmem;
...@@ -121,6 +114,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, ...@@ -121,6 +114,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
prop.queue_address = kq->pq_gpu_addr; prop.queue_address = kq->pq_gpu_addr;
prop.read_ptr = (uint32_t *) kq->rptr_gpu_addr; prop.read_ptr = (uint32_t *) kq->rptr_gpu_addr;
prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr; prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr;
prop.eop_ring_buffer_address = kq->eop_gpu_addr;
prop.eop_ring_buffer_size = PAGE_SIZE;
if (init_queue(&kq->queue, prop) != 0) if (init_queue(&kq->queue, prop) != 0)
goto err_init_queue; goto err_init_queue;
...@@ -145,11 +140,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, ...@@ -145,11 +140,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
} else { } else {
/* allocate fence for DIQ */ /* allocate fence for DIQ */
retval = kfd2kgd->allocate_mem(dev->kgd, retval = kfd_gtt_sa_allocate(dev, sizeof(uint32_t),
sizeof(uint32_t), &kq->fence_mem_obj);
32,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) &kq->fence_mem_obj);
if (retval != 0) if (retval != 0)
goto err_alloc_fence; goto err_alloc_fence;
...@@ -165,11 +157,13 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, ...@@ -165,11 +157,13 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
err_init_mqd: err_init_mqd:
uninit_queue(kq->queue); uninit_queue(kq->queue);
err_init_queue: err_init_queue:
kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->wptr_mem); kfd_gtt_sa_free(dev, kq->wptr_mem);
err_wptr_allocate_vidmem: err_wptr_allocate_vidmem:
kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->rptr_mem); kfd_gtt_sa_free(dev, kq->rptr_mem);
err_rptr_allocate_vidmem: err_rptr_allocate_vidmem:
kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->pq); kfd_gtt_sa_free(dev, kq->eop_mem);
err_eop_allocate_vidmem:
kfd_gtt_sa_free(dev, kq->pq);
err_pq_allocate_vidmem: err_pq_allocate_vidmem:
pr_err("kfd: error init pq\n"); pr_err("kfd: error init pq\n");
kfd_release_kernel_doorbell(dev, prop.doorbell_ptr); kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
...@@ -190,10 +184,13 @@ static void uninitialize(struct kernel_queue *kq) ...@@ -190,10 +184,13 @@ static void uninitialize(struct kernel_queue *kq)
QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS, QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
kq->queue->pipe, kq->queue->pipe,
kq->queue->queue); kq->queue->queue);
else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->rptr_mem); kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->wptr_mem); kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->pq); kq->ops_asic_specific.uninitialize(kq);
kfd_gtt_sa_free(kq->dev, kq->pq);
kfd_release_kernel_doorbell(kq->dev, kfd_release_kernel_doorbell(kq->dev,
kq->queue->properties.doorbell_ptr); kq->queue->properties.doorbell_ptr);
uninit_queue(kq->queue); uninit_queue(kq->queue);
...@@ -265,28 +262,6 @@ static void submit_packet(struct kernel_queue *kq) ...@@ -265,28 +262,6 @@ static void submit_packet(struct kernel_queue *kq)
kq->pending_wptr); kq->pending_wptr);
} }
static int sync_with_hw(struct kernel_queue *kq, unsigned long timeout_ms)
{
unsigned long org_timeout_ms;
BUG_ON(!kq);
org_timeout_ms = timeout_ms;
timeout_ms += jiffies * 1000 / HZ;
while (*kq->wptr_kernel != *kq->rptr_kernel) {
if (time_after(jiffies * 1000 / HZ, timeout_ms)) {
pr_err("kfd: kernel_queue %s timeout expired %lu\n",
__func__, org_timeout_ms);
pr_err("kfd: wptr: %d rptr: %d\n",
*kq->wptr_kernel, *kq->rptr_kernel);
return -ETIME;
}
schedule();
}
return 0;
}
static void rollback_packet(struct kernel_queue *kq) static void rollback_packet(struct kernel_queue *kq)
{ {
BUG_ON(!kq); BUG_ON(!kq);
...@@ -304,14 +279,23 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, ...@@ -304,14 +279,23 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
if (!kq) if (!kq)
return NULL; return NULL;
kq->initialize = initialize; kq->ops.initialize = initialize;
kq->uninitialize = uninitialize; kq->ops.uninitialize = uninitialize;
kq->acquire_packet_buffer = acquire_packet_buffer; kq->ops.acquire_packet_buffer = acquire_packet_buffer;
kq->submit_packet = submit_packet; kq->ops.submit_packet = submit_packet;
kq->sync_with_hw = sync_with_hw; kq->ops.rollback_packet = rollback_packet;
kq->rollback_packet = rollback_packet;
switch (dev->device_info->asic_family) {
case CHIP_CARRIZO:
kernel_queue_init_vi(&kq->ops_asic_specific);
break;
case CHIP_KAVERI:
kernel_queue_init_cik(&kq->ops_asic_specific);
break;
}
if (kq->initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) { if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
pr_err("kfd: failed to init kernel queue\n"); pr_err("kfd: failed to init kernel queue\n");
kfree(kq); kfree(kq);
return NULL; return NULL;
...@@ -323,7 +307,7 @@ void kernel_queue_uninit(struct kernel_queue *kq) ...@@ -323,7 +307,7 @@ void kernel_queue_uninit(struct kernel_queue *kq)
{ {
BUG_ON(!kq); BUG_ON(!kq);
kq->uninitialize(kq); kq->ops.uninitialize(kq);
kfree(kq); kfree(kq);
} }
...@@ -335,19 +319,18 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev) ...@@ -335,19 +319,18 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
BUG_ON(!dev); BUG_ON(!dev);
pr_debug("kfd: starting kernel queue test\n"); pr_err("kfd: starting kernel queue test\n");
kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ); kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
BUG_ON(!kq); BUG_ON(!kq);
retval = kq->acquire_packet_buffer(kq, 5, &buffer); retval = kq->ops.acquire_packet_buffer(kq, 5, &buffer);
BUG_ON(retval != 0); BUG_ON(retval != 0);
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
buffer[i] = kq->nop_packet; buffer[i] = kq->nop_packet;
kq->submit_packet(kq); kq->ops.submit_packet(kq);
kq->sync_with_hw(kq, 1000);
pr_debug("kfd: ending kernel queue test\n"); pr_err("kfd: ending kernel queue test\n");
} }
...@@ -28,8 +28,31 @@ ...@@ -28,8 +28,31 @@
#include <linux/types.h> #include <linux/types.h>
#include "kfd_priv.h" #include "kfd_priv.h"
struct kernel_queue { /**
/* interface */ * struct kernel_queue_ops
*
* @initialize: Initialize a kernel queue, including allocations of GART memory
* needed for the queue.
*
* @uninitialize: Uninitialize a kernel queue and free all its memory usages.
*
* @acquire_packet_buffer: Returns a pointer to the location in the kernel
* queue ring buffer where the calling function can write its packet. It is
* Guaranteed that there is enough space for that packet. It also updates the
* pending write pointer to that location so subsequent calls to
* acquire_packet_buffer will get a correct write pointer
*
* @submit_packet: Update the write pointer and doorbell of a kernel queue.
*
* @sync_with_hw: Wait until the write pointer and the read pointer of a kernel
* queue are equal, which means the CP has read all the submitted packets.
*
* @rollback_packet: This routine is called if we failed to build an acquired
* packet for some reason. It just overwrites the pending wptr with the current
* one
*
*/
struct kernel_queue_ops {
bool (*initialize)(struct kernel_queue *kq, struct kfd_dev *dev, bool (*initialize)(struct kernel_queue *kq, struct kfd_dev *dev,
enum kfd_queue_type type, unsigned int queue_size); enum kfd_queue_type type, unsigned int queue_size);
void (*uninitialize)(struct kernel_queue *kq); void (*uninitialize)(struct kernel_queue *kq);
...@@ -38,9 +61,12 @@ struct kernel_queue { ...@@ -38,9 +61,12 @@ struct kernel_queue {
unsigned int **buffer_ptr); unsigned int **buffer_ptr);
void (*submit_packet)(struct kernel_queue *kq); void (*submit_packet)(struct kernel_queue *kq);
int (*sync_with_hw)(struct kernel_queue *kq,
unsigned long timeout_ms);
void (*rollback_packet)(struct kernel_queue *kq); void (*rollback_packet)(struct kernel_queue *kq);
};
struct kernel_queue {
struct kernel_queue_ops ops;
struct kernel_queue_ops ops_asic_specific;
/* data */ /* data */
struct kfd_dev *dev; struct kfd_dev *dev;
...@@ -58,6 +84,9 @@ struct kernel_queue { ...@@ -58,6 +84,9 @@ struct kernel_queue {
struct kfd_mem_obj *pq; struct kfd_mem_obj *pq;
uint64_t pq_gpu_addr; uint64_t pq_gpu_addr;
uint32_t *pq_kernel_addr; uint32_t *pq_kernel_addr;
struct kfd_mem_obj *eop_mem;
uint64_t eop_gpu_addr;
uint32_t *eop_kernel_addr;
struct kfd_mem_obj *fence_mem_obj; struct kfd_mem_obj *fence_mem_obj;
uint64_t fence_gpu_addr; uint64_t fence_gpu_addr;
...@@ -66,4 +95,7 @@ struct kernel_queue { ...@@ -66,4 +95,7 @@ struct kernel_queue {
struct list_head list; struct list_head list;
}; };
void kernel_queue_init_cik(struct kernel_queue_ops *ops);
void kernel_queue_init_vi(struct kernel_queue_ops *ops);
#endif /* KFD_KERNEL_QUEUE_H_ */ #endif /* KFD_KERNEL_QUEUE_H_ */
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "kfd_kernel_queue.h"
static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev,
enum kfd_queue_type type, unsigned int queue_size);
static void uninitialize_cik(struct kernel_queue *kq);
void kernel_queue_init_cik(struct kernel_queue_ops *ops)
{
ops->initialize = initialize_cik;
ops->uninitialize = uninitialize_cik;
}
static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev,
enum kfd_queue_type type, unsigned int queue_size)
{
return true;
}
static void uninitialize_cik(struct kernel_queue *kq)
{
}
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "kfd_kernel_queue.h"
static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev,
enum kfd_queue_type type, unsigned int queue_size);
static void uninitialize_vi(struct kernel_queue *kq);
void kernel_queue_init_vi(struct kernel_queue_ops *ops)
{
ops->initialize = initialize_vi;
ops->uninitialize = uninitialize_vi;
}
static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev,
enum kfd_queue_type type, unsigned int queue_size)
{
int retval;
retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem);
if (retval != 0)
return false;
kq->eop_gpu_addr = kq->eop_mem->gpu_addr;
kq->eop_kernel_addr = kq->eop_mem->cpu_ptr;
memset(kq->eop_kernel_addr, 0, PAGE_SIZE);
return true;
}
static void uninitialize_vi(struct kernel_queue *kq)
{
kfd_gtt_sa_free(kq->dev, kq->eop_mem);
}
...@@ -29,10 +29,10 @@ ...@@ -29,10 +29,10 @@
#define KFD_DRIVER_AUTHOR "AMD Inc. and others" #define KFD_DRIVER_AUTHOR "AMD Inc. and others"
#define KFD_DRIVER_DESC "Standalone HSA driver for AMD's GPUs" #define KFD_DRIVER_DESC "Standalone HSA driver for AMD's GPUs"
#define KFD_DRIVER_DATE "20141113" #define KFD_DRIVER_DATE "20150122"
#define KFD_DRIVER_MAJOR 0 #define KFD_DRIVER_MAJOR 0
#define KFD_DRIVER_MINOR 7 #define KFD_DRIVER_MINOR 7
#define KFD_DRIVER_PATCHLEVEL 0 #define KFD_DRIVER_PATCHLEVEL 1
const struct kfd2kgd_calls *kfd2kgd; const struct kfd2kgd_calls *kfd2kgd;
static const struct kgd2kfd_calls kgd2kfd = { static const struct kgd2kfd_calls kgd2kfd = {
...@@ -48,7 +48,7 @@ static const struct kgd2kfd_calls kgd2kfd = { ...@@ -48,7 +48,7 @@ static const struct kgd2kfd_calls kgd2kfd = {
int sched_policy = KFD_SCHED_POLICY_HWS; int sched_policy = KFD_SCHED_POLICY_HWS;
module_param(sched_policy, int, 0444); module_param(sched_policy, int, 0444);
MODULE_PARM_DESC(sched_policy, MODULE_PARM_DESC(sched_policy,
"Kernel cmdline parameter that defines the amdkfd scheduling policy"); "Scheduling policy (0 = HWS (Default), 1 = HWS without over-subscription, 2 = Non-HWS (Used for debugging only)");
int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT; int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT;
module_param(max_num_of_queues_per_device, int, 0444); module_param(max_num_of_queues_per_device, int, 0444);
......
...@@ -21,326 +21,17 @@ ...@@ -21,326 +21,17 @@
* *
*/ */
#include <linux/printk.h>
#include <linux/slab.h>
#include "kfd_priv.h" #include "kfd_priv.h"
#include "kfd_mqd_manager.h"
#include "cik_regs.h"
#include "../../radeon/cik_reg.h"
inline void busy_wait(unsigned long ms)
{
while (time_before(jiffies, ms))
cpu_relax();
}
static inline struct cik_mqd *get_mqd(void *mqd)
{
return (struct cik_mqd *)mqd;
}
static int init_mqd(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *q)
{
uint64_t addr;
struct cik_mqd *m;
int retval;
BUG_ON(!mm || !q || !mqd);
pr_debug("kfd: In func %s\n", __func__);
retval = kfd2kgd->allocate_mem(mm->dev->kgd,
sizeof(struct cik_mqd),
256,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) mqd_mem_obj);
if (retval != 0)
return -ENOMEM;
m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
addr = (*mqd_mem_obj)->gpu_addr;
memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
m->header = 0xC0310800;
m->compute_pipelinestat_enable = 1;
m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
/*
* Make sure to use the last queue state saved on mqd when the cp
* reassigns the queue, so when queue is switched on/off (e.g over
* subscription or quantum timeout) the context will be consistent
*/
m->cp_hqd_persistent_state =
DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
/* Although WinKFD writes this, I suspect it should not be necessary */
m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
QUANTUM_DURATION(10);
/*
* Pipe Priority
* Identifies the pipe relative priority when this queue is connected
* to the pipeline. The pipe priority is against the GFX pipe and HP3D.
* In KFD we are using a fixed pipe priority set to CS_MEDIUM.
* 0 = CS_LOW (typically below GFX)
* 1 = CS_MEDIUM (typically between HP3D and GFX
* 2 = CS_HIGH (typically above HP3D)
*/
m->cp_hqd_pipe_priority = 1;
m->cp_hqd_queue_priority = 15;
*mqd = m;
if (gart_addr != NULL)
*gart_addr = addr;
retval = mm->update_mqd(mm, m, q);
return retval;
}
static void uninit_mqd(struct mqd_manager *mm, void *mqd,
struct kfd_mem_obj *mqd_mem_obj)
{
BUG_ON(!mm || !mqd);
kfd2kgd->free_mem(mm->dev->kgd, (struct kgd_mem *) mqd_mem_obj);
}
static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr)
{
return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
}
static int update_mqd(struct mqd_manager *mm, void *mqd,
struct queue_properties *q)
{
struct cik_mqd *m;
BUG_ON(!mm || !q || !mqd);
pr_debug("kfd: In func %s\n", __func__);
m = get_mqd(mqd);
m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
/*
* Calculating queue size which is log base 2 of actual queue size -1
* dwords and another -1 for ffs
*/
m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
- 1 - 1;
m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
DOORBELL_OFFSET(q->doorbell_off);
m->cp_hqd_vmid = q->vmid;
if (q->format == KFD_QUEUE_FORMAT_AQL) {
m->cp_hqd_iq_rptr = AQL_ENABLE;
m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
}
m->cp_hqd_active = 0;
q->is_active = false;
if (q->queue_size > 0 &&
q->queue_address != 0 &&
q->queue_percent > 0) {
m->cp_hqd_active = 1;
q->is_active = true;
}
return 0;
}
static int destroy_mqd(struct mqd_manager *mm, void *mqd,
enum kfd_preempt_type type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id)
{
return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
pipe_id, queue_id);
}
static bool is_occupied(struct mqd_manager *mm, void *mqd,
uint64_t queue_address, uint32_t pipe_id,
uint32_t queue_id)
{
return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
pipe_id, queue_id);
}
/*
* HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
* The HIQ queue in Kaveri is using the same MQD structure as all the user mode
* queues but with different initial values.
*/
static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *q)
{
uint64_t addr;
struct cik_mqd *m;
int retval;
BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
pr_debug("kfd: In func %s\n", __func__);
retval = kfd2kgd->allocate_mem(mm->dev->kgd,
sizeof(struct cik_mqd),
256,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) mqd_mem_obj);
if (retval != 0)
return -ENOMEM;
m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
addr = (*mqd_mem_obj)->gpu_addr;
memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
m->header = 0xC0310800;
m->compute_pipelinestat_enable = 1;
m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
PRELOAD_REQ;
m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
QUANTUM_DURATION(10);
m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
/*
* Pipe Priority
* Identifies the pipe relative priority when this queue is connected
* to the pipeline. The pipe priority is against the GFX pipe and HP3D.
* In KFD we are using a fixed pipe priority set to CS_MEDIUM.
* 0 = CS_LOW (typically below GFX)
* 1 = CS_MEDIUM (typically between HP3D and GFX
* 2 = CS_HIGH (typically above HP3D)
*/
m->cp_hqd_pipe_priority = 1;
m->cp_hqd_queue_priority = 15;
*mqd = m;
if (gart_addr)
*gart_addr = addr;
retval = mm->update_mqd(mm, m, q);
return retval;
}
static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
struct queue_properties *q)
{
struct cik_mqd *m;
BUG_ON(!mm || !q || !mqd);
pr_debug("kfd: In func %s\n", __func__);
m = get_mqd(mqd);
m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
DEFAULT_MIN_AVAIL_SIZE |
PRIV_STATE |
KMD_QUEUE;
/*
* Calculating queue size which is log base 2 of actual queue
* size -1 dwords
*/
m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
- 1 - 1;
m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
DOORBELL_OFFSET(q->doorbell_off);
m->cp_hqd_vmid = q->vmid;
m->cp_hqd_active = 0;
q->is_active = false;
if (q->queue_size > 0 &&
q->queue_address != 0 &&
q->queue_percent > 0) {
m->cp_hqd_active = 1;
q->is_active = true;
}
return 0;
}
struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
struct kfd_dev *dev) struct kfd_dev *dev)
{ {
struct mqd_manager *mqd; switch (dev->device_info->asic_family) {
case CHIP_KAVERI:
BUG_ON(!dev); return mqd_manager_init_cik(type, dev);
BUG_ON(type >= KFD_MQD_TYPE_MAX); case CHIP_CARRIZO:
return mqd_manager_init_vi(type, dev);
pr_debug("kfd: In func %s\n", __func__);
mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
if (!mqd)
return NULL;
mqd->dev = dev;
switch (type) {
case KFD_MQD_TYPE_CIK_CP:
case KFD_MQD_TYPE_CIK_COMPUTE:
mqd->init_mqd = init_mqd;
mqd->uninit_mqd = uninit_mqd;
mqd->load_mqd = load_mqd;
mqd->update_mqd = update_mqd;
mqd->destroy_mqd = destroy_mqd;
mqd->is_occupied = is_occupied;
break;
case KFD_MQD_TYPE_CIK_HIQ:
mqd->init_mqd = init_mqd_hiq;
mqd->uninit_mqd = uninit_mqd;
mqd->load_mqd = load_mqd;
mqd->update_mqd = update_mqd_hiq;
mqd->destroy_mqd = destroy_mqd;
mqd->is_occupied = is_occupied;
break;
default:
kfree(mqd);
return NULL;
} }
return mqd; return NULL;
} }
/* SDMA queues should be implemented here when the cp will supports them */
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/printk.h>
#include <linux/slab.h>
#include "kfd_priv.h"
#include "kfd_mqd_manager.h"
#include "cik_regs.h"
#include "cik_structs.h"
static inline struct cik_mqd *get_mqd(void *mqd)
{
return (struct cik_mqd *)mqd;
}
static int init_mqd(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *q)
{
uint64_t addr;
struct cik_mqd *m;
int retval;
BUG_ON(!mm || !q || !mqd);
pr_debug("kfd: In func %s\n", __func__);
retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
mqd_mem_obj);
if (retval != 0)
return -ENOMEM;
m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
addr = (*mqd_mem_obj)->gpu_addr;
memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
m->header = 0xC0310800;
m->compute_pipelinestat_enable = 1;
m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
/*
* Make sure to use the last queue state saved on mqd when the cp
* reassigns the queue, so when queue is switched on/off (e.g over
* subscription or quantum timeout) the context will be consistent
*/
m->cp_hqd_persistent_state =
DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
/* Although WinKFD writes this, I suspect it should not be necessary */
m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
QUANTUM_DURATION(10);
/*
* Pipe Priority
* Identifies the pipe relative priority when this queue is connected
* to the pipeline. The pipe priority is against the GFX pipe and HP3D.
* In KFD we are using a fixed pipe priority set to CS_MEDIUM.
* 0 = CS_LOW (typically below GFX)
* 1 = CS_MEDIUM (typically between HP3D and GFX
* 2 = CS_HIGH (typically above HP3D)
*/
m->cp_hqd_pipe_priority = 1;
m->cp_hqd_queue_priority = 15;
if (q->format == KFD_QUEUE_FORMAT_AQL)
m->cp_hqd_iq_rptr = AQL_ENABLE;
*mqd = m;
if (gart_addr != NULL)
*gart_addr = addr;
retval = mm->update_mqd(mm, m, q);
return retval;
}
static int init_mqd_sdma(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *q)
{
int retval;
struct cik_sdma_rlc_registers *m;
BUG_ON(!mm || !mqd || !mqd_mem_obj);
retval = kfd_gtt_sa_allocate(mm->dev,
sizeof(struct cik_sdma_rlc_registers),
mqd_mem_obj);
if (retval != 0)
return -ENOMEM;
m = (struct cik_sdma_rlc_registers *) (*mqd_mem_obj)->cpu_ptr;
memset(m, 0, sizeof(struct cik_sdma_rlc_registers));
*mqd = m;
if (gart_addr != NULL)
*gart_addr = (*mqd_mem_obj)->gpu_addr;
retval = mm->update_mqd(mm, m, q);
return retval;
}
static void uninit_mqd(struct mqd_manager *mm, void *mqd,
struct kfd_mem_obj *mqd_mem_obj)
{
BUG_ON(!mm || !mqd);
kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
}
static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
struct kfd_mem_obj *mqd_mem_obj)
{
BUG_ON(!mm || !mqd);
kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
}
static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr)
{
return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
}
static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
uint32_t pipe_id, uint32_t queue_id,
uint32_t __user *wptr)
{
return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
}
static int update_mqd(struct mqd_manager *mm, void *mqd,
struct queue_properties *q)
{
struct cik_mqd *m;
BUG_ON(!mm || !q || !mqd);
pr_debug("kfd: In func %s\n", __func__);
m = get_mqd(mqd);
m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
/*
* Calculating queue size which is log base 2 of actual queue size -1
* dwords and another -1 for ffs
*/
m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
- 1 - 1;
m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
DOORBELL_OFFSET(q->doorbell_off);
m->cp_hqd_vmid = q->vmid;
if (q->format == KFD_QUEUE_FORMAT_AQL) {
m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
}
m->cp_hqd_active = 0;
q->is_active = false;
if (q->queue_size > 0 &&
q->queue_address != 0 &&
q->queue_percent > 0) {
m->cp_hqd_active = 1;
q->is_active = true;
}
return 0;
}
static int update_mqd_sdma(struct mqd_manager *mm, void *mqd,
struct queue_properties *q)
{
struct cik_sdma_rlc_registers *m;
BUG_ON(!mm || !mqd || !q);
m = get_sdma_mqd(mqd);
m->sdma_rlc_rb_cntl =
SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) |
SDMA_RB_VMID(q->vmid) |
SDMA_RPTR_WRITEBACK_ENABLE |
SDMA_RPTR_WRITEBACK_TIMER(6);
m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8);
m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8);
m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE;
m->sdma_rlc_virtual_addr = q->sdma_vm_addr;
m->sdma_engine_id = q->sdma_engine_id;
m->sdma_queue_id = q->sdma_queue_id;
q->is_active = false;
if (q->queue_size > 0 &&
q->queue_address != 0 &&
q->queue_percent > 0) {
m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE;
q->is_active = true;
}
return 0;
}
static int destroy_mqd(struct mqd_manager *mm, void *mqd,
enum kfd_preempt_type type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id)
{
return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
pipe_id, queue_id);
}
/*
* preempt type here is ignored because there is only one way
* to preempt sdma queue
*/
static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
enum kfd_preempt_type type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id)
{
return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
}
static bool is_occupied(struct mqd_manager *mm, void *mqd,
uint64_t queue_address, uint32_t pipe_id,
uint32_t queue_id)
{
return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
pipe_id, queue_id);
}
static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
uint64_t queue_address, uint32_t pipe_id,
uint32_t queue_id)
{
return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
}
/*
* HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
* The HIQ queue in Kaveri is using the same MQD structure as all the user mode
* queues but with different initial values.
*/
static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *q)
{
uint64_t addr;
struct cik_mqd *m;
int retval;
BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
pr_debug("kfd: In func %s\n", __func__);
retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
mqd_mem_obj);
if (retval != 0)
return -ENOMEM;
m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
addr = (*mqd_mem_obj)->gpu_addr;
memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
m->header = 0xC0310800;
m->compute_pipelinestat_enable = 1;
m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
PRELOAD_REQ;
m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
QUANTUM_DURATION(10);
m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
/*
* Pipe Priority
* Identifies the pipe relative priority when this queue is connected
* to the pipeline. The pipe priority is against the GFX pipe and HP3D.
* In KFD we are using a fixed pipe priority set to CS_MEDIUM.
* 0 = CS_LOW (typically below GFX)
* 1 = CS_MEDIUM (typically between HP3D and GFX
* 2 = CS_HIGH (typically above HP3D)
*/
m->cp_hqd_pipe_priority = 1;
m->cp_hqd_queue_priority = 15;
*mqd = m;
if (gart_addr)
*gart_addr = addr;
retval = mm->update_mqd(mm, m, q);
return retval;
}
static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
struct queue_properties *q)
{
struct cik_mqd *m;
BUG_ON(!mm || !q || !mqd);
pr_debug("kfd: In func %s\n", __func__);
m = get_mqd(mqd);
m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
DEFAULT_MIN_AVAIL_SIZE |
PRIV_STATE |
KMD_QUEUE;
/*
* Calculating queue size which is log base 2 of actual queue
* size -1 dwords
*/
m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
- 1 - 1;
m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
DOORBELL_OFFSET(q->doorbell_off);
m->cp_hqd_vmid = q->vmid;
m->cp_hqd_active = 0;
q->is_active = false;
if (q->queue_size > 0 &&
q->queue_address != 0 &&
q->queue_percent > 0) {
m->cp_hqd_active = 1;
q->is_active = true;
}
return 0;
}
struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
{
struct cik_sdma_rlc_registers *m;
BUG_ON(!mqd);
m = (struct cik_sdma_rlc_registers *)mqd;
return m;
}
struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
struct kfd_dev *dev)
{
struct mqd_manager *mqd;
BUG_ON(!dev);
BUG_ON(type >= KFD_MQD_TYPE_MAX);
pr_debug("kfd: In func %s\n", __func__);
mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
if (!mqd)
return NULL;
mqd->dev = dev;
switch (type) {
case KFD_MQD_TYPE_CP:
case KFD_MQD_TYPE_COMPUTE:
mqd->init_mqd = init_mqd;
mqd->uninit_mqd = uninit_mqd;
mqd->load_mqd = load_mqd;
mqd->update_mqd = update_mqd;
mqd->destroy_mqd = destroy_mqd;
mqd->is_occupied = is_occupied;
break;
case KFD_MQD_TYPE_HIQ:
mqd->init_mqd = init_mqd_hiq;
mqd->uninit_mqd = uninit_mqd;
mqd->load_mqd = load_mqd;
mqd->update_mqd = update_mqd_hiq;
mqd->destroy_mqd = destroy_mqd;
mqd->is_occupied = is_occupied;
break;
case KFD_MQD_TYPE_SDMA:
mqd->init_mqd = init_mqd_sdma;
mqd->uninit_mqd = uninit_mqd_sdma;
mqd->load_mqd = load_mqd_sdma;
mqd->update_mqd = update_mqd_sdma;
mqd->destroy_mqd = destroy_mqd_sdma;
mqd->is_occupied = is_occupied_sdma;
break;
default:
kfree(mqd);
return NULL;
}
return mqd;
}
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/printk.h>
#include "kfd_priv.h"
#include "kfd_mqd_manager.h"
struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
struct kfd_dev *dev)
{
pr_warn("amdkfd: VI MQD is not currently supported\n");
return NULL;
}
...@@ -97,11 +97,8 @@ static int pm_allocate_runlist_ib(struct packet_manager *pm, ...@@ -97,11 +97,8 @@ static int pm_allocate_runlist_ib(struct packet_manager *pm,
pm_calc_rlib_size(pm, rl_buffer_size, is_over_subscription); pm_calc_rlib_size(pm, rl_buffer_size, is_over_subscription);
retval = kfd2kgd->allocate_mem(pm->dqm->dev->kgd, retval = kfd_gtt_sa_allocate(pm->dqm->dev, *rl_buffer_size,
*rl_buffer_size, &pm->ib_buffer_obj);
PAGE_SIZE,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
(struct kgd_mem **) &pm->ib_buffer_obj);
if (retval != 0) { if (retval != 0) {
pr_err("kfd: failed to allocate runlist IB\n"); pr_err("kfd: failed to allocate runlist IB\n");
...@@ -351,7 +348,7 @@ int pm_send_set_resources(struct packet_manager *pm, ...@@ -351,7 +348,7 @@ int pm_send_set_resources(struct packet_manager *pm,
pr_debug("kfd: In func %s\n", __func__); pr_debug("kfd: In func %s\n", __func__);
mutex_lock(&pm->lock); mutex_lock(&pm->lock);
pm->priv_queue->acquire_packet_buffer(pm->priv_queue, pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue,
sizeof(*packet) / sizeof(uint32_t), sizeof(*packet) / sizeof(uint32_t),
(unsigned int **)&packet); (unsigned int **)&packet);
if (packet == NULL) { if (packet == NULL) {
...@@ -378,8 +375,7 @@ int pm_send_set_resources(struct packet_manager *pm, ...@@ -378,8 +375,7 @@ int pm_send_set_resources(struct packet_manager *pm,
packet->queue_mask_lo = lower_32_bits(res->queue_mask); packet->queue_mask_lo = lower_32_bits(res->queue_mask);
packet->queue_mask_hi = upper_32_bits(res->queue_mask); packet->queue_mask_hi = upper_32_bits(res->queue_mask);
pm->priv_queue->submit_packet(pm->priv_queue); pm->priv_queue->ops.submit_packet(pm->priv_queue);
pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
mutex_unlock(&pm->lock); mutex_unlock(&pm->lock);
...@@ -405,7 +401,7 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues) ...@@ -405,7 +401,7 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues)
packet_size_dwords = sizeof(struct pm4_runlist) / sizeof(uint32_t); packet_size_dwords = sizeof(struct pm4_runlist) / sizeof(uint32_t);
mutex_lock(&pm->lock); mutex_lock(&pm->lock);
retval = pm->priv_queue->acquire_packet_buffer(pm->priv_queue, retval = pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue,
packet_size_dwords, &rl_buffer); packet_size_dwords, &rl_buffer);
if (retval != 0) if (retval != 0)
goto fail_acquire_packet_buffer; goto fail_acquire_packet_buffer;
...@@ -415,15 +411,14 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues) ...@@ -415,15 +411,14 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues)
if (retval != 0) if (retval != 0)
goto fail_create_runlist; goto fail_create_runlist;
pm->priv_queue->submit_packet(pm->priv_queue); pm->priv_queue->ops.submit_packet(pm->priv_queue);
pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
mutex_unlock(&pm->lock); mutex_unlock(&pm->lock);
return retval; return retval;
fail_create_runlist: fail_create_runlist:
pm->priv_queue->rollback_packet(pm->priv_queue); pm->priv_queue->ops.rollback_packet(pm->priv_queue);
fail_acquire_packet_buffer: fail_acquire_packet_buffer:
mutex_unlock(&pm->lock); mutex_unlock(&pm->lock);
fail_create_runlist_ib: fail_create_runlist_ib:
...@@ -441,7 +436,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address, ...@@ -441,7 +436,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
BUG_ON(!pm || !fence_address); BUG_ON(!pm || !fence_address);
mutex_lock(&pm->lock); mutex_lock(&pm->lock);
retval = pm->priv_queue->acquire_packet_buffer( retval = pm->priv_queue->ops.acquire_packet_buffer(
pm->priv_queue, pm->priv_queue,
sizeof(struct pm4_query_status) / sizeof(uint32_t), sizeof(struct pm4_query_status) / sizeof(uint32_t),
(unsigned int **)&packet); (unsigned int **)&packet);
...@@ -462,8 +457,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address, ...@@ -462,8 +457,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
packet->data_hi = upper_32_bits((uint64_t)fence_value); packet->data_hi = upper_32_bits((uint64_t)fence_value);
packet->data_lo = lower_32_bits((uint64_t)fence_value); packet->data_lo = lower_32_bits((uint64_t)fence_value);
pm->priv_queue->submit_packet(pm->priv_queue); pm->priv_queue->ops.submit_packet(pm->priv_queue);
pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
mutex_unlock(&pm->lock); mutex_unlock(&pm->lock);
return 0; return 0;
...@@ -485,7 +479,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type, ...@@ -485,7 +479,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
BUG_ON(!pm); BUG_ON(!pm);
mutex_lock(&pm->lock); mutex_lock(&pm->lock);
retval = pm->priv_queue->acquire_packet_buffer( retval = pm->priv_queue->ops.acquire_packet_buffer(
pm->priv_queue, pm->priv_queue,
sizeof(struct pm4_unmap_queues) / sizeof(uint32_t), sizeof(struct pm4_unmap_queues) / sizeof(uint32_t),
&buffer); &buffer);
...@@ -540,8 +534,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type, ...@@ -540,8 +534,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
break; break;
}; };
pm->priv_queue->submit_packet(pm->priv_queue); pm->priv_queue->ops.submit_packet(pm->priv_queue);
pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
mutex_unlock(&pm->lock); mutex_unlock(&pm->lock);
return 0; return 0;
...@@ -557,8 +550,7 @@ void pm_release_ib(struct packet_manager *pm) ...@@ -557,8 +550,7 @@ void pm_release_ib(struct packet_manager *pm)
mutex_lock(&pm->lock); mutex_lock(&pm->lock);
if (pm->allocated) { if (pm->allocated) {
kfd2kgd->free_mem(pm->dqm->dev->kgd, kfd_gtt_sa_free(pm->dqm->dev, pm->ib_buffer_obj);
(struct kgd_mem *) pm->ib_buffer_obj);
pm->allocated = false; pm->allocated = false;
} }
mutex_unlock(&pm->lock); mutex_unlock(&pm->lock);
......
...@@ -103,12 +103,26 @@ enum cache_policy { ...@@ -103,12 +103,26 @@ enum cache_policy {
cache_policy_noncoherent cache_policy_noncoherent
}; };
enum asic_family_type {
CHIP_KAVERI = 0,
CHIP_CARRIZO
};
struct kfd_device_info { struct kfd_device_info {
unsigned int asic_family;
unsigned int max_pasid_bits; unsigned int max_pasid_bits;
size_t ih_ring_entry_size; size_t ih_ring_entry_size;
uint8_t num_of_watch_points;
uint16_t mqd_size_aligned; uint16_t mqd_size_aligned;
}; };
struct kfd_mem_obj {
uint32_t range_start;
uint32_t range_end;
uint64_t gpu_addr;
uint32_t *cpu_ptr;
};
struct kfd_dev { struct kfd_dev {
struct kgd_dev *kgd; struct kgd_dev *kgd;
...@@ -134,6 +148,14 @@ struct kfd_dev { ...@@ -134,6 +148,14 @@ struct kfd_dev {
struct kgd2kfd_shared_resources shared_resources; struct kgd2kfd_shared_resources shared_resources;
void *gtt_mem;
uint64_t gtt_start_gpu_addr;
void *gtt_start_cpu_ptr;
void *gtt_sa_bitmap;
struct mutex gtt_sa_lock;
unsigned int gtt_sa_chunk_size;
unsigned int gtt_sa_num_of_chunks;
/* QCM Device instance */ /* QCM Device instance */
struct device_queue_manager *dqm; struct device_queue_manager *dqm;
...@@ -149,12 +171,6 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd); ...@@ -149,12 +171,6 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd);
extern const struct kfd2kgd_calls *kfd2kgd; extern const struct kfd2kgd_calls *kfd2kgd;
struct kfd_mem_obj {
void *bo;
uint64_t gpu_addr;
uint32_t *cpu_ptr;
};
enum kfd_mempool { enum kfd_mempool {
KFD_MEMPOOL_SYSTEM_CACHEABLE = 1, KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2, KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
...@@ -272,6 +288,15 @@ struct queue_properties { ...@@ -272,6 +288,15 @@ struct queue_properties {
bool is_active; bool is_active;
/* Not relevant for user mode queues in cp scheduling */ /* Not relevant for user mode queues in cp scheduling */
unsigned int vmid; unsigned int vmid;
/* Relevant only for sdma queues*/
uint32_t sdma_engine_id;
uint32_t sdma_queue_id;
uint32_t sdma_vm_addr;
/* Relevant only for VI */
uint64_t eop_ring_buffer_address;
uint32_t eop_ring_buffer_size;
uint64_t ctx_save_restore_area_address;
uint32_t ctx_save_restore_area_size;
}; };
/** /**
...@@ -314,6 +339,8 @@ struct queue { ...@@ -314,6 +339,8 @@ struct queue {
uint32_t pipe; uint32_t pipe;
uint32_t queue; uint32_t queue;
unsigned int sdma_id;
struct kfd_process *process; struct kfd_process *process;
struct kfd_dev *device; struct kfd_dev *device;
}; };
...@@ -322,10 +349,10 @@ struct queue { ...@@ -322,10 +349,10 @@ struct queue {
* Please read the kfd_mqd_manager.h description. * Please read the kfd_mqd_manager.h description.
*/ */
enum KFD_MQD_TYPE { enum KFD_MQD_TYPE {
KFD_MQD_TYPE_CIK_COMPUTE = 0, /* for no cp scheduling */ KFD_MQD_TYPE_COMPUTE = 0, /* for no cp scheduling */
KFD_MQD_TYPE_CIK_HIQ, /* for hiq */ KFD_MQD_TYPE_HIQ, /* for hiq */
KFD_MQD_TYPE_CIK_CP, /* for cp queues and diq */ KFD_MQD_TYPE_CP, /* for cp queues and diq */
KFD_MQD_TYPE_CIK_SDMA, /* for sdma queues */ KFD_MQD_TYPE_SDMA, /* for sdma queues */
KFD_MQD_TYPE_MAX KFD_MQD_TYPE_MAX
}; };
...@@ -477,8 +504,9 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, ...@@ -477,8 +504,9 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
struct kfd_process *p); struct kfd_process *p);
void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid); void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid);
struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev, struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
struct kfd_process *p, struct kfd_process *p);
int create_pdd); struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
struct kfd_process *p);
/* Process device data iterator */ /* Process device data iterator */
struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p); struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p);
...@@ -506,6 +534,13 @@ unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd, ...@@ -506,6 +534,13 @@ unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
struct kfd_process *process, struct kfd_process *process,
unsigned int queue_id); unsigned int queue_id);
/* GTT Sub-Allocator */
int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
struct kfd_mem_obj **mem_obj);
int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj);
extern struct device *kfd_device; extern struct device *kfd_device;
/* Topology */ /* Topology */
...@@ -530,6 +565,8 @@ int kfd_init_apertures(struct kfd_process *process); ...@@ -530,6 +565,8 @@ int kfd_init_apertures(struct kfd_process *process);
/* Queue Context Management */ /* Queue Context Management */
inline uint32_t lower_32(uint64_t x); inline uint32_t lower_32(uint64_t x);
inline uint32_t upper_32(uint64_t x); inline uint32_t upper_32(uint64_t x);
struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd);
inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m);
int init_queue(struct queue **q, struct queue_properties properties); int init_queue(struct queue **q, struct queue_properties properties);
void uninit_queue(struct queue *q); void uninit_queue(struct queue *q);
...@@ -538,6 +575,10 @@ void print_queue(struct queue *q); ...@@ -538,6 +575,10 @@ void print_queue(struct queue *q);
struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
struct kfd_dev *dev); struct kfd_dev *dev);
struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
struct kfd_dev *dev);
struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
struct kfd_dev *dev);
struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev); struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev);
void device_queue_manager_uninit(struct device_queue_manager *dqm); void device_queue_manager_uninit(struct device_queue_manager *dqm);
struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
......
...@@ -311,24 +311,29 @@ static struct kfd_process *create_process(const struct task_struct *thread) ...@@ -311,24 +311,29 @@ static struct kfd_process *create_process(const struct task_struct *thread)
} }
struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev, struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
struct kfd_process *p, struct kfd_process *p)
int create_pdd)
{ {
struct kfd_process_device *pdd = NULL; struct kfd_process_device *pdd = NULL;
list_for_each_entry(pdd, &p->per_device_data, per_device_list) list_for_each_entry(pdd, &p->per_device_data, per_device_list)
if (pdd->dev == dev) if (pdd->dev == dev)
return pdd; break;
if (create_pdd) { return pdd;
pdd = kzalloc(sizeof(*pdd), GFP_KERNEL); }
if (pdd != NULL) {
pdd->dev = dev; struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
INIT_LIST_HEAD(&pdd->qpd.queues_list); struct kfd_process *p)
INIT_LIST_HEAD(&pdd->qpd.priv_queue_list); {
pdd->qpd.dqm = dev->dqm; struct kfd_process_device *pdd = NULL;
list_add(&pdd->per_device_list, &p->per_device_data);
} pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
if (pdd != NULL) {
pdd->dev = dev;
INIT_LIST_HEAD(&pdd->qpd.queues_list);
INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
pdd->qpd.dqm = dev->dqm;
list_add(&pdd->per_device_list, &p->per_device_data);
} }
return pdd; return pdd;
...@@ -344,11 +349,14 @@ struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev, ...@@ -344,11 +349,14 @@ struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
struct kfd_process *p) struct kfd_process *p)
{ {
struct kfd_process_device *pdd = kfd_get_process_device_data(dev, p, 1); struct kfd_process_device *pdd;
int err; int err;
if (pdd == NULL) pdd = kfd_get_process_device_data(dev, p);
if (!pdd) {
pr_err("Process device data doesn't exist\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
if (pdd->bound) if (pdd->bound)
return pdd; return pdd;
...@@ -384,7 +392,7 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid) ...@@ -384,7 +392,7 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)
pqm_uninit(&p->pqm); pqm_uninit(&p->pqm);
pdd = kfd_get_process_device_data(dev, p, 0); pdd = kfd_get_process_device_data(dev, p);
/* /*
* Just mark pdd as unbound, because we still need it to call * Just mark pdd as unbound, because we still need it to call
......
...@@ -128,7 +128,6 @@ static int create_cp_queue(struct process_queue_manager *pqm, ...@@ -128,7 +128,6 @@ static int create_cp_queue(struct process_queue_manager *pqm,
/* let DQM handle it*/ /* let DQM handle it*/
q_properties->vmid = 0; q_properties->vmid = 0;
q_properties->queue_id = qid; q_properties->queue_id = qid;
q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
retval = init_queue(q, *q_properties); retval = init_queue(q, *q_properties);
if (retval != 0) if (retval != 0)
...@@ -167,8 +166,11 @@ int pqm_create_queue(struct process_queue_manager *pqm, ...@@ -167,8 +166,11 @@ int pqm_create_queue(struct process_queue_manager *pqm,
q = NULL; q = NULL;
kq = NULL; kq = NULL;
pdd = kfd_get_process_device_data(dev, pqm->process, 1); pdd = kfd_get_process_device_data(dev, pqm->process);
BUG_ON(!pdd); if (!pdd) {
pr_err("Process device data doesn't exist\n");
return -1;
}
retval = find_available_queue_slot(pqm, qid); retval = find_available_queue_slot(pqm, qid);
if (retval != 0) if (retval != 0)
...@@ -176,7 +178,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, ...@@ -176,7 +178,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
if (list_empty(&pqm->queues)) { if (list_empty(&pqm->queues)) {
pdd->qpd.pqm = pqm; pdd->qpd.pqm = pqm;
dev->dqm->register_process(dev->dqm, &pdd->qpd); dev->dqm->ops.register_process(dev->dqm, &pdd->qpd);
} }
pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL); pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL);
...@@ -186,6 +188,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, ...@@ -186,6 +188,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
} }
switch (type) { switch (type) {
case KFD_QUEUE_TYPE_SDMA:
case KFD_QUEUE_TYPE_COMPUTE: case KFD_QUEUE_TYPE_COMPUTE:
/* check if there is over subscription */ /* check if there is over subscription */
if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) && if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
...@@ -201,7 +204,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, ...@@ -201,7 +204,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
goto err_create_queue; goto err_create_queue;
pqn->q = q; pqn->q = q;
pqn->kq = NULL; pqn->kq = NULL;
retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd, retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
&q->properties.vmid); &q->properties.vmid);
pr_debug("DQM returned %d for create_queue\n", retval); pr_debug("DQM returned %d for create_queue\n", retval);
print_queue(q); print_queue(q);
...@@ -215,7 +218,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, ...@@ -215,7 +218,8 @@ int pqm_create_queue(struct process_queue_manager *pqm,
kq->queue->properties.queue_id = *qid; kq->queue->properties.queue_id = *qid;
pqn->kq = kq; pqn->kq = kq;
pqn->q = NULL; pqn->q = NULL;
retval = dev->dqm->create_kernel_queue(dev->dqm, kq, &pdd->qpd); retval = dev->dqm->ops.create_kernel_queue(dev->dqm,
kq, &pdd->qpd);
break; break;
default: default:
BUG(); BUG();
...@@ -245,7 +249,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, ...@@ -245,7 +249,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
/* check if queues list is empty unregister process from device */ /* check if queues list is empty unregister process from device */
clear_bit(*qid, pqm->queue_slot_bitmap); clear_bit(*qid, pqm->queue_slot_bitmap);
if (list_empty(&pqm->queues)) if (list_empty(&pqm->queues))
dev->dqm->unregister_process(dev->dqm, &pdd->qpd); dev->dqm->ops.unregister_process(dev->dqm, &pdd->qpd);
return retval; return retval;
} }
...@@ -277,19 +281,22 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) ...@@ -277,19 +281,22 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
dev = pqn->q->device; dev = pqn->q->device;
BUG_ON(!dev); BUG_ON(!dev);
pdd = kfd_get_process_device_data(dev, pqm->process, 1); pdd = kfd_get_process_device_data(dev, pqm->process);
BUG_ON(!pdd); if (!pdd) {
pr_err("Process device data doesn't exist\n");
return -1;
}
if (pqn->kq) { if (pqn->kq) {
/* destroy kernel queue (DIQ) */ /* destroy kernel queue (DIQ) */
dqm = pqn->kq->dev->dqm; dqm = pqn->kq->dev->dqm;
dqm->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd); dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
kernel_queue_uninit(pqn->kq); kernel_queue_uninit(pqn->kq);
} }
if (pqn->q) { if (pqn->q) {
dqm = pqn->q->device->dqm; dqm = pqn->q->device->dqm;
retval = dqm->destroy_queue(dqm, &pdd->qpd, pqn->q); retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q);
if (retval != 0) if (retval != 0)
return retval; return retval;
...@@ -301,7 +308,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) ...@@ -301,7 +308,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
clear_bit(qid, pqm->queue_slot_bitmap); clear_bit(qid, pqm->queue_slot_bitmap);
if (list_empty(&pqm->queues)) if (list_empty(&pqm->queues))
dqm->unregister_process(dqm, &pdd->qpd); dqm->ops.unregister_process(dqm, &pdd->qpd);
return retval; return retval;
} }
...@@ -326,7 +333,8 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, ...@@ -326,7 +333,8 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,
pqn->q->properties.queue_percent = p->queue_percent; pqn->q->properties.queue_percent = p->queue_percent;
pqn->q->properties.priority = p->priority; pqn->q->properties.priority = p->priority;
retval = pqn->q->device->dqm->update_queue(pqn->q->device->dqm, pqn->q); retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
pqn->q);
if (retval != 0) if (retval != 0)
return retval; return retval;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/log2.h>
#include "kfd_priv.h" #include "kfd_priv.h"
#include "kfd_crat.h" #include "kfd_crat.h"
...@@ -630,10 +631,10 @@ static struct kobj_type cache_type = { ...@@ -630,10 +631,10 @@ static struct kobj_type cache_type = {
static ssize_t node_show(struct kobject *kobj, struct attribute *attr, static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
char *buffer) char *buffer)
{ {
ssize_t ret;
struct kfd_topology_device *dev; struct kfd_topology_device *dev;
char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE]; char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
uint32_t i; uint32_t i;
uint32_t log_max_watch_addr;
/* Making sure that the buffer is an empty string */ /* Making sure that the buffer is an empty string */
buffer[0] = 0; buffer[0] = 0;
...@@ -641,8 +642,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, ...@@ -641,8 +642,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
if (strcmp(attr->name, "gpu_id") == 0) { if (strcmp(attr->name, "gpu_id") == 0) {
dev = container_of(attr, struct kfd_topology_device, dev = container_of(attr, struct kfd_topology_device,
attr_gpuid); attr_gpuid);
ret = sysfs_show_32bit_val(buffer, dev->gpu_id); return sysfs_show_32bit_val(buffer, dev->gpu_id);
} else if (strcmp(attr->name, "name") == 0) { }
if (strcmp(attr->name, "name") == 0) {
dev = container_of(attr, struct kfd_topology_device, dev = container_of(attr, struct kfd_topology_device,
attr_name); attr_name);
for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) { for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) {
...@@ -652,80 +655,90 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, ...@@ -652,80 +655,90 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
break; break;
} }
public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0; public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0;
ret = sysfs_show_str_val(buffer, public_name); return sysfs_show_str_val(buffer, public_name);
} else { }
dev = container_of(attr, struct kfd_topology_device,
attr_props);
sysfs_show_32bit_prop(buffer, "cpu_cores_count",
dev->node_props.cpu_cores_count);
sysfs_show_32bit_prop(buffer, "simd_count",
dev->node_props.simd_count);
if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
dev->node_props.mem_banks_count,
dev->mem_bank_count);
sysfs_show_32bit_prop(buffer, "mem_banks_count",
dev->mem_bank_count);
} else {
sysfs_show_32bit_prop(buffer, "mem_banks_count",
dev->node_props.mem_banks_count);
}
sysfs_show_32bit_prop(buffer, "caches_count", dev = container_of(attr, struct kfd_topology_device,
dev->node_props.caches_count); attr_props);
sysfs_show_32bit_prop(buffer, "io_links_count", sysfs_show_32bit_prop(buffer, "cpu_cores_count",
dev->node_props.io_links_count); dev->node_props.cpu_cores_count);
sysfs_show_32bit_prop(buffer, "cpu_core_id_base", sysfs_show_32bit_prop(buffer, "simd_count",
dev->node_props.cpu_core_id_base); dev->node_props.simd_count);
sysfs_show_32bit_prop(buffer, "simd_id_base",
dev->node_props.simd_id_base); if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
sysfs_show_32bit_prop(buffer, "capability", pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
dev->node_props.capability); dev->node_props.mem_banks_count,
sysfs_show_32bit_prop(buffer, "max_waves_per_simd", dev->mem_bank_count);
dev->node_props.max_waves_per_simd); sysfs_show_32bit_prop(buffer, "mem_banks_count",
sysfs_show_32bit_prop(buffer, "lds_size_in_kb", dev->mem_bank_count);
dev->node_props.lds_size_in_kb); } else {
sysfs_show_32bit_prop(buffer, "gds_size_in_kb", sysfs_show_32bit_prop(buffer, "mem_banks_count",
dev->node_props.gds_size_in_kb); dev->node_props.mem_banks_count);
sysfs_show_32bit_prop(buffer, "wave_front_size", }
dev->node_props.wave_front_size);
sysfs_show_32bit_prop(buffer, "array_count",
dev->node_props.array_count);
sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
dev->node_props.simd_arrays_per_engine);
sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
dev->node_props.cu_per_simd_array);
sysfs_show_32bit_prop(buffer, "simd_per_cu",
dev->node_props.simd_per_cu);
sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
dev->node_props.max_slots_scratch_cu);
sysfs_show_32bit_prop(buffer, "vendor_id",
dev->node_props.vendor_id);
sysfs_show_32bit_prop(buffer, "device_id",
dev->node_props.device_id);
sysfs_show_32bit_prop(buffer, "location_id",
dev->node_props.location_id);
if (dev->gpu) {
sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
kfd2kgd->get_max_engine_clock_in_mhz(
dev->gpu->kgd));
sysfs_show_64bit_prop(buffer, "local_mem_size",
kfd2kgd->get_vmem_size(dev->gpu->kgd));
sysfs_show_32bit_prop(buffer, "fw_version",
kfd2kgd->get_fw_version(
dev->gpu->kgd,
KGD_ENGINE_MEC1));
sysfs_show_32bit_prop(buffer, "caches_count",
dev->node_props.caches_count);
sysfs_show_32bit_prop(buffer, "io_links_count",
dev->node_props.io_links_count);
sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
dev->node_props.cpu_core_id_base);
sysfs_show_32bit_prop(buffer, "simd_id_base",
dev->node_props.simd_id_base);
sysfs_show_32bit_prop(buffer, "capability",
dev->node_props.capability);
sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
dev->node_props.max_waves_per_simd);
sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
dev->node_props.lds_size_in_kb);
sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
dev->node_props.gds_size_in_kb);
sysfs_show_32bit_prop(buffer, "wave_front_size",
dev->node_props.wave_front_size);
sysfs_show_32bit_prop(buffer, "array_count",
dev->node_props.array_count);
sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
dev->node_props.simd_arrays_per_engine);
sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
dev->node_props.cu_per_simd_array);
sysfs_show_32bit_prop(buffer, "simd_per_cu",
dev->node_props.simd_per_cu);
sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
dev->node_props.max_slots_scratch_cu);
sysfs_show_32bit_prop(buffer, "vendor_id",
dev->node_props.vendor_id);
sysfs_show_32bit_prop(buffer, "device_id",
dev->node_props.device_id);
sysfs_show_32bit_prop(buffer, "location_id",
dev->node_props.location_id);
if (dev->gpu) {
log_max_watch_addr =
__ilog2_u32(dev->gpu->device_info->num_of_watch_points);
if (log_max_watch_addr) {
dev->node_props.capability |=
HSA_CAP_WATCH_POINTS_SUPPORTED;
dev->node_props.capability |=
((log_max_watch_addr <<
HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT) &
HSA_CAP_WATCH_POINTS_TOTALBITS_MASK);
} }
ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute", sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
cpufreq_quick_get_max(0)/1000); kfd2kgd->get_max_engine_clock_in_mhz(
dev->gpu->kgd));
sysfs_show_64bit_prop(buffer, "local_mem_size",
kfd2kgd->get_vmem_size(dev->gpu->kgd));
sysfs_show_32bit_prop(buffer, "fw_version",
kfd2kgd->get_fw_version(
dev->gpu->kgd,
KGD_ENGINE_MEC1));
} }
return ret; return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
cpufreq_quick_get_max(0)/1000);
} }
static const struct sysfs_ops node_ops = { static const struct sysfs_ops node_ops = {
......
/*
* Copyright 2012 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef CIK_STRUCTS_H_
#define CIK_STRUCTS_H_
struct cik_mqd {
uint32_t header;
uint32_t compute_dispatch_initiator;
uint32_t compute_dim_x;
uint32_t compute_dim_y;
uint32_t compute_dim_z;
uint32_t compute_start_x;
uint32_t compute_start_y;
uint32_t compute_start_z;
uint32_t compute_num_thread_x;
uint32_t compute_num_thread_y;
uint32_t compute_num_thread_z;
uint32_t compute_pipelinestat_enable;
uint32_t compute_perfcount_enable;
uint32_t compute_pgm_lo;
uint32_t compute_pgm_hi;
uint32_t compute_tba_lo;
uint32_t compute_tba_hi;
uint32_t compute_tma_lo;
uint32_t compute_tma_hi;
uint32_t compute_pgm_rsrc1;
uint32_t compute_pgm_rsrc2;
uint32_t compute_vmid;
uint32_t compute_resource_limits;
uint32_t compute_static_thread_mgmt_se0;
uint32_t compute_static_thread_mgmt_se1;
uint32_t compute_tmpring_size;
uint32_t compute_static_thread_mgmt_se2;
uint32_t compute_static_thread_mgmt_se3;
uint32_t compute_restart_x;
uint32_t compute_restart_y;
uint32_t compute_restart_z;
uint32_t compute_thread_trace_enable;
uint32_t compute_misc_reserved;
uint32_t compute_user_data_0;
uint32_t compute_user_data_1;
uint32_t compute_user_data_2;
uint32_t compute_user_data_3;
uint32_t compute_user_data_4;
uint32_t compute_user_data_5;
uint32_t compute_user_data_6;
uint32_t compute_user_data_7;
uint32_t compute_user_data_8;
uint32_t compute_user_data_9;
uint32_t compute_user_data_10;
uint32_t compute_user_data_11;
uint32_t compute_user_data_12;
uint32_t compute_user_data_13;
uint32_t compute_user_data_14;
uint32_t compute_user_data_15;
uint32_t cp_compute_csinvoc_count_lo;
uint32_t cp_compute_csinvoc_count_hi;
uint32_t cp_mqd_base_addr_lo;
uint32_t cp_mqd_base_addr_hi;
uint32_t cp_hqd_active;
uint32_t cp_hqd_vmid;
uint32_t cp_hqd_persistent_state;
uint32_t cp_hqd_pipe_priority;
uint32_t cp_hqd_queue_priority;
uint32_t cp_hqd_quantum;
uint32_t cp_hqd_pq_base_lo;
uint32_t cp_hqd_pq_base_hi;
uint32_t cp_hqd_pq_rptr;
uint32_t cp_hqd_pq_rptr_report_addr_lo;
uint32_t cp_hqd_pq_rptr_report_addr_hi;
uint32_t cp_hqd_pq_wptr_poll_addr_lo;
uint32_t cp_hqd_pq_wptr_poll_addr_hi;
uint32_t cp_hqd_pq_doorbell_control;
uint32_t cp_hqd_pq_wptr;
uint32_t cp_hqd_pq_control;
uint32_t cp_hqd_ib_base_addr_lo;
uint32_t cp_hqd_ib_base_addr_hi;
uint32_t cp_hqd_ib_rptr;
uint32_t cp_hqd_ib_control;
uint32_t cp_hqd_iq_timer;
uint32_t cp_hqd_iq_rptr;
uint32_t cp_hqd_dequeue_request;
uint32_t cp_hqd_dma_offload;
uint32_t cp_hqd_sema_cmd;
uint32_t cp_hqd_msg_type;
uint32_t cp_hqd_atomic0_preop_lo;
uint32_t cp_hqd_atomic0_preop_hi;
uint32_t cp_hqd_atomic1_preop_lo;
uint32_t cp_hqd_atomic1_preop_hi;
uint32_t cp_hqd_hq_status0;
uint32_t cp_hqd_hq_control0;
uint32_t cp_mqd_control;
uint32_t cp_mqd_query_time_lo;
uint32_t cp_mqd_query_time_hi;
uint32_t cp_mqd_connect_start_time_lo;
uint32_t cp_mqd_connect_start_time_hi;
uint32_t cp_mqd_connect_end_time_lo;
uint32_t cp_mqd_connect_end_time_hi;
uint32_t cp_mqd_connect_end_wf_count;
uint32_t cp_mqd_connect_end_pq_rptr;
uint32_t cp_mqd_connect_end_pq_wptr;
uint32_t cp_mqd_connect_end_ib_rptr;
uint32_t reserved_96;
uint32_t reserved_97;
uint32_t reserved_98;
uint32_t reserved_99;
uint32_t iqtimer_pkt_header;
uint32_t iqtimer_pkt_dw0;
uint32_t iqtimer_pkt_dw1;
uint32_t iqtimer_pkt_dw2;
uint32_t iqtimer_pkt_dw3;
uint32_t iqtimer_pkt_dw4;
uint32_t iqtimer_pkt_dw5;
uint32_t iqtimer_pkt_dw6;
uint32_t reserved_108;
uint32_t reserved_109;
uint32_t reserved_110;
uint32_t reserved_111;
uint32_t queue_doorbell_id0;
uint32_t queue_doorbell_id1;
uint32_t queue_doorbell_id2;
uint32_t queue_doorbell_id3;
uint32_t queue_doorbell_id4;
uint32_t queue_doorbell_id5;
uint32_t queue_doorbell_id6;
uint32_t queue_doorbell_id7;
uint32_t queue_doorbell_id8;
uint32_t queue_doorbell_id9;
uint32_t queue_doorbell_id10;
uint32_t queue_doorbell_id11;
uint32_t queue_doorbell_id12;
uint32_t queue_doorbell_id13;
uint32_t queue_doorbell_id14;
uint32_t queue_doorbell_id15;
};
struct cik_sdma_rlc_registers {
uint32_t sdma_rlc_rb_cntl;
uint32_t sdma_rlc_rb_base;
uint32_t sdma_rlc_rb_base_hi;
uint32_t sdma_rlc_rb_rptr;
uint32_t sdma_rlc_rb_wptr;
uint32_t sdma_rlc_rb_wptr_poll_cntl;
uint32_t sdma_rlc_rb_wptr_poll_addr_hi;
uint32_t sdma_rlc_rb_wptr_poll_addr_lo;
uint32_t sdma_rlc_rb_rptr_addr_hi;
uint32_t sdma_rlc_rb_rptr_addr_lo;
uint32_t sdma_rlc_ib_cntl;
uint32_t sdma_rlc_ib_rptr;
uint32_t sdma_rlc_ib_offset;
uint32_t sdma_rlc_ib_base_lo;
uint32_t sdma_rlc_ib_base_hi;
uint32_t sdma_rlc_ib_size;
uint32_t sdma_rlc_skip_cntl;
uint32_t sdma_rlc_context_status;
uint32_t sdma_rlc_doorbell;
uint32_t sdma_rlc_virtual_addr;
uint32_t sdma_rlc_ape1_cntl;
uint32_t sdma_rlc_doorbell_log;
uint32_t reserved_22;
uint32_t reserved_23;
uint32_t reserved_24;
uint32_t reserved_25;
uint32_t reserved_26;
uint32_t reserved_27;
uint32_t reserved_28;
uint32_t reserved_29;
uint32_t reserved_30;
uint32_t reserved_31;
uint32_t reserved_32;
uint32_t reserved_33;
uint32_t reserved_34;
uint32_t reserved_35;
uint32_t reserved_36;
uint32_t reserved_37;
uint32_t reserved_38;
uint32_t reserved_39;
uint32_t reserved_40;
uint32_t reserved_41;
uint32_t reserved_42;
uint32_t reserved_43;
uint32_t reserved_44;
uint32_t reserved_45;
uint32_t reserved_46;
uint32_t reserved_47;
uint32_t reserved_48;
uint32_t reserved_49;
uint32_t reserved_50;
uint32_t reserved_51;
uint32_t reserved_52;
uint32_t reserved_53;
uint32_t reserved_54;
uint32_t reserved_55;
uint32_t reserved_56;
uint32_t reserved_57;
uint32_t reserved_58;
uint32_t reserved_59;
uint32_t reserved_60;
uint32_t reserved_61;
uint32_t reserved_62;
uint32_t reserved_63;
uint32_t reserved_64;
uint32_t reserved_65;
uint32_t reserved_66;
uint32_t reserved_67;
uint32_t reserved_68;
uint32_t reserved_69;
uint32_t reserved_70;
uint32_t reserved_71;
uint32_t reserved_72;
uint32_t reserved_73;
uint32_t reserved_74;
uint32_t reserved_75;
uint32_t reserved_76;
uint32_t reserved_77;
uint32_t reserved_78;
uint32_t reserved_79;
uint32_t reserved_80;
uint32_t reserved_81;
uint32_t reserved_82;
uint32_t reserved_83;
uint32_t reserved_84;
uint32_t reserved_85;
uint32_t reserved_86;
uint32_t reserved_87;
uint32_t reserved_88;
uint32_t reserved_89;
uint32_t reserved_90;
uint32_t reserved_91;
uint32_t reserved_92;
uint32_t reserved_93;
uint32_t reserved_94;
uint32_t reserved_95;
uint32_t reserved_96;
uint32_t reserved_97;
uint32_t reserved_98;
uint32_t reserved_99;
uint32_t reserved_100;
uint32_t reserved_101;
uint32_t reserved_102;
uint32_t reserved_103;
uint32_t reserved_104;
uint32_t reserved_105;
uint32_t reserved_106;
uint32_t reserved_107;
uint32_t reserved_108;
uint32_t reserved_109;
uint32_t reserved_110;
uint32_t reserved_111;
uint32_t reserved_112;
uint32_t reserved_113;
uint32_t reserved_114;
uint32_t reserved_115;
uint32_t reserved_116;
uint32_t reserved_117;
uint32_t reserved_118;
uint32_t reserved_119;
uint32_t reserved_120;
uint32_t reserved_121;
uint32_t reserved_122;
uint32_t reserved_123;
uint32_t reserved_124;
uint32_t reserved_125;
uint32_t reserved_126;
uint32_t reserved_127;
uint32_t sdma_engine_id;
uint32_t sdma_queue_id;
};
#endif /* CIK_STRUCTS_H_ */
...@@ -110,17 +110,10 @@ struct kgd2kfd_calls { ...@@ -110,17 +110,10 @@ struct kgd2kfd_calls {
/** /**
* struct kfd2kgd_calls * struct kfd2kgd_calls
* *
* @init_sa_manager: Initialize an instance of the sa manager, used by * @init_gtt_mem_allocation: Allocate a buffer on the gart aperture.
* amdkfd for all system memory allocations that are mapped to the GART * The buffer can be used for mqds, hpds, kernel queue, fence and runlists
* address space
* *
* @fini_sa_manager: Releases all memory allocations for amdkfd that are * @free_gtt_mem: Frees a buffer that was allocated on the gart aperture
* handled by kgd sa manager
*
* @allocate_mem: Allocate a buffer from amdkfd's sa manager. The buffer can
* be used for mqds, hpds, kernel queue, fence and runlists
*
* @free_mem: Frees a buffer that was allocated by amdkfd's sa manager
* *
* @get_vmem_size: Retrieves (physical) size of VRAM * @get_vmem_size: Retrieves (physical) size of VRAM
* *
...@@ -136,18 +129,23 @@ struct kgd2kfd_calls { ...@@ -136,18 +129,23 @@ struct kgd2kfd_calls {
* @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp * @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp
* scheduling mode. Only used for no cp scheduling mode. * scheduling mode. Only used for no cp scheduling mode.
* *
* @init_memory: Initializes memory apertures to fixed base/limit address
* and non cached memory types.
*
* @init_pipeline: Initialized the compute pipelines. * @init_pipeline: Initialized the compute pipelines.
* *
* @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp * @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp
* sceduling mode. * sceduling mode.
* *
* @hqd_sdma_load: Loads the SDMA mqd structure to a H/W SDMA hqd slot.
* used only for no HWS mode.
*
* @hqd_is_occupies: Checks if a hqd slot is occupied. * @hqd_is_occupies: Checks if a hqd slot is occupied.
* *
* @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot. * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
* *
* @hqd_sdma_is_occupied: Checks if an SDMA hqd slot is occupied.
*
* @hqd_sdma_destroy: Destructs and preempts the SDMA queue assigned to that
* SDMA hqd slot.
*
* @get_fw_version: Returns FW versions from the header * @get_fw_version: Returns FW versions from the header
* *
* This structure contains function pointers to services that the kgd driver * This structure contains function pointers to services that the kgd driver
...@@ -155,13 +153,11 @@ struct kgd2kfd_calls { ...@@ -155,13 +153,11 @@ struct kgd2kfd_calls {
* *
*/ */
struct kfd2kgd_calls { struct kfd2kgd_calls {
/* Memory management. */ int (*init_gtt_mem_allocation)(struct kgd_dev *kgd, size_t size,
int (*init_sa_manager)(struct kgd_dev *kgd, unsigned int size); void **mem_obj, uint64_t *gpu_addr,
void (*fini_sa_manager)(struct kgd_dev *kgd); void **cpu_ptr);
int (*allocate_mem)(struct kgd_dev *kgd, size_t size, size_t alignment,
enum kgd_memory_pool pool, struct kgd_mem **mem);
void (*free_mem)(struct kgd_dev *kgd, struct kgd_mem *mem); void (*free_gtt_mem)(struct kgd_dev *kgd, void *mem_obj);
uint64_t (*get_vmem_size)(struct kgd_dev *kgd); uint64_t (*get_vmem_size)(struct kgd_dev *kgd);
uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd); uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
...@@ -176,25 +172,32 @@ struct kfd2kgd_calls { ...@@ -176,25 +172,32 @@ struct kfd2kgd_calls {
int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid, int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid,
unsigned int vmid); unsigned int vmid);
int (*init_memory)(struct kgd_dev *kgd);
int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id, int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id,
uint32_t hpd_size, uint64_t hpd_gpu_addr); uint32_t hpd_size, uint64_t hpd_gpu_addr);
int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr); uint32_t queue_id, uint32_t __user *wptr);
int (*hqd_sdma_load)(struct kgd_dev *kgd, void *mqd);
bool (*hqd_is_occupied)(struct kgd_dev *kgd, uint64_t queue_address, bool (*hqd_is_occupied)(struct kgd_dev *kgd, uint64_t queue_address,
uint32_t pipe_id, uint32_t queue_id); uint32_t pipe_id, uint32_t queue_id);
int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type, int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
unsigned int timeout, uint32_t pipe_id, unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id); uint32_t queue_id);
bool (*hqd_sdma_is_occupied)(struct kgd_dev *kgd, void *mqd);
int (*hqd_sdma_destroy)(struct kgd_dev *kgd, void *mqd,
unsigned int timeout);
uint16_t (*get_fw_version)(struct kgd_dev *kgd, uint16_t (*get_fw_version)(struct kgd_dev *kgd,
enum kgd_engine_type type); enum kgd_engine_type type);
}; };
bool kgd2kfd_init(unsigned interface_version, bool kgd2kfd_init(unsigned interface_version,
const struct kfd2kgd_calls *f2g, const struct kfd2kgd_calls *f2g,
const struct kgd2kfd_calls **g2f); const struct kgd2kfd_calls **g2f);
#endif /* KGD_KFD_INTERFACE_H_INCLUDED */ #endif /* KGD_KFD_INTERFACE_H_INCLUDED */
...@@ -653,10 +653,6 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ...@@ -653,10 +653,6 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return 0; return 0;
} }
static void armada_drm_crtc_load_lut(struct drm_crtc *crtc)
{
}
/* The mode_config.mutex will be held for this call */ /* The mode_config.mutex will be held for this call */
static void armada_drm_crtc_disable(struct drm_crtc *crtc) static void armada_drm_crtc_disable(struct drm_crtc *crtc)
{ {
...@@ -678,7 +674,6 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { ...@@ -678,7 +674,6 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
.mode_fixup = armada_drm_crtc_mode_fixup, .mode_fixup = armada_drm_crtc_mode_fixup,
.mode_set = armada_drm_crtc_mode_set, .mode_set = armada_drm_crtc_mode_set,
.mode_set_base = armada_drm_crtc_mode_set_base, .mode_set_base = armada_drm_crtc_mode_set_base,
.load_lut = armada_drm_crtc_load_lut,
.disable = armada_drm_crtc_disable, .disable = armada_drm_crtc_disable,
}; };
......
...@@ -335,18 +335,27 @@ int ast_fbdev_init(struct drm_device *dev) ...@@ -335,18 +335,27 @@ int ast_fbdev_init(struct drm_device *dev)
ret = drm_fb_helper_init(dev, &afbdev->helper, ret = drm_fb_helper_init(dev, &afbdev->helper,
1, 1); 1, 1);
if (ret) { if (ret)
kfree(afbdev); goto free;
return ret;
}
drm_fb_helper_single_add_all_connectors(&afbdev->helper); ret = drm_fb_helper_single_add_all_connectors(&afbdev->helper);
if (ret)
goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */ /* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev); drm_helper_disable_unused_functions(dev);
drm_fb_helper_initial_config(&afbdev->helper, 32); ret = drm_fb_helper_initial_config(&afbdev->helper, 32);
if (ret)
goto fini;
return 0; return 0;
fini:
drm_fb_helper_fini(&afbdev->helper);
free:
kfree(afbdev);
return ret;
} }
void ast_fbdev_fini(struct drm_device *dev) void ast_fbdev_fini(struct drm_device *dev)
......
config DRM_ATMEL_HLCDC
tristate "DRM Support for ATMEL HLCDC Display Controller"
depends on DRM && OF && COMMON_CLK && MFD_ATMEL_HLCDC && ARM
select DRM_GEM_CMA_HELPER
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select DRM_KMS_CMA_HELPER
select DRM_PANEL
help
Choose this option if you have an ATMEL SoC with an HLCDC display
controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
atmel_hlcdc_dc.o \
atmel_hlcdc_layer.o \
atmel_hlcdc_output.o \
atmel_hlcdc_plane.o
obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc-dc.o
/*
* Copyright (C) 2014 Traphandler
* Copyright (C) 2014 Free Electrons
*
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drmP.h>
#include <video/videomode.h>
#include "atmel_hlcdc_dc.h"
/**
* Atmel HLCDC CRTC structure
*
* @base: base DRM CRTC structure
* @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
* @event: pointer to the current page flip event
* @id: CRTC id (returned by drm_crtc_index)
* @dpms: DPMS mode
*/
struct atmel_hlcdc_crtc {
struct drm_crtc base;
struct atmel_hlcdc_dc *dc;
struct drm_pending_vblank_event *event;
int id;
int dpms;
};
static inline struct atmel_hlcdc_crtc *
drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
{
return container_of(crtc, struct atmel_hlcdc_crtc, base);
}
static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
{
struct drm_device *dev = c->dev;
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap;
unsigned int status;
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (crtc->dpms == mode)
return;
pm_runtime_get_sync(dev->dev);
if (mode != DRM_MODE_DPMS_ON) {
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_DISP))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_SYNC))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_PIXEL_CLK))
cpu_relax();
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
pm_runtime_allow(dev->dev);
} else {
pm_runtime_forbid(dev->dev);
clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_PIXEL_CLK))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_SYNC))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_DISP))
cpu_relax();
}
pm_runtime_put_sync(dev->dev);
crtc->dpms = mode;
}
static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
struct drm_display_mode *mode,
struct drm_display_mode *adj,
int x, int y,
struct drm_framebuffer *old_fb)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap;
struct drm_plane *plane = c->primary;
struct drm_framebuffer *fb;
unsigned long mode_rate;
struct videomode vm;
unsigned long prate;
unsigned int cfg;
int div;
if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
return -EINVAL;
vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
vm.hfront_porch = adj->crtc_hsync_start - adj->crtc_hdisplay;
vm.hback_porch = adj->crtc_htotal - adj->crtc_hsync_end;
vm.hsync_len = adj->crtc_hsync_end - adj->crtc_hsync_start;
regmap_write(regmap, ATMEL_HLCDC_CFG(1),
(vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
regmap_write(regmap, ATMEL_HLCDC_CFG(2),
(vm.vfront_porch - 1) | (vm.vback_porch << 16));
regmap_write(regmap, ATMEL_HLCDC_CFG(3),
(vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
regmap_write(regmap, ATMEL_HLCDC_CFG(4),
(adj->crtc_hdisplay - 1) |
((adj->crtc_vdisplay - 1) << 16));
cfg = ATMEL_HLCDC_CLKPOL;
prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
mode_rate = mode->crtc_clock * 1000;
if ((prate / 2) < mode_rate) {
prate *= 2;
cfg |= ATMEL_HLCDC_CLKSEL;
}
div = DIV_ROUND_UP(prate, mode_rate);
if (div < 2)
div = 2;
cfg |= ATMEL_HLCDC_CLKDIV(div);
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0),
ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK |
ATMEL_HLCDC_CLKPOL, cfg);
cfg = 0;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
cfg |= ATMEL_HLCDC_VSPOL;
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
cfg |= ATMEL_HLCDC_HSPOL;
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
ATMEL_HLCDC_GUARDTIME_MASK,
cfg);
fb = plane->fb;
plane->fb = old_fb;
return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0,
adj->hdisplay, adj->vdisplay,
x << 16, y << 16,
adj->hdisplay << 16,
adj->vdisplay << 16,
adj);
}
int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y,
struct drm_framebuffer *old_fb)
{
struct drm_plane *plane = c->primary;
struct drm_framebuffer *fb = plane->fb;
struct drm_display_mode *mode = &c->hwmode;
plane->fb = old_fb;
return plane->funcs->update_plane(plane, c, fb,
0, 0,
mode->hdisplay,
mode->vdisplay,
x << 16, y << 16,
mode->hdisplay << 16,
mode->vdisplay << 16);
}
static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
{
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
}
static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
{
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}
static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc)
{
struct drm_plane *plane;
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
crtc->primary->funcs->disable_plane(crtc->primary);
drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
if (plane->crtc != crtc)
continue;
plane->funcs->disable_plane(crtc->primary);
plane->crtc = NULL;
}
}
static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
.mode_fixup = atmel_hlcdc_crtc_mode_fixup,
.dpms = atmel_hlcdc_crtc_dpms,
.mode_set = atmel_hlcdc_crtc_mode_set,
.mode_set_base = atmel_hlcdc_crtc_mode_set_base,
.prepare = atmel_hlcdc_crtc_prepare,
.commit = atmel_hlcdc_crtc_commit,
.disable = atmel_hlcdc_crtc_disable,
};
static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
drm_crtc_cleanup(c);
kfree(crtc);
}
void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
struct drm_file *file)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct drm_pending_vblank_event *event;
struct drm_device *dev = c->dev;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
event = crtc->event;
if (event && event->base.file_priv == file) {
event->base.destroy(&event->base);
drm_vblank_put(dev, crtc->id);
crtc->event = NULL;
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
if (crtc->event) {
drm_send_vblank_event(dev, crtc->id, crtc->event);
drm_vblank_put(dev, crtc->id);
crtc->event = NULL;
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
{
drm_handle_vblank(c->dev, 0);
atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
}
static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct atmel_hlcdc_plane_update_req req;
struct drm_plane *plane = c->primary;
struct drm_device *dev = c->dev;
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&dev->event_lock, flags);
if (crtc->event)
ret = -EBUSY;
spin_unlock_irqrestore(&dev->event_lock, flags);
if (ret)
return ret;
memset(&req, 0, sizeof(req));
req.crtc_x = 0;
req.crtc_y = 0;
req.crtc_h = c->mode.crtc_vdisplay;
req.crtc_w = c->mode.crtc_hdisplay;
req.src_x = c->x << 16;
req.src_y = c->y << 16;
req.src_w = req.crtc_w << 16;
req.src_h = req.crtc_h << 16;
req.fb = fb;
ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode);
if (ret)
return ret;
if (event) {
drm_vblank_get(c->dev, crtc->id);
spin_lock_irqsave(&dev->event_lock, flags);
crtc->event = event;
spin_unlock_irqrestore(&dev->event_lock, flags);
}
ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
if (ret)
crtc->event = NULL;
else
plane->fb = fb;
return ret;
}
static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
.page_flip = atmel_hlcdc_crtc_page_flip,
.set_config = drm_crtc_helper_set_config,
.destroy = atmel_hlcdc_crtc_destroy,
};
int atmel_hlcdc_crtc_create(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
struct atmel_hlcdc_planes *planes = dc->planes;
struct atmel_hlcdc_crtc *crtc;
int ret;
int i;
crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
if (!crtc)
return -ENOMEM;
crtc->dpms = DRM_MODE_DPMS_OFF;
crtc->dc = dc;
ret = drm_crtc_init_with_planes(dev, &crtc->base,
&planes->primary->base,
planes->cursor ? &planes->cursor->base : NULL,
&atmel_hlcdc_crtc_funcs);
if (ret < 0)
goto fail;
crtc->id = drm_crtc_index(&crtc->base);
if (planes->cursor)
planes->cursor->base.possible_crtcs = 1 << crtc->id;
for (i = 0; i < planes->noverlays; i++)
planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
dc->crtc = &crtc->base;
return 0;
fail:
atmel_hlcdc_crtc_destroy(&crtc->base);
return ret;
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -207,12 +207,22 @@ int bochs_fbdev_init(struct bochs_device *bochs) ...@@ -207,12 +207,22 @@ int bochs_fbdev_init(struct bochs_device *bochs)
if (ret) if (ret)
return ret; return ret;
drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
if (ret)
goto fini;
drm_helper_disable_unused_functions(bochs->dev); drm_helper_disable_unused_functions(bochs->dev);
drm_fb_helper_initial_config(&bochs->fb.helper, 32);
ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32);
if (ret)
goto fini;
bochs->fb.initialized = true; bochs->fb.initialized = true;
return 0; return 0;
fini:
drm_fb_helper_fini(&bochs->fb.helper);
return ret;
} }
void bochs_fbdev_fini(struct bochs_device *bochs) void bochs_fbdev_fini(struct bochs_device *bochs)
......
...@@ -18,10 +18,6 @@ MODULE_PARM_DESC(defy, "default y resolution"); ...@@ -18,10 +18,6 @@ MODULE_PARM_DESC(defy, "default y resolution");
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static void bochs_crtc_load_lut(struct drm_crtc *crtc)
{
}
static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
{ {
switch (mode) { switch (mode) {
...@@ -144,7 +140,6 @@ static const struct drm_crtc_helper_funcs bochs_helper_funcs = { ...@@ -144,7 +140,6 @@ static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
.mode_set_base = bochs_crtc_mode_set_base, .mode_set_base = bochs_crtc_mode_set_base,
.prepare = bochs_crtc_prepare, .prepare = bochs_crtc_prepare,
.commit = bochs_crtc_commit, .commit = bochs_crtc_commit,
.load_lut = bochs_crtc_load_lut,
}; };
static void bochs_crtc_init(struct drm_device *dev) static void bochs_crtc_init(struct drm_device *dev)
......
config DRM_DW_HDMI
tristate
depends on DRM
select DRM_KMS_HELPER
config DRM_PTN3460 config DRM_PTN3460
tristate "PTN3460 DP/LVDS bridge" tristate "PTN3460 DP/LVDS bridge"
depends on DRM depends on DRM
depends on OF
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_PANEL
---help--- ---help---
ptn3460 eDP-LVDS bridge chip driver.
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -317,17 +317,17 @@ int cirrus_fbdev_init(struct cirrus_device *cdev) ...@@ -317,17 +317,17 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
cdev->num_crtc, CIRRUSFB_CONN_LIMIT); cdev->num_crtc, CIRRUSFB_CONN_LIMIT);
if (ret) { if (ret)
kfree(gfbdev); return ret;
ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
if (ret)
return ret; return ret;
}
drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
/* disable all the possible outputs/crtcs before entering KMS mode */ /* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(cdev->dev); drm_helper_disable_unused_functions(cdev->dev);
drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
return 0; return drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
} }
void cirrus_fbdev_fini(struct cirrus_device *cdev) void cirrus_fbdev_fini(struct cirrus_device *cdev)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#if defined(CONFIG_X86) #if defined(CONFIG_X86)
#include <asm/smp.h>
/* /*
* clflushopt is an unordered instruction which needs fencing with mfence or * clflushopt is an unordered instruction which needs fencing with mfence or
...@@ -64,12 +65,6 @@ static void drm_cache_flush_clflush(struct page *pages[], ...@@ -64,12 +65,6 @@ static void drm_cache_flush_clflush(struct page *pages[],
drm_clflush_page(*pages++); drm_clflush_page(*pages++);
mb(); mb();
} }
static void
drm_clflush_ipi_handler(void *null)
{
wbinvd();
}
#endif #endif
void void
...@@ -82,7 +77,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages) ...@@ -82,7 +77,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
return; return;
} }
if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n"); printk(KERN_ERR "Timed out waiting for cache flush.\n");
#elif defined(__powerpc__) #elif defined(__powerpc__)
...@@ -121,7 +116,7 @@ drm_clflush_sg(struct sg_table *st) ...@@ -121,7 +116,7 @@ drm_clflush_sg(struct sg_table *st)
return; return;
} }
if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n"); printk(KERN_ERR "Timed out waiting for cache flush.\n");
#else #else
printk(KERN_ERR "Architecture has no drm_cache.c support\n"); printk(KERN_ERR "Architecture has no drm_cache.c support\n");
...@@ -144,7 +139,7 @@ drm_clflush_virt_range(void *addr, unsigned long length) ...@@ -144,7 +139,7 @@ drm_clflush_virt_range(void *addr, unsigned long length)
return; return;
} }
if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n"); printk(KERN_ERR "Timed out waiting for cache flush.\n");
#else #else
printk(KERN_ERR "Architecture has no drm_cache.c support\n"); printk(KERN_ERR "Architecture has no drm_cache.c support\n");
......
此差异已折叠。
...@@ -946,6 +946,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod ...@@ -946,6 +946,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
if (!crtc_state) if (!crtc_state)
return -ENOMEM; return -ENOMEM;
crtc_state->crtc = crtc;
crtc_state->enable = true; crtc_state->enable = true;
crtc_state->planes_changed = true; crtc_state->planes_changed = true;
...@@ -1005,6 +1006,7 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ...@@ -1005,6 +1006,7 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state) if (!plane_state)
return -ENOMEM; return -ENOMEM;
plane_state->plane = plane;
plane_state->crtc = crtc; plane_state->crtc = crtc;
drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
......
...@@ -36,3 +36,9 @@ int drm_mode_object_get(struct drm_device *dev, ...@@ -36,3 +36,9 @@ int drm_mode_object_get(struct drm_device *dev,
void drm_mode_object_put(struct drm_device *dev, void drm_mode_object_put(struct drm_device *dev,
struct drm_mode_object *object); struct drm_mode_object *object);
/* drm_atomic.c */
int drm_atomic_get_property(struct drm_mode_object *obj,
struct drm_property *property, uint64_t *val);
int drm_mode_atomic_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册