[PATCH v3 2/5] dt-bindings: display: panel: Add ilitek ili9341 panel bindings

2020-05-12 Thread dillon . minfei
From: dillon min 

Add documentation for "ilitek,ili9341" panel.

Signed-off-by: dillon min 
---

Changes:

V3:
change compatible to st,sf-tc240t-9370-t, match #vendor,#lcd_module style

V2:
verifyied with make dt_binding_check

V1:
none

.../bindings/display/panel/ilitek,ili9341.yaml | 68 ++
 1 file changed, 68 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml

diff --git 
a/Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml 
b/Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml
new file mode 100644
index 000..9f694d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/ilitek,ili9341.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ilitek-9341 Display Panel
+
+maintainers:
+  - Dillon Min 
+
+description: |
+  Ilitek ILI9341 TFT panel driver with SPI control bus
+  This is a driver for 320x240 TFT panels, accepting a rgb input
+  streams with 16 bits or 18 bits.
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+items:
+  - enum:
+  # ili9341 240*320 Color on stm32f429-disco board
+- st,sf-tc240t-9370-t
+  - const: ilitek,ili9341
+
+  reg: true
+
+  dc-gpios:
+maxItems: 1
+description: Display data/command selection (D/CX)
+
+  spi-3wire: true
+
+  spi-max-frequency:
+const: 1000
+
+  port: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - dc-gpios
+  - port
+
+examples:
+  - |+
+spi {
+#address-cells = <1>;
+#size-cells = <0>;
+panel: display@0 {
+ compatible = "st,sf-tc240t-9370-t", "ilitek,ili9341";
+ reg = <0>;
+ spi-3wire;
+ spi-max-frequency = <1000>;
+ dc-gpios = <&gpiod 13 0>;
+ port {
+ panel_in: endpoint {
+   remote-endpoint = <&display_out>;
+  };
+ };
+ };
+};
+...
+
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 07/15] Documentation: power: update Energy Model description

2020-05-12 Thread Lukasz Luba
The Energy Model framework supports also other devices than CPUs. Update
related information and add description for the new usage.

Acked-by: Daniel Lezcano 
Signed-off-by: Lukasz Luba 
---
 Documentation/power/energy-model.rst | 135 +++
 1 file changed, 75 insertions(+), 60 deletions(-)

diff --git a/Documentation/power/energy-model.rst 
b/Documentation/power/energy-model.rst
index 90a345d57ae9..a6fb986abe3c 100644
--- a/Documentation/power/energy-model.rst
+++ b/Documentation/power/energy-model.rst
@@ -1,15 +1,17 @@
-
-Energy Model of CPUs
-
+.. SPDX-License-Identifier: GPL-2.0
+
+===
+Energy Model of devices
+===
 
 1. Overview
 ---
 
 The Energy Model (EM) framework serves as an interface between drivers knowing
-the power consumed by CPUs at various performance levels, and the kernel
+the power consumed by devices at various performance levels, and the kernel
 subsystems willing to use that information to make energy-aware decisions.
 
-The source of the information about the power consumed by CPUs can vary greatly
+The source of the information about the power consumed by devices can vary 
greatly
 from one platform to another. These power costs can be estimated using
 devicetree data in some cases. In others, the firmware will know better.
 Alternatively, userspace might be best positioned. And so on. In order to avoid
@@ -25,7 +27,7 @@ framework, and interested clients reading the data from it::
+---+  +-+  +---+
| Thermal (IPA) |  | Scheduler (EAS) |  | Other |
+---+  +-+  +---+
-   |   | em_pd_energy()|
+   |   | em_cpu_energy()   |
|   | em_cpu_get()  |
+-+ | +-+
  | | |
@@ -35,7 +37,7 @@ framework, and interested clients reading the data from it::
 | Framework   |
 +-+
^   ^   ^
-   |   |   | em_register_perf_domain()
+   |   |   | em_dev_register_perf_domain()
 +--+   |   +-+
 |  | |
 +---+  +---+  +--+
@@ -47,12 +49,12 @@ framework, and interested clients reading the data from it::
 | Device Tree  |   |   Firmware|  |  ?   |
 +--+   +---+  +--+
 
-The EM framework manages power cost tables per 'performance domain' in the
-system. A performance domain is a group of CPUs whose performance is scaled
-together. Performance domains generally have a 1-to-1 mapping with CPUFreq
-policies. All CPUs in a performance domain are required to have the same
-micro-architecture. CPUs in different performance domains can have different
-micro-architectures.
+In case of CPU devices the EM framework manages power cost tables per
+'performance domain' in the system. A performance domain is a group of CPUs
+whose performance is scaled together. Performance domains generally have a
+1-to-1 mapping with CPUFreq policies. All CPUs in a performance domain are
+required to have the same micro-architecture. CPUs in different performance
+domains can have different micro-architectures.
 
 
 2. Core APIs
@@ -70,14 +72,16 @@ CONFIG_ENERGY_MODEL must be enabled to use the EM framework.
 Drivers are expected to register performance domains into the EM framework by
 calling the following API::
 
-  int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
- struct em_data_callback *cb);
+  int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+   struct em_data_callback *cb, cpumask_t *cpus);
 
-Drivers must specify the CPUs of the performance domains using the cpumask
-argument, and provide a callback function returning  tuples
-for each capacity state. The callback function provided by the driver is free
+Drivers must provide a callback function returning  tuples
+for each performance state. The callback function provided by the driver is 
free
 to fetch data from any relevant location (DT, firmware, ...), and by any mean
-deemed necessary. See Section 3. for an example of driver implementing this
+deemed necessary. Only for CPU devices, drivers must specify the CPUs of the
+performance domains using cpumask. For other devices than CPUs the last
+argument must be set to NULL.
+See Section 3. for an example of driver implementing this
 callback, and kernel/power/energy_model.c for further documentation on this
 API.
 
@@ -85,13 +89,20 @@ API.
 2.3 Accessing performance domains
 ^^^

[PATCH v7 06/15] PM / EM: change name of em_pd_energy to em_cpu_energy

2020-05-12 Thread Lukasz Luba
Energy Model framework supports now other devices than CPUs. Refactor some
of the functions in order to prevent wrong usage. The old function
em_pd_energy has to generic name. It must not be used without proper
cpumask pointer, which is possible only for CPU devices. Thus, rename it
and add proper description to warn of potential wrong usage for other
devices.

Acked-by: Daniel Lezcano 
Signed-off-by: Lukasz Luba 
---
 include/linux/energy_model.h | 11 ---
 kernel/sched/fair.c  |  2 +-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index 6b56ae6c6a89..c92e3ee15245 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -82,15 +82,20 @@ int em_dev_register_perf_domain(struct device *dev, 
unsigned int nr_states,
 void em_dev_unregister_perf_domain(struct device *dev);
 
 /**
- * em_pd_energy() - Estimates the energy consumed by the CPUs of a perf. domain
+ * em_cpu_energy() - Estimates the energy consumed by the CPUs of a
+   performance domain
  * @pd : performance domain for which energy has to be estimated
  * @max_util   : highest utilization among CPUs of the domain
  * @sum_util   : sum of the utilization of all CPUs in the domain
  *
+ * This function must be used only for CPU devices. There is no validation,
+ * i.e. if the EM is a CPU type and has cpumask allocated. It is called from
+ * the scheduler code quite frequently and that is why there is not checks.
+ *
  * Return: the sum of the energy consumed by the CPUs of the domain assuming
  * a capacity state satisfying the max utilization of the domain.
  */
-static inline unsigned long em_pd_energy(struct em_perf_domain *pd,
+static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
unsigned long max_util, unsigned long sum_util)
 {
unsigned long freq, scale_cpu;
@@ -195,7 +200,7 @@ static inline struct em_perf_domain *em_pd_get(struct 
device *dev)
 {
return NULL;
 }
-static inline unsigned long em_pd_energy(struct em_perf_domain *pd,
+static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
unsigned long max_util, unsigned long sum_util)
 {
return 0;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b3bb4d6e49c3..7700e97af52f 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6468,7 +6468,7 @@ compute_energy(struct task_struct *p, int dst_cpu, struct 
perf_domain *pd)
max_util = max(max_util, cpu_util);
}
 
-   return em_pd_energy(pd->em_pd, max_util, sum_util);
+   return em_cpu_energy(pd->em_pd, max_util, sum_util);
 }
 
 /*
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 11/15] thermal: devfreq_cooling: work on a copy of device status

2020-05-12 Thread Lukasz Luba
Devfreq framework can change the device status in the background. To
mitigate this situation make a copy of the status structure and use it
for internal calculations.

Signed-off-by: Lukasz Luba 
---
 drivers/thermal/devfreq_cooling.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index 396f16bb6566..36ec6a48606c 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -348,14 +348,20 @@ static int devfreq_cooling_power2state(struct 
thermal_cooling_device *cdev,
 {
struct devfreq_cooling_device *dfc = cdev->devdata;
struct devfreq *df = dfc->devfreq;
-   struct devfreq_dev_status *status = &df->last_status;
-   unsigned long freq = status->current_frequency;
+   struct devfreq_dev_status status;
unsigned long busy_time;
+   unsigned long freq;
s32 dyn_power;
u32 static_power;
s32 est_power;
int i;
 
+   mutex_lock(&df->lock);
+   status = df->last_status;
+   mutex_unlock(&df->lock);
+
+   freq = status.current_frequency;
+
if (dfc->power_ops->get_real_power) {
/* Scale for resource utilization */
est_power = power * dfc->res_util;
@@ -367,8 +373,8 @@ static int devfreq_cooling_power2state(struct 
thermal_cooling_device *cdev,
dyn_power = dyn_power > 0 ? dyn_power : 0;
 
/* Scale dynamic power for utilization */
-   busy_time = status->busy_time ?: 1;
-   est_power = (dyn_power * status->total_time) / busy_time;
+   busy_time = status.busy_time ?: 1;
+   est_power = (dyn_power * status.total_time) / busy_time;
}
 
/*
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 0/5] Enable ilitek ili9341 on stm32f429-disco board

2020-05-12 Thread dillon . minfei
From: dillon min 

This patchset has following changes:

V3:
merge original tiny/ili9341.c driver to panel/panel-ilitek-ili9341.c
to support serial spi & parallel rgb interface in one driver.
update ilitek,ili9341.yaml dts binding documentation.
update stm32f429-disco dts binding

V2: 
verify ilitek,ili9341.yaml with make O=../linux-stm32 dt_binding_check
DT_SCHEMA_FILES=Documentation/devicetree/bindings/display/panel/
ilitek,ili9341.yaml

V1:
add ili9341 drm panel driver
add ltdc, spi5 controller for stm32f429-disco
add ltdc, spi5 pin map for stm32f429-disco
add docs about ili9341
fix ltdc driver loading hang in clk set rate bug

dillon min (5):
  ARM: dts: stm32: Add pin map for ltdc, spi5 on stm32f429-disco board
  dt-bindings: display: panel: Add ilitek ili9341 panel bindings
  ARM: dts: stm32: enable ltdc binding with ili9341 on stm32429-disco
board
  clk: stm32: Fix stm32f429 ltdc driver loading hang in clk set rate.
keep ltdc clk running after kernel startup
  drm/panel: Add ilitek ili9341 driver

 .../bindings/display/panel/ilitek,ili9341.yaml |  68 ++
 arch/arm/boot/dts/stm32f4-pinctrl.dtsi |  67 ++
 arch/arm/boot/dts/stm32f429-disco.dts  |  39 ++
 drivers/clk/clk-stm32f4.c  |   5 +-
 drivers/gpu/drm/panel/Kconfig  |  12 +
 drivers/gpu/drm/panel/Makefile |   1 +
 drivers/gpu/drm/panel/panel-ilitek-ili9341.c   | 700 +
 7 files changed, 890 insertions(+), 2 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml
 create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c

-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 12/15] thermal: devfreq_cooling: add new registration functions with Energy Model

2020-05-12 Thread Lukasz Luba
The Energy Model (EM) framework supports devices such as Devfreq. Create
new registration functions which automatically register EM for the thermal
devfreq_cooling devices. This patch prepares the code for coming changes
which are going to replace old power model with the new EM.

Signed-off-by: Lukasz Luba 
---
 drivers/thermal/devfreq_cooling.c | 99 ++-
 include/linux/devfreq_cooling.h   | 22 +++
 2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index 36ec6a48606c..c7ffed2d6ee0 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -58,6 +58,8 @@ static DEFINE_IDA(devfreq_ida);
  * @capped_state:  index to cooling state with in dynamic power budget
  * @req_max_freq:  PM QoS request for limiting the maximum frequency
  * of the devfreq device.
+ * @em:Energy Model which represents the associated Devfreq 
device
+ * @em_registered: Devfreq cooling registered the EM and should free it.
  */
 struct devfreq_cooling_device {
int id;
@@ -71,6 +73,8 @@ struct devfreq_cooling_device {
u32 res_util;
int capped_state;
struct dev_pm_qos_request req_max_freq;
+   struct em_perf_domain *em;
+   bool em_registered;
 };
 
 static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev,
@@ -594,22 +598,115 @@ struct thermal_cooling_device 
*devfreq_cooling_register(struct devfreq *df)
 }
 EXPORT_SYMBOL_GPL(devfreq_cooling_register);
 
+/**
+ * devfreq_cooling_em_register_power() - Register devfreq cooling device with
+ * power information and attempt to register Energy Model (EM)
+ * @df:Pointer to devfreq device.
+ * @dfc_power: Pointer to devfreq_cooling_power.
+ * @em_cb: Callback functions providing the data of the EM
+ *
+ * Register a devfreq cooling device and attempt to register Energy Model. The
+ * available OPPs must be registered for the device.
+ *
+ * If @dfc_power is provided, the cooling device is registered with the
+ * power extensions. If @em_cb is provided it will be called for each OPP to
+ * calculate power value and cost. If @em_cb is not provided then simple Energy
+ * Model is going to be used, which requires "dynamic-power-coefficient" a
+ * devicetree property.
+ */
+struct thermal_cooling_device *
+devfreq_cooling_em_register_power(struct devfreq *df,
+ struct devfreq_cooling_power *dfc_power,
+ struct em_data_callback *em_cb)
+{
+   struct thermal_cooling_device *cdev;
+   struct devfreq_cooling_device *dfc;
+   struct device_node *np = NULL;
+   struct device *dev;
+   int nr_opp, ret;
+
+   if (IS_ERR_OR_NULL(df))
+   return ERR_PTR(-EINVAL);
+
+   dev = df->dev.parent;
+
+   if (em_cb) {
+   nr_opp = dev_pm_opp_get_opp_count(dev);
+   if (nr_opp <= 0) {
+   dev_err(dev, "No valid OPPs found\n");
+   return ERR_PTR(-EINVAL);
+   }
+
+   ret = em_dev_register_perf_domain(dev, nr_opp, em_cb, NULL);
+   } else {
+   ret = dev_pm_opp_of_register_em(dev, NULL);
+   }
+
+   if (ret)
+   dev_warn(dev, "Unable to register EM for devfreq cooling device 
(%d)\n",
+ret);
+
+   if (dev->of_node)
+   np = of_node_get(dev->of_node);
+
+   cdev = of_devfreq_cooling_register_power(np, df, dfc_power);
+
+   if (np)
+   of_node_put(np);
+
+   if (IS_ERR_OR_NULL(cdev)) {
+   if (!ret)
+   em_dev_unregister_perf_domain(dev);
+   } else {
+   dfc = cdev->devdata;
+   dfc->em_registered = !ret;
+   }
+
+   return cdev;
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_em_register_power);
+
+/**
+ * devfreq_cooling_em_register() - Register devfreq cooling device together
+ * with Energy Model.
+ * @df:Pointer to devfreq device.
+ * @em_cb: Callback functions providing the data of the Energy Model
+ *
+ * This function attempts to register Energy Model for devfreq device and then
+ * register the devfreq cooling device.
+ */
+struct thermal_cooling_device *
+devfreq_cooling_em_register(struct devfreq *df, struct em_data_callback *em_cb)
+{
+   return devfreq_cooling_em_register_power(df, NULL, em_cb);
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_em_register);
+
 /**
  * devfreq_cooling_unregister() - Unregister devfreq cooling device.
  * @cdev: Pointer to devfreq cooling device to unregister.
+ *
+ * Unregisters devfreq cooling device and related Energy Model if it was
+ * present.
  */
 void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
struct devfreq_cooling_device *dfc;
+   struct device *dev;
 
-   i

Re: [PATCH v5 1/6] drm/bridge: ti-sn65dsi86: Export bridge GPIOs to Linux

2020-05-12 Thread Bjorn Andersson
On Thu 07 May 14:34 PDT 2020, Douglas Anderson wrote:

> The ti-sn65dsi86 MIPI DSI to eDP bridge chip has 4 pins on it that can
> be used as GPIOs in a system.  Each pin can be configured as input,
> output, or a special function for the bridge chip.  These are:
> - GPIO1: SUSPEND Input
> - GPIO2: DSIA VSYNC
> - GPIO3: DSIA HSYNC or VSYNC
> - GPIO4: PWM
> 
> Let's expose these pins as GPIOs.  A few notes:
> - Access to ti-sn65dsi86 is via i2c so we set "can_sleep".
> - These pins can't be configured for IRQ.
> - There are no programmable pulls or other fancy features.
> - Keeping the bridge chip powered might be expensive.  The driver is
>   setup such that if all used GPIOs are only inputs we'll power the
>   bridge chip on just long enough to read the GPIO and then power it
>   off again.  Setting a GPIO as output will keep the bridge powered.
> - If someone releases a GPIO we'll implicitly switch it to an input so
>   we no longer need to keep the bridge powered for it.
> 
> Because of all of the above limitations we just need to implement a
> bare-bones GPIO driver.  The device tree bindings already account for
> this device being a GPIO controller so we only need the driver changes
> for it.
> 
> NOTE: Despite the fact that these pins are nominally muxable I don't
> believe it makes sense to expose them through the pinctrl interface as
> well as the GPIO interface.  The special functions are things that the
> bridge chip driver itself would care about and it can just configure
> the pins as needed.
> 

I'm working on a patch for supporting the PWM controller in the bridge
and as you say the muxing for that is better left internal to the bridge
driver.

> Signed-off-by: Douglas Anderson 
> Cc: Linus Walleij 
> Cc: Bartosz Golaszewski 

Reviewed-by: Bjorn Andersson 

Regards,
Bjorn

> ---
> Removed Stephen's review tag in v5 to confirm he's good with the way I
> implemented of_xlate.
> 
> Changes in v5:
> - Use of_xlate so that numbers in dts start at 1, not 0.
> 
> Changes in v4:
> - Don't include gpio.h
> - Use gpiochip_get_data() instead of container_of() to get data.
> - GPIOF_DIR_XXX => GPIO_LINE_DIRECTION_XXX
> - Use Linus W's favorite syntax to read a bit from a bitfield.
> - Define and use SN_GPIO_MUX_MASK.
> - Add a comment about why we use a bitmap for gchip_output.
> 
> Changes in v3:
> - Becaue => Because
> - Add a kernel-doc to our pdata to clarify double-duty of gchip_output.
> - More comments about how powering off affects us (get_dir, dir_input).
> - Cleanup tail of ti_sn_setup_gpio_controller() to avoid one "return".
> - Use a bitmap rather than rolling my own.
> 
> Changes in v2:
> - ("Export...GPIOs") is 1/2 of replacement for ("Allow...bridge GPIOs")
> 
>  drivers/gpu/drm/bridge/ti-sn65dsi86.c | 214 ++
>  1 file changed, 214 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c 
> b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> index 6ad688b320ae..4e8df948b3b8 100644
> --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> @@ -4,9 +4,11 @@
>   * datasheet: http://www.ti.com/lit/ds/symlink/sn65dsi86.pdf
>   */
>  
> +#include 
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -54,6 +56,14 @@
>  #define  BPP_18_RGB  BIT(0)
>  #define SN_HPD_DISABLE_REG   0x5C
>  #define  HPD_DISABLE BIT(0)
> +#define SN_GPIO_IO_REG   0x5E
> +#define  SN_GPIO_INPUT_SHIFT 4
> +#define  SN_GPIO_OUTPUT_SHIFT0
> +#define SN_GPIO_CTRL_REG 0x5F
> +#define  SN_GPIO_MUX_INPUT   0
> +#define  SN_GPIO_MUX_OUTPUT  1
> +#define  SN_GPIO_MUX_SPECIAL 2
> +#define  SN_GPIO_MUX_MASK0x3
>  #define SN_AUX_WDATA_REG(x)  (0x64 + (x))
>  #define SN_AUX_ADDR_19_16_REG0x74
>  #define SN_AUX_ADDR_15_8_REG 0x75
> @@ -88,6 +98,35 @@
>  
>  #define SN_REGULATOR_SUPPLY_NUM  4
>  
> +#define SN_NUM_GPIOS 4
> +#define SN_GPIO_PHYSICAL_OFFSET  1
> +
> +/**
> + * struct ti_sn_bridge - Platform data for ti-sn65dsi86 driver.
> + * @dev:  Pointer to our device.
> + * @regmap:   Regmap for accessing i2c.
> + * @aux:  Our aux channel.
> + * @bridge:   Our bridge.
> + * @connector:Our connector.
> + * @debugfs:  Used for managing our debugfs.
> + * @host_node:Remote DSI node.
> + * @dsi:  Our MIPI DSI source.
> + * @refclk:   Our reference clock.
> + * @panel:Our panel.
> + * @enable_gpio:  The GPIO we toggle to enable the bridge.
> + * @supplies: Data for bulk enabling/disabling our regulators.
> + * @dp_lanes: Count of dp_lanes we're using.
> + *
> + * @gchip:If we expose our GPIOs, this is used.
> + * @gchip_output: A cache of whether we've s

[PATCH v3] mtd: rawnand: brcmnand: correctly verify erased pages

2020-05-12 Thread Álvaro Fernández Rojas
The current code checks that the whole OOB area is erased.
This is a problem when JFFS2 cleanmarkers are added to the OOB, since it will
fail due to the usable OOB bytes not being 0xff.
Correct this by only checking that data and ECC bytes aren't 0xff.

Fixes: 02b88eea9f9c ("mtd: brcmnand: Add check for erased page bitflips")
Signed-off-by: Álvaro Fernández Rojas 
---
 v3: Fix commit log and merge nand_check_erased_ecc_chunk calls.
 v2: Add Fixes tag

 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 19 ++-
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c 
b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index e4e3ceeac38f..80fe01f03516 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2018,8 +2018,9 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, 
struct nand_chip *chip,
 static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
  struct nand_chip *chip, void *buf, u64 addr)
 {
+   struct mtd_oob_region oobecc;
int i, sas;
-   void *oob = chip->oob_poi;
+   void *oob;
int bitflips = 0;
int page = addr >> chip->page_shift;
int ret;
@@ -2035,11 +2036,19 @@ static int brcmstb_nand_verify_erased_page(struct 
mtd_info *mtd,
if (ret)
return ret;
 
-   for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
+   for (i = 0; i < chip->ecc.steps; i++) {
ecc_chunk = buf + chip->ecc.size * i;
-   ret = nand_check_erased_ecc_chunk(ecc_chunk,
- chip->ecc.size,
- oob, sas, NULL, 0,
+
+   if (mtd->ooblayout->ecc(mtd, i, &oobecc)) {
+   oob = NULL;
+   oobecc.length = 0;
+   } else {
+   oob = chip->oob_poi + oobecc.offset;
+   }
+
+   ret = nand_check_erased_ecc_chunk(ecc_chunk, chip->ecc.size,
+ oob, oobecc.length,
+ NULL, 0,
  chip->ecc.strength);
if (ret < 0)
return ret;
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 5/5] drm/panel: Add ilitek ili9341 driver

2020-05-12 Thread dillon . minfei
From: dillon min 

Currently, we can use tinydrm ili9341 driver to drive ili9341 panel
by spi interface (both register configuration and video)

ili9341 have parallel and mcu interface as well, we extend the
support to parallel rgb interface with DRM_MODE_CONNECTOR_DPI

this driver can work as parallel rgb or serial spi mode by
different dts binding.
for serial spi interface dts binding configuration, refer to:
Documentation/devicetree/bindings/display/ilitek,ili9341.txt

Signed-off-by: dillon min 
---

Changes:

V3:
1 Add support for original dts binding "adafruit,yx240qv29",
  merged from tiny/ili9341.c, which is serial spi interface
  for register configuration and video trasfer.
2 change the dts binding to st,sf-tc240t-9370-t for parallel
  rgb interface.

V2:
none

V1:
Add support for parallel rgb interface

 drivers/gpu/drm/panel/Kconfig|  12 +
 drivers/gpu/drm/panel/Makefile   |   1 +
 drivers/gpu/drm/panel/panel-ilitek-ili9341.c | 700 +++
 3 files changed, 713 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index a1723c1..c938bee 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -95,6 +95,18 @@ config DRM_PANEL_ILITEK_IL9322
  Say Y here if you want to enable support for Ilitek IL9322
  QVGA (320x240) RGB, YUV and ITU-T BT.656 panels.
 
+config DRM_PANEL_ILITEK_ILI9341
+   tristate "Ilitek ILI9341 240x320 QVGA panels"
+   depends on OF && SPI
+   depends on DRM_KMS_HELPER
+   depends on DRM_KMS_CMA_HELPER
+   depends on BACKLIGHT_CLASS_DEVICE
+   select DRM_MIPI_DBI
+   help
+ Say Y here if you want to enable support for Ilitek IL9341
+ QVGA (240x320) RGB panels. support serial & parallel rgb
+ interface.
+
 config DRM_PANEL_ILITEK_ILI9881C
tristate "Ilitek ILI9881C-based panels"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 96a883c..16947d7 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
 obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
 obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += 
panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
+obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c 
b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
new file mode 100644
index 000..17339db
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ilitek ILI9341 TFT LCD drm_panel driver.
+ *
+ * This panel can be configured to support:
+ * - 16-bit parallel RGB interface
+ * - 18-bit parallel RGB interface
+ *
+ * Copyright (C) 2020 Dillon Min 
+ * Derived from drivers/drm/gpu/panel/panel-ilitek-ili9322.c
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#define ILI9341_SLEEP_OUT0x11   /* Sleep out register */
+#define ILI9341_GAMMA0x26   /* Gamma register */
+#define ILI9341_DISPLAY_OFF  0x28   /* Display off register */
+#define ILI9341_DISPLAY_ON   0x29   /* Display on register */
+#define ILI9341_COLUMN_ADDR  0x2a   /* Colomn address register */
+#define ILI9341_PAGE_ADDR0x2b   /* Page address register */
+#define ILI9341_GRAM 0x2c   /* GRAM register */
+#define ILI9341_MAC  0x36   /* Memory Access Control register*/
+#define ILI9341_PIXEL_FORMAT 0x3A   /* Pixel Format register */
+#define ILI9341_RGB_INTERFACE0xb0   /* RGB Interface Signal Control */
+#define ILI9341_FRC  0xb1   /* Frame Rate Control register */
+#define ILI9341_DFC  0xb6   /* Display Function Control
+* register
+*/
+#define ILI9341_POWER1   0xc0   /* Power Control 1 register */
+#define ILI9341_POWER2   0xc1   /* Power Control 2 register */
+#define ILI9341_VCOM10xc5   /* VCOM Control 1 register */
+#define ILI9341_VCOM20xc7   /* VCOM Control 2 register */
+#define ILI9341_POWERA   0xcb   /* Power control A register */
+#define ILI9341_POWERB   0xcf   /* Power control B register */
+#define ILI9341_PGAMMA  

[PATCH v7 02/15] PM / EM: introduce em_dev_register_perf_domain function

2020-05-12 Thread Lukasz Luba
Add now function in the Energy Model framework which is going to support
new devices. This function will help in transition and make it smoother.
For now it still checks if the cpumask is a valid pointer, which will be
removed later when the new structures and infrastructure will be ready.

Acked-by: Daniel Lezcano 
Signed-off-by: Lukasz Luba 
---
 include/linux/energy_model.h | 13 ++--
 kernel/power/energy_model.c  | 40 ++--
 2 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index fe336a9eb5d4..7c048df98447 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -2,6 +2,7 @@
 #ifndef _LINUX_ENERGY_MODEL_H
 #define _LINUX_ENERGY_MODEL_H
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -42,7 +43,7 @@ struct em_perf_domain {
 #define em_span_cpus(em) (to_cpumask((em)->cpus))
 
 #ifdef CONFIG_ENERGY_MODEL
-#define EM_CPU_MAX_POWER 0x
+#define EM_MAX_POWER 0x
 
 struct em_data_callback {
/**
@@ -59,7 +60,7 @@ struct em_data_callback {
 * and frequency.
 *
 * The power is the one of a single CPU in the domain, expressed in
-* milli-watts. It is expected to fit in the [0, EM_CPU_MAX_POWER]
+* milli-watts. It is expected to fit in the [0, EM_MAX_POWER]
 * range.
 *
 * Return 0 on success.
@@ -71,6 +72,8 @@ struct em_data_callback {
 struct em_perf_domain *em_cpu_get(int cpu);
 int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
struct em_data_callback *cb);
+int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+   struct em_data_callback *cb, cpumask_t *span);
 
 /**
  * em_pd_energy() - Estimates the energy consumed by the CPUs of a perf. domain
@@ -174,6 +177,12 @@ static inline int em_register_perf_domain(cpumask_t *span,
 {
return -EINVAL;
 }
+static inline
+int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+   struct em_data_callback *cb, cpumask_t *span)
+{
+   return -EINVAL;
+}
 static inline struct em_perf_domain *em_cpu_get(int cpu)
 {
return NULL;
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 9892d548a0fa..875b163e54ab 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -125,7 +125,7 @@ static struct em_perf_domain *em_create_pd(cpumask_t *span, 
int nr_states,
 * The power returned by active_state() is expected to be
 * positive, in milli-watts and to fit into 16 bits.
 */
-   if (!power || power > EM_CPU_MAX_POWER) {
+   if (!power || power > EM_MAX_POWER) {
pr_err("pd%d: invalid power: %lu\n", cpu, power);
goto free_ps_table;
}
@@ -183,10 +183,13 @@ struct em_perf_domain *em_cpu_get(int cpu)
 EXPORT_SYMBOL_GPL(em_cpu_get);
 
 /**
- * em_register_perf_domain() - Register the Energy Model of a performance 
domain
- * @span   : Mask of CPUs in the performance domain
+ * em_dev_register_perf_domain() - Register the Energy Model (EM) for a device
+ * @dev: Device for which the EM is to register
  * @nr_states  : Number of performance states to register
  * @cb : Callback functions providing the data of the Energy Model
+ * @span   : Pointer to cpumask_t, which in case of a CPU device is
+ * obligatory. It can be taken from i.e. 'policy->cpus'. For other
+ * type of devices this should be set to NULL.
  *
  * Create Energy Model tables for a performance domain using the callbacks
  * defined in cb.
@@ -196,14 +199,14 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
  *
  * Return 0 on success
  */
-int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
-   struct em_data_callback *cb)
+int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+   struct em_data_callback *cb, cpumask_t *span)
 {
unsigned long cap, prev_cap = 0;
struct em_perf_domain *pd;
int cpu, ret = 0;
 
-   if (!span || !nr_states || !cb)
+   if (!dev || !span || !nr_states || !cb)
return -EINVAL;
 
/*
@@ -255,4 +258,29 @@ int em_register_perf_domain(cpumask_t *span, unsigned int 
nr_states,
 
return ret;
 }
+EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
+
+/**
+ * em_register_perf_domain() - Register the Energy Model of a performance 
domain
+ * @span   : Mask of CPUs in the performance domain
+ * @nr_states  : Number of capacity states to register
+ * @cb : Callback functions providing the data of the Energy Model
+ *
+ * Create Energy Model tables for a performance domain using the callbacks
+ * defined in cb.
+ *
+

[PATCH v3 0/2] mtd: rawnand: brcmnand: improve hamming oob layout

2020-05-12 Thread Álvaro Fernández Rojas
These patches improve the OOB hamming layout by reducing the number of oob
sections and correctly 

v3: invert patch order.
v2: extend original comment and correctly skip byte 6 for small-page.

Álvaro Fernández Rojas (2):
  mtd: rawnand: brcmnand: fix hamming oob layout
  mtd: rawnand: brcmnand: improve hamming oob layout

 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 34 +---
 1 file changed, 18 insertions(+), 16 deletions(-)

-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 15/15] drm/panfrost: Register devfreq cooling and attempt to add Energy Model

2020-05-12 Thread Lukasz Luba
Register devfreq cooling device and attempt to register Energy Model. This
will add the devfreq device to the Energy Model framework. It will create
a dedicated and unified data structures used i.e. in thermal framework.
The last NULL parameter indicates that the power model is simplified and
created based on DT 'dynamic-power-coefficient', voltage and frequency.

Reviewed-by: Steven Price 
Reviewed-by: Alyssa Rosenzweig 
Signed-off-by: Lukasz Luba 
---
 drivers/gpu/drm/panfrost/panfrost_devfreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c 
b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
index 413987038fbf..8759a73db153 100644
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
@@ -105,7 +105,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
}
pfdev->devfreq.devfreq = devfreq;
 
-   cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
+   cooling = devfreq_cooling_em_register(devfreq, NULL);
if (IS_ERR(cooling))
DRM_DEV_INFO(dev, "Failed to register cooling device\n");
else
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 14/15] thermal: devfreq_cooling: update license to use SPDX

2020-05-12 Thread Lukasz Luba
Change the license headers and use SPDX standard.

Signed-off-by: Lukasz Luba 
---
 drivers/thermal/devfreq_cooling.c | 12 ++--
 include/linux/devfreq_cooling.h   | 12 ++--
 2 files changed, 4 insertions(+), 20 deletions(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index 79dcef3dbeeb..77d996fd82d2 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * devfreq_cooling: Thermal cooling device implementation for devices using
  *  devfreq
  *
- * Copyright (C) 2014-2015 ARM Limited
- *
- * 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 "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Copyright (C) 2014-2020 ARM Limited
  *
  * TODO:
  *- If OPPs are added or removed after devfreq cooling has
diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h
index 613678ce23df..1f5c07c78f0f 100644
--- a/include/linux/devfreq_cooling.h
+++ b/include/linux/devfreq_cooling.h
@@ -1,17 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * devfreq_cooling: Thermal cooling device implementation for devices using
  *  devfreq
  *
- * Copyright (C) 2014-2015 ARM Limited
- *
- * 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 "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Copyright (C) 2014-2020 ARM Limited
  */
 
 #ifndef __DEVFREQ_COOLING_H__
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 03/15] PM / EM: update callback structure and add device pointer

2020-05-12 Thread Lukasz Luba
The Energy Model framework is going to support devices other that CPUs. In
order to make this happen change the callback function and add pointer to
a device as an argument.

Update the related users to use new function and new callback from the
Energy Model.

Signed-off-by: Lukasz Luba 
---
 drivers/cpufreq/scmi-cpufreq.c | 11 +++
 drivers/opp/of.c   |  9 ++---
 include/linux/energy_model.h   | 15 ---
 kernel/power/energy_model.c|  9 +
 4 files changed, 18 insertions(+), 26 deletions(-)

diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c
index 61623e2ff149..11ee24e06d12 100644
--- a/drivers/cpufreq/scmi-cpufreq.c
+++ b/drivers/cpufreq/scmi-cpufreq.c
@@ -103,17 +103,12 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct 
cpumask *cpumask)
 }
 
 static int __maybe_unused
-scmi_get_cpu_power(unsigned long *power, unsigned long *KHz, int cpu)
+scmi_get_cpu_power(unsigned long *power, unsigned long *KHz,
+  struct device *cpu_dev)
 {
-   struct device *cpu_dev = get_cpu_device(cpu);
unsigned long Hz;
int ret, domain;
 
-   if (!cpu_dev) {
-   pr_err("failed to get cpu%d device\n", cpu);
-   return -ENODEV;
-   }
-
domain = handle->perf_ops->device_domain_id(cpu_dev);
if (domain < 0)
return domain;
@@ -200,7 +195,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
 
policy->fast_switch_possible = true;
 
-   em_register_perf_domain(policy->cpus, nr_opp, &em_cb);
+   em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus);
 
return 0;
 
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 9cd8f0adacae..5b75829a915d 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -1047,9 +1047,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
  * calculation failed because of missing parameters, 0 otherwise.
  */
 static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,
-int cpu)
+struct device *cpu_dev)
 {
-   struct device *cpu_dev;
struct dev_pm_opp *opp;
struct device_node *np;
unsigned long mV, Hz;
@@ -1057,10 +1056,6 @@ static int __maybe_unused _get_cpu_power(unsigned long 
*mW, unsigned long *kHz,
u64 tmp;
int ret;
 
-   cpu_dev = get_cpu_device(cpu);
-   if (!cpu_dev)
-   return -ENODEV;
-
np = of_node_get(cpu_dev->of_node);
if (!np)
return -EINVAL;
@@ -1128,6 +1123,6 @@ void dev_pm_opp_of_register_em(struct cpumask *cpus)
if (ret || !cap)
return;
 
-   em_register_perf_domain(cpus, nr_opp, &em_cb);
+   em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, cpus);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em);
diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index 7c048df98447..7076cb22b247 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -48,24 +48,25 @@ struct em_perf_domain {
 struct em_data_callback {
/**
 * active_power() - Provide power at the next performance state of
-*  a CPU
+*  a device
 * @power   : Active power at the performance state in mW
 *  (modified)
 * @freq: Frequency at the performance state in kHz
 *  (modified)
-* @cpu : CPU for which we do this operation
+* @dev : Device for which we do this operation (can be a CPU)
 *
-* active_power() must find the lowest performance state of 'cpu' above
+* active_power() must find the lowest performance state of 'dev' above
 * 'freq' and update 'power' and 'freq' to the matching active power
 * and frequency.
 *
-* The power is the one of a single CPU in the domain, expressed in
-* milli-watts. It is expected to fit in the [0, EM_MAX_POWER]
-* range.
+* In case of CPUs, the power is the one of a single CPU in the domain,
+* expressed in milli-watts. It is expected to fit in the
+* [0, EM_MAX_POWER] range.
 *
 * Return 0 on success.
 */
-   int (*active_power)(unsigned long *power, unsigned long *freq, int cpu);
+   int (*active_power)(unsigned long *power, unsigned long *freq,
+   struct device *dev);
 };
 #define EM_DATA_CB(_active_power_cb) { .active_power = &_active_power_cb }
 
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 875b163e54ab..5b8a1566526a 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -78,8 +78,9 @@ core_initcall(em_debug_init);
 #else /* CONFIG_DEBUG_FS */
 static void em_debug_create_pd(struct em_perf_domain *pd, int cpu) {}
 #endif
-static struct em_perf_domain *em_cre

[PATCH v7 00/15] Add support for devices in the Energy Model

2020-05-12 Thread Lukasz Luba
Hi all,

This patch set introduces support for devices in the Energy Model (EM)
framework. It will unify the power model for thermal subsystem. It will
make simpler to add support for new devices willing to use more
advanced features (like Intelligent Power Allocation). Now it should
require less knowledge and effort for driver developer to add e.g.
GPU driver with simple energy model. A more sophisticated energy model
in the thermal framework is also possible, driver needs to provide
a dedicated callback function. More information can be found in the
updated documentation file.

First 7 patches are refactoring Energy Model framework to add support
of other devices that CPUs. They change:
- naming convention from 'capacity' to 'performance' state,
- API arguments adding device pointer and not rely only on cpumask,
- change naming when 'cpu' was used, now it's a 'device'
- internal structure to maintain registered devices
- update users to the new API
Patch 8 updates OPP framework helper function to be more generic, not
CPU specific.
Patches 9-14 change devfreq cooling, dropping part of old power model and
adding registration with Energy Model via exported GPL function.
The last path is a simple change for Panfrost GPU driver.

The patch set is based on linux-next tag next-20200508.

Changes:
v7:
- all the EM changes are for patch 4/10 from v6
-- added em_perf_domain structure into struct device in order to simplify
  code (suggested by Daniel)
-- removed kref, em_pd, debug_dir from em_device (suggested by Daniel)
-- refactored code and removed unsed functions
-- refactored checking if EM exists for a CPU and deleted em_cpus_pd_exist()
-- simplified em_pd_get() and em_cpu_get()
-- removed em_debug_type_show()
-- removed a few unused debug prints
-- changed debug dir name in order to remove em_debug_type_show() and
  em_debug_dev_show() functions
-- removed em_dev_list and em_device since it is now possible to use
  struct device and rely on it
- thermal: split patch 9/10 from v6 as requested by Daniel and created 6 new:
-- patch v7 9/15 with only tracing change - exactly the same code so I keep
   'Reviewed-by # for tracing code' from Steven Rostedt
-- patch 10/15 and 11/14 takes more consistent state of devfreq device
-- patch 12/15 which adds Energy Model register/unregister functions
-- patch 13/15 which uses the new Energy Model
-- patch 14/15 adjusts headers license into the SPDX
v6 [6]:
- split patch 1/5 from v5 into smaller patches as requested by Daniel
  and dropped ACK from Quentin which was in the old there
- added function em_dev_register_perf_domain as suggested by Daniel, which
  would help transition into the new API
- changed 'cs' (capacity state) in different places into 'ps' (performance 
state),
  since now there are many smaller patches (previously skipped because
  of too big size of the patch with main features and left to do later)
- changed cpumask_equal() to cpumask_intersects() when checking if 'cpus' coming
  as an argument to registration function might overlap with already known;
  this shouldn't be an issue when cpufreq policy is OK, but a check doesn't harm
- added Reviewed-by from Alyssa into Panfrost related patch
- dropped Matthias patch with PM QoS from the series since it's in the next now
v5 [5]:
- devfreq cooling: rebased on top of pending patch introducing PM QoS limits
- devfreq cooling: added Matthias's patch to make this series build check pass
- devfreq cooling: removed OPP disable code and switched to PM QoS
- devfreq cooling: since thermal code always used a pointer to 
devfreq_dev_status,
  switched to work on a local copy and avoid potential race when either 
busy_time or
  total_time could change in the background
- devfreq cooling: added _normalize_load() and handle all scenarios when
  busy_time and total_time could have odd values (even raw counters)
- Energy Model patch 2/4: removed prints from cpufreq drivers and added print 
inside
  dev_pm_opp_of_register_em()
- update patch 2/4 description to better reflect upcoming changes
- collected ACK from Quentin for patch 1/4 and Reviewed-by from Steven for 4/4
v4 [4]:
- devfreq cooling: added two new registration functions, which will take care
  of registering EM for the device and simplify drivers code
  (suggested by Robin and Rob)
- Energy Model: changed unregistering code, added kref to track usage, added
  code freeing tables, added helper function
- added return value to function dev_pm_opp_of_register_em() and updated
  CPUFreq drivers code, added debug prints in case of failure
- updated comments in devfreq cooling removing statement that only
  simple_ondemand devfreq governor is supported to work with power extentions
- fixed spelling in the documentation (reported by Randy)
v3 [3]:
- added back the cpumask 'cpus' in the em_perf_domain due potential cache misses
- removed _is_cpu_em() since there is no need for it
- changed function name from em_pd_energy() to em_cpu_energy(), which is
  optimized fo

[PATCH v7 04/15] PM / EM: add support for other devices than CPUs in Energy Model

2020-05-12 Thread Lukasz Luba
Add support for other devices that CPUs. The registration function
does not require a valid cpumask pointer and is ready to handle new
devices. Some of the internal structures has been reorganized in order to
keep consistent view (like removing per_cpu pd pointers). To track usage
of the Energy Model structures, they are protected with kref.

Signed-off-by: Lukasz Luba 
---
 include/linux/device.h   |   5 +
 include/linux/energy_model.h |  28 +++--
 kernel/power/energy_model.c  | 237 ---
 3 files changed, 187 insertions(+), 83 deletions(-)

diff --git a/include/linux/device.h b/include/linux/device.h
index ac8e37cd716a..7023d3ea189b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -13,6 +13,7 @@
 #define _DEVICE_H_
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -559,6 +560,10 @@ struct device {
struct dev_pm_info  power;
struct dev_pm_domain*pm_domain;
 
+#ifdef CONFIG_ENERGY_MODEL
+   struct em_perf_domain   *em_pd;
+#endif
+
 #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
struct irq_domain   *msi_domain;
 #endif
diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index 7076cb22b247..f5a88486d1c4 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -12,8 +12,10 @@
 
 /**
  * em_perf_state - Performance state of a performance domain
- * @frequency: The CPU frequency in KHz, for consistency with CPUFreq
- * @power: The power consumed by 1 CPU at this level, in milli-watts
+ * @frequency: The frequency in KHz, for consistency with CPUFreq
+ * @power: The power consumed at this level, in milli-watts (by 1 CPU or
+   by a registered device). It can be a total power: static and
+   dynamic.
  * @cost:  The cost coefficient associated with this level, used during
  * energy calculation. Equal to: power * max_frequency / frequency
  */
@@ -27,12 +29,15 @@ struct em_perf_state {
  * em_perf_domain - Performance domain
  * @table: List of performance states, in ascending order
  * @nr_perf_states:Number of performance states
- * @cpus:  Cpumask covering the CPUs of the domain
+ * @cpus:  Cpumask covering the CPUs of the domain. It's here
+ * for performance reasons to avoid potential cache
+ * misses during energy calculations in the scheduler
  *
- * A "performance domain" represents a group of CPUs whose performance is
- * scaled together. All CPUs of a performance domain must have the same
- * micro-architecture. Performance domains often have a 1-to-1 mapping with
- * CPUFreq policies.
+ * In case of CPU device, a "performance domain" represents a group of CPUs
+ * whose performance is scaled together. All CPUs of a performance domain
+ * must have the same micro-architecture. Performance domains often have
+ * a 1-to-1 mapping with CPUFreq policies. In case of other devices the 'cpus'
+ * field is unused.
  */
 struct em_perf_domain {
struct em_perf_state *table;
@@ -71,10 +76,12 @@ struct em_data_callback {
 #define EM_DATA_CB(_active_power_cb) { .active_power = &_active_power_cb }
 
 struct em_perf_domain *em_cpu_get(int cpu);
+struct em_perf_domain *em_pd_get(struct device *dev);
 int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
struct em_data_callback *cb);
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *span);
+void em_dev_unregister_perf_domain(struct device *dev);
 
 /**
  * em_pd_energy() - Estimates the energy consumed by the CPUs of a perf. domain
@@ -184,10 +191,17 @@ int em_dev_register_perf_domain(struct device *dev, 
unsigned int nr_states,
 {
return -EINVAL;
 }
+static inline void em_dev_unregister_perf_domain(struct device *dev)
+{
+}
 static inline struct em_perf_domain *em_cpu_get(int cpu)
 {
return NULL;
 }
+static inline struct em_perf_domain *em_pd_get(struct device *dev)
+{
+   return NULL;
+}
 static inline unsigned long em_pd_energy(struct em_perf_domain *pd,
unsigned long max_util, unsigned long sum_util)
 {
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 5b8a1566526a..9cc7f2973600 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -2,8 +2,9 @@
 /*
  * Energy Model of CPUs
  *
- * Copyright (c) 2018, Arm ltd.
+ * Copyright (c) 2018-2020, Arm ltd.
  * Written by: Quentin Perret, Arm ltd.
+ * Improvements provided by: Lukasz Luba, Arm ltd.
  */
 
 #define pr_fmt(fmt) "energy_model: " fmt
@@ -15,15 +16,17 @@
 #include 
 #include 
 
-/* Mapping of each CPU to the performance domain to which it belongs. */
-static DEFINE_PER_CPU(struct em_perf_domain *, em_data);
-
 /*
  * Mutex serializing the registrations of performance domains and letting
  * cal

[PATCH v7 05/15] PM / EM: remove em_register_perf_domain

2020-05-12 Thread Lukasz Luba
Remove old function em_register_perf_domain which is no longer needed.
There is em_dev_register_perf_domain that covers old use cases and new as
well.

Acked-by: Daniel Lezcano 
Signed-off-by: Lukasz Luba 
---
 include/linux/energy_model.h |  7 ---
 kernel/power/energy_model.c  | 25 -
 2 files changed, 32 deletions(-)

diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index f5a88486d1c4..6b56ae6c6a89 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -77,8 +77,6 @@ struct em_data_callback {
 
 struct em_perf_domain *em_cpu_get(int cpu);
 struct em_perf_domain *em_pd_get(struct device *dev);
-int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
-   struct em_data_callback *cb);
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *span);
 void em_dev_unregister_perf_domain(struct device *dev);
@@ -180,11 +178,6 @@ static inline int em_pd_nr_perf_states(struct 
em_perf_domain *pd)
 struct em_data_callback {};
 #define EM_DATA_CB(_active_power_cb) { }
 
-static inline int em_register_perf_domain(cpumask_t *span,
-   unsigned int nr_states, struct em_data_callback *cb)
-{
-   return -EINVAL;
-}
 static inline
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *span)
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 9cc7f2973600..3c5c579ad2c2 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -322,31 +322,6 @@ int em_dev_register_perf_domain(struct device *dev, 
unsigned int nr_states,
 }
 EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
 
-/**
- * em_register_perf_domain() - Register the Energy Model of a performance 
domain
- * @span   : Mask of CPUs in the performance domain
- * @nr_states  : Number of capacity states to register
- * @cb : Callback functions providing the data of the Energy Model
- *
- * Create Energy Model tables for a performance domain using the callbacks
- * defined in cb.
- *
- * If multiple clients register the same performance domain, all but the first
- * registration will be ignored.
- *
- * Return 0 on success
- */
-int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
-   struct em_data_callback *cb)
-{
-   struct device *cpu_dev;
-
-   cpu_dev = get_cpu_device(cpumask_first(span));
-
-   return em_dev_register_perf_domain(cpu_dev, nr_states, cb, span);
-}
-EXPORT_SYMBOL_GPL(em_register_perf_domain);
-
 /**
  * em_dev_unregister_perf_domain() - Unregister Energy Model (EM) for a device
  * @dev: Device for which the EM is registered
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 10/15] thermal: devfreq_cooling: get device load and frequency directly

2020-05-12 Thread Lukasz Luba
Devfreq cooling needs to now the correct status of the device in order
to operate. Do not rely on Devfreq last_status which might be a stale data
and get more up-to-date values of load and frequency.

In addition this patch adds normalization function, which also makes sure
that whatever data comes from the device, it is in a sane range.

Signed-off-by: Lukasz Luba 
---
 drivers/thermal/devfreq_cooling.c | 38 +++
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index 52694d4bd819..396f16bb6566 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -235,6 +235,24 @@ static inline unsigned long get_total_power(struct 
devfreq_cooling_device *dfc,
   voltage);
 }
 
+static void _normalize_load(struct devfreq_dev_status *status)
+{
+   /* Make some space if needed */
+   if (status->busy_time > 0x) {
+   status->busy_time >>= 10;
+   status->total_time >>= 10;
+   }
+
+   if (status->busy_time > status->total_time)
+   status->busy_time = status->total_time;
+
+   status->busy_time *= 100;
+   status->busy_time /= status->total_time ? : 1;
+
+   /* Avoid division by 0 */
+   status->busy_time = status->busy_time ? : 1;
+   status->total_time = 100;
+}
 
 static int devfreq_cooling_get_requested_power(struct thermal_cooling_device 
*cdev,
   struct thermal_zone_device *tz,
@@ -242,14 +260,22 @@ static int devfreq_cooling_get_requested_power(struct 
thermal_cooling_device *cd
 {
struct devfreq_cooling_device *dfc = cdev->devdata;
struct devfreq *df = dfc->devfreq;
-   struct devfreq_dev_status *status = &df->last_status;
+   struct devfreq_dev_status status;
unsigned long state;
-   unsigned long freq = status->current_frequency;
+   unsigned long freq;
unsigned long voltage;
u32 dyn_power = 0;
u32 static_power = 0;
int res;
 
+   mutex_lock(&df->lock);
+   res = df->profile->get_dev_status(df->dev.parent, &status);
+   mutex_unlock(&df->lock);
+   if (res)
+   return res;
+
+   freq = status.current_frequency;
+
state = freq_get_state(dfc, freq);
if (state == THERMAL_CSTATE_INVALID) {
res = -EAGAIN;
@@ -277,16 +303,18 @@ static int devfreq_cooling_get_requested_power(struct 
thermal_cooling_device *cd
} else {
dyn_power = dfc->power_table[state];
 
+   _normalize_load(&status);
+
/* Scale dynamic power for utilization */
-   dyn_power *= status->busy_time;
-   dyn_power /= status->total_time;
+   dyn_power *= status.busy_time;
+   dyn_power /= status.total_time;
/* Get static power */
static_power = get_static_power(dfc, freq);
 
*power = dyn_power + static_power;
}
 
-   trace_thermal_power_devfreq_get_power(cdev, status, freq, *power);
+   trace_thermal_power_devfreq_get_power(cdev, &status, freq, *power);
 
return 0;
 fail:
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 1/2] mtd: rawnand: brcmnand: fix hamming oob layout

2020-05-12 Thread Álvaro Fernández Rojas
First 2 bytes are used in large-page nand.

Fixes: ef5eeea6e911 ("mtd: nand: brcm: switch to mtd_ooblayout_ops")
Cc: sta...@vger.kernel.org
Signed-off-by: Álvaro Fernández Rojas 
---
 v3: invert patch order
 v2: extend original comment

 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c 
b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index e4e3ceeac38f..1c1070111ebc 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1116,11 +1116,14 @@ static int brcmnand_hamming_ooblayout_free(struct 
mtd_info *mtd, int section,
if (!section) {
/*
 * Small-page NAND use byte 6 for BBI while large-page
-* NAND use byte 0.
+* NAND use bytes 0 and 1.
 */
-   if (cfg->page_size > 512)
-   oobregion->offset++;
-   oobregion->length--;
+   if (cfg->page_size > 512) {
+   oobregion->offset += 2;
+   oobregion->length -= 2;
+   } else {
+   oobregion->length--;
+   }
}
}
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 2/2] mtd: rawnand: brcmnand: improve hamming oob layout

2020-05-12 Thread Álvaro Fernández Rojas
The current code generates 8 oob sections:
S1  1-5
ECC 6-8
S2  9-15
S3  16-21
ECC 22-24
S4  25-31
S5  32-37
ECC 38-40
S6  41-47
S7  48-53
ECC 54-56
S8  57-63

Change it by merging continuous sections:
S1  1-5
ECC 6-8
S2  9-21
ECC 22-24
S3  25-37
ECC 38-40
S4  41-53
ECC 54-56
S5  57-63

Fixes: ef5eeea6e911 ("mtd: nand: brcm: switch to mtd_ooblayout_ops")
Signed-off-by: Álvaro Fernández Rojas 
---
 v3: invert patch order
 v2: keep original comment and fix correctly skip byte 6 for small-page nand

 drivers/mtd/nand/raw/brcmnand/brcmnand.c | 37 
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c 
b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 1c1070111ebc..0a1d76fde37b 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1100,33 +1100,32 @@ static int brcmnand_hamming_ooblayout_free(struct 
mtd_info *mtd, int section,
struct brcmnand_cfg *cfg = &host->hwcfg;
int sas = cfg->spare_area_size << cfg->sector_size_1k;
int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+   u32 next;
 
-   if (section >= sectors * 2)
+   if (section > sectors)
return -ERANGE;
 
-   oobregion->offset = (section / 2) * sas;
+   next = (section * sas);
+   if (section < sectors)
+   next += 6;
 
-   if (section & 1) {
-   oobregion->offset += 9;
-   oobregion->length = 7;
+   if (section) {
+   oobregion->offset = ((section - 1) * sas) + 9;
} else {
-   oobregion->length = 6;
-
-   /* First sector of each page may have BBI */
-   if (!section) {
-   /*
-* Small-page NAND use byte 6 for BBI while large-page
-* NAND use bytes 0 and 1.
-*/
-   if (cfg->page_size > 512) {
-   oobregion->offset += 2;
-   oobregion->length -= 2;
-   } else {
-   oobregion->length--;
-   }
+   /*
+* Small-page NAND use byte 6 for BBI while large-page
+* NAND use bytes 0 and 1.
+*/
+   if (cfg->page_size > 512) {
+   oobregion->offset = 2;
+   } else {
+   oobregion->offset = 0;
+   next--;
}
}
 
+   oobregion->length = next - oobregion->offset;
+
return 0;
 }
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH] dma-buf: fix use-after-free in dmabuffs_dname

2020-05-12 Thread Charan Teja Kalla


Thank you Greg for the comments.

On 5/6/2020 2:30 PM, Greg KH wrote:

On Wed, May 06, 2020 at 02:00:10PM +0530, Charan Teja Kalla wrote:

Thank you Greg for the reply.

On 5/5/2020 3:38 PM, Greg KH wrote:

On Tue, Apr 28, 2020 at 01:24:02PM +0530, Charan Teja Reddy wrote:

The following race occurs while accessing the dmabuf object exported as
file:
P1  P2
dma_buf_release()  dmabuffs_dname()
   [say lsof reading /proc//fd/]

   read dmabuf stored in dentry->fsdata
Free the dmabuf object
   Start accessing the dmabuf structure

In the above description, the dmabuf object freed in P1 is being
accessed from P2 which is resulting into the use-after-free. Below is
the dump stack reported.

Call Trace:
   kasan_report+0x12/0x20
   __asan_report_load8_noabort+0x14/0x20
   dmabuffs_dname+0x4f4/0x560
   tomoyo_realpath_from_path+0x165/0x660
   tomoyo_get_realpath
   tomoyo_check_open_permission+0x2a3/0x3e0
   tomoyo_file_open
   tomoyo_file_open+0xa9/0xd0
   security_file_open+0x71/0x300
   do_dentry_open+0x37a/0x1380
   vfs_open+0xa0/0xd0
   path_openat+0x12ee/0x3490
   do_filp_open+0x192/0x260
   do_sys_openat2+0x5eb/0x7e0
   do_sys_open+0xf2/0x180

Fixes: bb2bb90 ("dma-buf: add DMA_BUF_SET_NAME ioctls")

Nit, please read the documentation for how to do a Fixes: line properly,
you need more digits:
Fixes: bb2bb9030425 ("dma-buf: add DMA_BUF_SET_NAME ioctls")


Will update the patch



Reported-by:syzbot+3643a18836bce555b...@syzkaller.appspotmail.com
Signed-off-by: Charan Teja Reddy

Also, any reason you didn't include the other mailing lists that
get_maintainer.pl said to?


Really sorry for not sending to complete list. Added now.



And finally, no cc: stable in the s-o-b area for an issue that needs to
be backported to older kernels?


Will update the patch.



---
   drivers/dma-buf/dma-buf.c | 25 +++--
   include/linux/dma-buf.h   |  1 +
   2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 570c923..069d8f78 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -25,6 +25,7 @@
   #include 
   #include 
   #include 
+#include 
   #include 
   #include 
@@ -38,18 +39,34 @@ struct dma_buf_list {
   static struct dma_buf_list db_list;
+static void dmabuf_dent_put(struct dma_buf *dmabuf)
+{
+   if (atomic_dec_and_test(&dmabuf->dent_count)) {
+   kfree(dmabuf->name);
+   kfree(dmabuf);
+   }

Why not just use a kref instead of an open-coded atomic value?


Kref approach looks cleaner. will update the patch accordingly.



+}
+
   static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
   {
struct dma_buf *dmabuf;
char name[DMA_BUF_NAME_LEN];
size_t ret = 0;
+   spin_lock(&dentry->d_lock);
dmabuf = dentry->d_fsdata;
+   if (!dmabuf || !atomic_add_unless(&dmabuf->dent_count, 1, 0)) {
+   spin_unlock(&dentry->d_lock);
+   goto out;

How can dmabuf not be valid here?

And isn't there already a usecount for the buffer?


dmabuf exported as file simply relies on that file's refcount, thus fput()
releases the dmabuf.

We are storing the dmabuf in the dentry->d_fsdata but there is no binding
between the dentry and the dmabuf. So, flow will be like

1) P1 calls fput(dmabuf_fd)

2) P2 trying to access the file information of P1.
     Eg: lsof command trying to list out the dmabuf_fd information using
/proc//fd/dmabuf_fd

3) P1 calls the file->f_op->release(dmabuf_fd_file)(ends up in calling
dma_buf_release()),   thus frees up the dmabuf buffer.

4) P2 access the dmabuf stored in the dentry->d_fsdata which was freed in
step 3.

So we need to have some refcount mechanism to avoid the use-after-free in
step 4.

Ok, but watch out, now you have 2 different reference counts for the
same structure.  Keeping them coordinated is almost always an impossible
task so you need to only rely on one.  If you can't use the file api,
just drop all of the reference counting logic in there and only use the
kref one.


I feel that changing the refcount logic now to dma-buf objects involve 
changes in


the core dma-buf framework. NO? Instead, how about passing the user 
passed name directly


in the ->d_fsdata inplace of dmabuf object? Because we just need user 
passed name in the


dmabuffs_dname(). With this we can avoid the need for extra refcount on 
dmabuf.


Posted patch-V2: https://lkml.org/lkml/2020/5/8/158




good luck!

greg k-h


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a 
Linux Foundation Collaborative Project
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 4/5] clk: stm32: Fix stm32f429 ltdc driver loading hang in clk set rate. keep ltdc clk running after kernel startup

2020-05-12 Thread dillon . minfei
From: dillon min 

as store stm32f4_rcc_register_pll return to the wrong offset of clks,
so ltdc gate clk is null. need change clks[PLL_VCO_SAI] to clks[PLL_SAI]

add CLK_IGNORE_UNUSED for ltdc to make sure clk not be freed by
clk_disable_unused

Signed-off-by: dillon min 
---
 drivers/clk/clk-stm32f4.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 18117ce..0ba73de 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -129,7 +129,8 @@ static const struct stm32f4_gate_data stm32f429_gates[] 
__initconst = {
{ STM32F4_RCC_APB2ENR, 20,  "spi5", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 21,  "spi6", "apb2_div" },
{ STM32F4_RCC_APB2ENR, 22,  "sai1", "apb2_div" },
-   { STM32F4_RCC_APB2ENR, 26,  "ltdc", "apb2_div" },
+   { STM32F4_RCC_APB2ENR, 26,  "ltdc", "apb2_div",
+   CLK_IGNORE_UNUSED },
 };
 
 static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
@@ -1757,7 +1758,7 @@ static void __init stm32f4_rcc_init(struct device_node 
*np)
clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
&data->pll_data[1], &stm32f4_clk_lock);
 
-   clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
+   clks[PLL_SAI] = stm32f4_rcc_register_pll("vco_in",
&data->pll_data[2], &stm32f4_clk_lock);
 
for (n = 0; n < MAX_POST_DIV; n++) {
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


BUG: unable to handle kernel paging request in bitfill_aligned

2020-05-12 Thread syzbot
Hello,

syzbot found the following crash on:

HEAD commit:1d3962ae Merge tag 'io_uring-5.7-2020-05-08' of git://git...
git tree:   upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=1487425810
kernel config:  https://syzkaller.appspot.com/x/.config?x=b0212dbee046bc1f
dashboard link: https://syzkaller.appspot.com/bug?extid=00ed1cf405874e141432
compiler:   gcc (GCC) 9.0.0 20181231 (experimental)

Unfortunately, I don't have any reproducer for this crash yet.

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+00ed1cf405874e141...@syzkaller.appspotmail.com

BUG: unable to handle page fault for address: 888000cf5080
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD d401067 P4D d401067 PUD d402067 PMD cf4063 PTE 0
Oops: 0002 [#1] PREEMPT SMP KASAN
CPU: 0 PID: 30473 Comm: syz-executor.4 Not tainted 5.7.0-rc4-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 
01/01/2011
RIP: 0010:__writeq arch/x86/include/asm/io.h:98 [inline]
RIP: 0010:bitfill_aligned drivers/video/fbdev/core/cfbfillrect.c:64 [inline]
RIP: 0010:bitfill_aligned+0xfc/0x200 drivers/video/fbdev/core/cfbfillrect.c:35
Code: fd 44 89 e0 31 d2 bf 07 00 00 00 f7 f5 41 89 c4 89 c6 89 c5 e8 c5 ab b3 
fd 41 83 fc 07 76 62 45 89 e7 4c 89 ed e8 44 aa b3 fd <48> 89 5d 00 48 89 5d 08 
48 89 5d 10 48 89 5d 18 48 89 5d 20 48 89
RSP: 0018:c90001c474e0 EFLAGS: 00010246
RAX: 0004 RBX:  RCX: c90012324000
RDX: 0004 RSI: 83bf846c RDI: 0005
RBP: 888000cf5080 R08: 888056a6a340 R09: 0040
R10: 888218d3331f R11: ed10431a6663 R12: 0030
R13: 888000cf5080 R14:  R15: 0030
FS:  7fe0d9986700() GS:8880ae60() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 888000cf5080 CR3: 8ea77000 CR4: 001426f0
DR0:  DR1:  DR2: 
DR3:  DR6: fffe0ff0 DR7: 0400
Call Trace:
 cfb_fillrect+0x418/0x7a0 drivers/video/fbdev/core/cfbfillrect.c:327
 vga16fb_fillrect+0x68f/0x1960 drivers/video/fbdev/vga16fb.c:951
 bit_clear_margins+0x2d5/0x4a0 drivers/video/fbdev/core/bitblit.c:232
 fbcon_clear_margins+0x1de/0x240 drivers/video/fbdev/core/fbcon.c:1381
 fbcon_switch+0xcde/0x16f0 drivers/video/fbdev/core/fbcon.c:2363
 redraw_screen+0x2ae/0x770 drivers/tty/vt/vt.c:1015
 fbcon_modechanged+0x581/0x720 drivers/video/fbdev/core/fbcon.c:3000
 fbcon_update_vcs+0x3a/0x50 drivers/video/fbdev/core/fbcon.c:3047
 fb_set_var+0xad0/0xd40 drivers/video/fbdev/core/fbmem.c:1056
 do_fb_ioctl+0x390/0x6e0 drivers/video/fbdev/core/fbmem.c:1109
 fb_ioctl+0xdd/0x130 drivers/video/fbdev/core/fbmem.c:1185
 vfs_ioctl fs/ioctl.c:47 [inline]
 ksys_ioctl+0x11a/0x180 fs/ioctl.c:771
 __do_sys_ioctl fs/ioctl.c:780 [inline]
 __se_sys_ioctl fs/ioctl.c:778 [inline]
 __x64_sys_ioctl+0x6f/0xb0 fs/ioctl.c:778
 do_syscall_64+0xf6/0x7d0 arch/x86/entry/common.c:295
 entry_SYSCALL_64_after_hwframe+0x49/0xb3
RIP: 0033:0x45c829
Code: 0d b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 
89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 
db b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:7fe0d9985c78 EFLAGS: 0246 ORIG_RAX: 0010
RAX: ffda RBX: 004e4860 RCX: 0045c829
RDX: 2000 RSI: 4601 RDI: 0003
RBP: 0078bf00 R08:  R09: 
R10:  R11: 0246 R12: 
R13: 02f2 R14: 004c54c8 R15: 7fe0d99866d4
Modules linked in:
CR2: 888000cf5080

==


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkal...@googlegroups.com.

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v5 6/6] arm64: dts: sdm845: Add "no-hpd" to sn65dsi86 on cheza

2020-05-12 Thread Bjorn Andersson
On Thu 07 May 14:35 PDT 2020, Douglas Anderson wrote:

> We don't have the HPD line hooked up to the bridge chip.  Add it as
> suggested in the patch ("dt-bindings: drm/bridge: ti-sn65dsi86:
> Document no-hpd").
> 
> NOTE: this patch isn't expected to have any effect but just keeps us
> cleaner for the future.  Currently the driver in Linux just assumes
> that nobody has HPD hooked up.  This change allows us to later
> implement HPD support in the driver without messing up sdm845-cheza.
> 
> Signed-off-by: Douglas Anderson 
> Reviewed-by: Stephen Boyd 

Applied this patch for 5.8 in the Qualcomm SoC tree.

Regards,
Bjorn

> ---
> 
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> - ("arm64: dts: sdm845: Add "no-hpd" to sn65dsi86 on cheza") new for v2.
> 
>  arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi 
> b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
> index 9070be43a309..5938f8b2aa2f 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
> @@ -548,6 +548,8 @@ sn65dsi86_bridge: bridge@2d {
>   clocks = <&rpmhcc RPMH_LN_BB_CLK2>;
>   clock-names = "refclk";
>  
> + no-hpd;
> +
>   ports {
>   #address-cells = <1>;
>   #size-cells = <0>;
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 01/15] PM / EM: change naming convention from 'capacity' to 'performance'

2020-05-12 Thread Lukasz Luba
The Energy Model uses concept of performance domain and capacity states in
order to calculate power used by CPUs. Change naming convention from
capacity to performance state would enable wider usage in future, e.g.
upcoming support for other devices other than CPUs.

Acked-by: Daniel Lezcano 
Signed-off-by: Lukasz Luba 
---
 drivers/thermal/cpufreq_cooling.c | 12 ++---
 include/linux/energy_model.h  | 86 +--
 kernel/power/energy_model.c   | 44 
 kernel/sched/topology.c   | 20 +++
 4 files changed, 84 insertions(+), 78 deletions(-)

diff --git a/drivers/thermal/cpufreq_cooling.c 
b/drivers/thermal/cpufreq_cooling.c
index e297e135c031..ad8971e26538 100644
--- a/drivers/thermal/cpufreq_cooling.c
+++ b/drivers/thermal/cpufreq_cooling.c
@@ -333,18 +333,18 @@ static inline bool em_is_sane(struct 
cpufreq_cooling_device *cpufreq_cdev,
return false;
 
policy = cpufreq_cdev->policy;
-   if (!cpumask_equal(policy->related_cpus, to_cpumask(em->cpus))) {
+   if (!cpumask_equal(policy->related_cpus, em_span_cpus(em))) {
pr_err("The span of pd %*pbl is misaligned with cpufreq policy 
%*pbl\n",
-   cpumask_pr_args(to_cpumask(em->cpus)),
+   cpumask_pr_args(em_span_cpus(em)),
cpumask_pr_args(policy->related_cpus));
return false;
}
 
nr_levels = cpufreq_cdev->max_level + 1;
-   if (em->nr_cap_states != nr_levels) {
-   pr_err("The number of cap states in pd %*pbl (%u) doesn't match 
the number of cooling levels (%u)\n",
-   cpumask_pr_args(to_cpumask(em->cpus)),
-   em->nr_cap_states, nr_levels);
+   if (em_pd_nr_perf_states(em) != nr_levels) {
+   pr_err("The number of performance states in pd %*pbl (%u) 
doesn't match the number of cooling levels (%u)\n",
+   cpumask_pr_args(em_span_cpus(em)),
+   em_pd_nr_perf_states(em), nr_levels);
return false;
}
 
diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index ade6486a3382..fe336a9eb5d4 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -10,13 +10,13 @@
 #include 
 
 /**
- * em_cap_state - Capacity state of a performance domain
+ * em_perf_state - Performance state of a performance domain
  * @frequency: The CPU frequency in KHz, for consistency with CPUFreq
  * @power: The power consumed by 1 CPU at this level, in milli-watts
  * @cost:  The cost coefficient associated with this level, used during
  * energy calculation. Equal to: power * max_frequency / frequency
  */
-struct em_cap_state {
+struct em_perf_state {
unsigned long frequency;
unsigned long power;
unsigned long cost;
@@ -24,8 +24,8 @@ struct em_cap_state {
 
 /**
  * em_perf_domain - Performance domain
- * @table: List of capacity states, in ascending order
- * @nr_cap_states: Number of capacity states
+ * @table: List of performance states, in ascending order
+ * @nr_perf_states:Number of performance states
  * @cpus:  Cpumask covering the CPUs of the domain
  *
  * A "performance domain" represents a group of CPUs whose performance is
@@ -34,22 +34,27 @@ struct em_cap_state {
  * CPUFreq policies.
  */
 struct em_perf_domain {
-   struct em_cap_state *table;
-   int nr_cap_states;
+   struct em_perf_state *table;
+   int nr_perf_states;
unsigned long cpus[];
 };
 
+#define em_span_cpus(em) (to_cpumask((em)->cpus))
+
 #ifdef CONFIG_ENERGY_MODEL
 #define EM_CPU_MAX_POWER 0x
 
 struct em_data_callback {
/**
-* active_power() - Provide power at the next capacity state of a CPU
-* @power   : Active power at the capacity state in mW (modified)
-* @freq: Frequency at the capacity state in kHz (modified)
+* active_power() - Provide power at the next performance state of
+*  a CPU
+* @power   : Active power at the performance state in mW
+*  (modified)
+* @freq: Frequency at the performance state in kHz
+*  (modified)
 * @cpu : CPU for which we do this operation
 *
-* active_power() must find the lowest capacity state of 'cpu' above
+* active_power() must find the lowest performance state of 'cpu' above
 * 'freq' and update 'power' and 'freq' to the matching active power
 * and frequency.
 *
@@ -80,46 +85,46 @@ static inline unsigned long em_pd_energy(struct 
em_perf_domain *pd,
unsigned long max_util, unsigned long sum_util)
 {
unsigned long freq, scale_cpu;
-   struct em_cap_state *cs;
+   struct em_perf_state *ps;
int i, cpu;
 
/*
-* In orde

[PATCH v7 09/15] thermal: devfreq_cooling: change tracing function and arguments

2020-05-12 Thread Lukasz Luba
Prepare for deleting the static and dynamic power calculation and clean
the trace function. These two fields are going to be removed in the next
changes.

Reviewed-by: Steven Rostedt (VMware)  # for tracing code
Signed-off-by: Lukasz Luba 
---
 drivers/thermal/devfreq_cooling.c |  3 +--
 include/trace/events/thermal.h| 19 +--
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index f7f32e98331b..52694d4bd819 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -286,8 +286,7 @@ static int devfreq_cooling_get_requested_power(struct 
thermal_cooling_device *cd
*power = dyn_power + static_power;
}
 
-   trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power,
- static_power, *power);
+   trace_thermal_power_devfreq_get_power(cdev, status, freq, *power);
 
return 0;
 fail:
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h
index 135e5421f003..8a5f04888abd 100644
--- a/include/trace/events/thermal.h
+++ b/include/trace/events/thermal.h
@@ -153,31 +153,30 @@ TRACE_EVENT(thermal_power_cpu_limit,
 TRACE_EVENT(thermal_power_devfreq_get_power,
TP_PROTO(struct thermal_cooling_device *cdev,
 struct devfreq_dev_status *status, unsigned long freq,
-   u32 dynamic_power, u32 static_power, u32 power),
+   u32 power),
 
-   TP_ARGS(cdev, status,  freq, dynamic_power, static_power, power),
+   TP_ARGS(cdev, status,  freq, power),
 
TP_STRUCT__entry(
__string(type, cdev->type)
__field(unsigned long, freq  )
-   __field(u32,   load  )
-   __field(u32,   dynamic_power )
-   __field(u32,   static_power  )
+   __field(u32,   busy_time)
+   __field(u32,   total_time)
__field(u32,   power)
),
 
TP_fast_assign(
__assign_str(type, cdev->type);
__entry->freq = freq;
-   __entry->load = (100 * status->busy_time) / status->total_time;
-   __entry->dynamic_power = dynamic_power;
-   __entry->static_power = static_power;
+   __entry->busy_time = status->busy_time;
+   __entry->total_time = status->total_time;
__entry->power = power;
),
 
-   TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u 
power=%u",
+   TP_printk("type=%s freq=%lu load=%u power=%u",
__get_str(type), __entry->freq,
-   __entry->load, __entry->dynamic_power, __entry->static_power,
+   __entry->total_time == 0 ? 0 :
+   (100 * __entry->busy_time) / __entry->total_time,
__entry->power)
 );
 
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 3/5] ARM: dts: stm32: enable ltdc binding with ili9341 on stm32429-disco board

2020-05-12 Thread dillon . minfei
From: dillon min 

Enable the ltdc & ili9341 on stm32429-disco board.

Signed-off-by: dillon min 
---

Changes:

V3:
change dts binding compatible to "st,sf-tc240t-9370-t"

V2:
none

v1:
none

arch/arm/boot/dts/stm32f429-disco.dts | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429-disco.dts 
b/arch/arm/boot/dts/stm32f429-disco.dts
index 30c0f67..4475e40 100644
--- a/arch/arm/boot/dts/stm32f429-disco.dts
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -49,6 +49,8 @@
 #include "stm32f429.dtsi"
 #include "stm32f429-pinctrl.dtsi"
 #include 
+#include 
+#include 
 
 / {
model = "STMicroelectronics STM32F429i-DISCO board";
@@ -127,3 +129,40 @@
pinctrl-names = "default";
status = "okay";
 };
+
+;
+   pinctrl-names = "default";
+
+   port {
+   ltdc_out_rgb: endpoint {
+   remote-endpoint = <&panel_in_rgb>;
+   };
+   };
+};
+
+&spi5 {
+   status = "okay";
+   pinctrl-0 = <&spi5_pins>;
+   pinctrl-names = "default";
+   #address-cells = <1>;
+   #size-cells = <0>;
+   cs-gpios = <&gpioc 2 GPIO_ACTIVE_LOW>;
+   dmas = <&dma2 3 2 0x400 0x0>,
+  <&dma2 4 2 0x400 0x0>;
+   dma-names = "rx", "tx";
+   display: display@0{
+   /* Connect panel-ilitek-9341 to stm32 via ltdc*/
+   compatible = "st,sf-tc240t-9370-t";
+   reg = <0>;
+   spi-3wire;
+   spi-max-frequency = <1000>;
+   dc-gpios = <&gpiod 13 0>;
+   port {
+   panel_in_rgb: endpoint {
+   remote-endpoint = <;
+   };
+   };
+   };
+};
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v7 13/15] thermal: devfreq_cooling: remove old power model and use EM

2020-05-12 Thread Lukasz Luba
Remove old power model and use new Energy Model to calculate the power
budget. It drops static + dynamic power calculations and power table
in order to use Energy Model performance domain data. This model
should be easy to use and could find more users. It is also less
complicated to setup the needed structures.

Signed-off-by: Lukasz Luba 
---
 drivers/thermal/devfreq_cooling.c | 282 +-
 include/linux/devfreq_cooling.h   |  17 --
 2 files changed, 86 insertions(+), 213 deletions(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index c7ffed2d6ee0..79dcef3dbeeb 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -41,20 +41,17 @@ static DEFINE_IDA(devfreq_ida);
  * @cdev:  Pointer to associated thermal cooling device.
  * @devfreq:   Pointer to associated devfreq device.
  * @cooling_state: Current cooling state.
- * @power_table:   Pointer to table with maximum power draw for each
- * cooling state. State is the index into the table, and
- * the power is in mW.
  * @freq_table:Pointer to a table with the frequencies sorted in 
descending
  * order.  You can index the table by cooling device state
- * @freq_table_size:   Size of the @freq_table and @power_table
- * @power_ops: Pointer to devfreq_cooling_power, used to generate the
- * @power_table.
+ * @max_state: It is the last index, that is, one less than the number of the
+ * OPPs
+ * @power_ops: Pointer to devfreq_cooling_power, a more precised model.
  * @res_util:  Resource utilization scaling factor for the power.
  * It is multiplied by 100 to minimize the error. It is used
  * for estimation of the power budget instead of using
- * 'utilization' (which is 'busy_time / 'total_time').
- * The 'res_util' range is from 100 to (power_table[state] * 100)
- * for the corresponding 'state'.
+ * 'utilization' (which is 'busy_time' / 'total_time').
+ * The 'res_util' range is from 100 to power * 100 for the
+ * corresponding 'state'.
  * @capped_state:  index to cooling state with in dynamic power budget
  * @req_max_freq:  PM QoS request for limiting the maximum frequency
  * of the devfreq device.
@@ -66,9 +63,8 @@ struct devfreq_cooling_device {
struct thermal_cooling_device *cdev;
struct devfreq *devfreq;
unsigned long cooling_state;
-   u32 *power_table;
u32 *freq_table;
-   size_t freq_table_size;
+   size_t max_state;
struct devfreq_cooling_power *power_ops;
u32 res_util;
int capped_state;
@@ -82,7 +78,7 @@ static int devfreq_cooling_get_max_state(struct 
thermal_cooling_device *cdev,
 {
struct devfreq_cooling_device *dfc = cdev->devdata;
 
-   *state = dfc->freq_table_size - 1;
+   *state = dfc->max_state;
 
return 0;
 }
@@ -110,10 +106,16 @@ static int devfreq_cooling_set_cur_state(struct 
thermal_cooling_device *cdev,
 
dev_dbg(dev, "Setting cooling state %lu\n", state);
 
-   if (state >= dfc->freq_table_size)
+   if (state > dfc->max_state)
return -EINVAL;
 
-   freq = dfc->freq_table[state];
+   if (dfc->em) {
+   /* Energy Model frequencies are in kHz */
+   freq = dfc->em->table[dfc->max_state - state].frequency;
+   freq *= 1000;
+   } else {
+   freq = dfc->freq_table[state];
+   }
 
dev_pm_qos_update_request(&dfc->req_max_freq,
  DIV_ROUND_UP(freq, HZ_PER_KHZ));
@@ -124,11 +126,11 @@ static int devfreq_cooling_set_cur_state(struct 
thermal_cooling_device *cdev,
 }
 
 /**
- * freq_get_state() - get the cooling state corresponding to a frequency
+ * freq_get_state() - get the performance index corresponding to a frequency
  * @dfc:   Pointer to devfreq cooling device
- * @freq:  frequency in Hz
+ * @freq:  frequency in kHz
  *
- * Return: the cooling state associated with the @freq, or
+ * Return: the performance index associated with the @freq, or
  * THERMAL_CSTATE_INVALID if it wasn't found.
  */
 static unsigned long
@@ -136,8 +138,8 @@ freq_get_state(struct devfreq_cooling_device *dfc, unsigned 
long freq)
 {
int i;
 
-   for (i = 0; i < dfc->freq_table_size; i++) {
-   if (dfc->freq_table[i] == freq)
+   for (i = 0; i <= dfc->max_state; i++) {
+   if (dfc->em->table[i].frequency == freq)
return i;
}
 
@@ -172,71 +174,15 @@ static unsigned long get_voltage(struct devfreq *df, 
unsigned long freq)
return voltage;
 }
 
-/**
- * get_static_power() - calculate the static power
- * @dfc:   Pointer to devfreq cooling device
- * @freq:  Frequency in Hz
- *
- * Calculate the static power in milliwatts usi

[PATCH v7 08/15] OPP: refactor dev_pm_opp_of_register_em() and update related drivers

2020-05-12 Thread Lukasz Luba
The Energy Model framework supports not only CPU devices. Drop the CPU
specific interface with cpumask and add struct device. Add also a return
value, user might use it. This new interface provides easy way to create
a simple Energy Model, which then might be used by e.g. thermal subsystem.

Acked-by: Daniel Lezcano 
Signed-off-by: Lukasz Luba 
---
 drivers/cpufreq/cpufreq-dt.c   |  2 +-
 drivers/cpufreq/imx6q-cpufreq.c|  2 +-
 drivers/cpufreq/mediatek-cpufreq.c |  2 +-
 drivers/cpufreq/omap-cpufreq.c |  2 +-
 drivers/cpufreq/qcom-cpufreq-hw.c  |  2 +-
 drivers/cpufreq/scpi-cpufreq.c |  2 +-
 drivers/cpufreq/vexpress-spc-cpufreq.c |  2 +-
 drivers/opp/of.c   | 71 --
 include/linux/pm_opp.h | 15 +-
 9 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 26fe8dfb9ce6..f9f03fd49b83 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -275,7 +275,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = transition_latency;
policy->dvfs_possible_from_any_cpu = true;
 
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
 
return 0;
 
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index fdb2bd15..ef7b34c1fd2b 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -193,7 +193,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
policy->clk = clks[ARM].clk;
cpufreq_generic_init(policy, freq_table, transition_latency);
policy->suspend_freq = max_freq;
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
 
return 0;
 }
diff --git a/drivers/cpufreq/mediatek-cpufreq.c 
b/drivers/cpufreq/mediatek-cpufreq.c
index 0c98dd08273d..7d1212c9b7c8 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -448,7 +448,7 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy)
policy->driver_data = info;
policy->clk = info->cpu_clk;
 
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(info->cpu_dev, policy->cpus);
 
return 0;
 }
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 8d14b42a8c6f..3694bb030df3 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -131,7 +131,7 @@ static int omap_cpu_init(struct cpufreq_policy *policy)
 
/* FIXME: what's the actual transition time? */
cpufreq_generic_init(policy, freq_table, 300 * 1000);
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(mpu_dev, policy->cpus);
 
return 0;
 }
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c 
b/drivers/cpufreq/qcom-cpufreq-hw.c
index fc92a8842e25..0a04b6f03b9a 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -238,7 +238,7 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy 
*policy)
goto error;
}
 
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
 
policy->fast_switch_possible = true;
 
diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c
index 20d1f85d5f5a..b0f5388b8854 100644
--- a/drivers/cpufreq/scpi-cpufreq.c
+++ b/drivers/cpufreq/scpi-cpufreq.c
@@ -167,7 +167,7 @@ static int scpi_cpufreq_init(struct cpufreq_policy *policy)
 
policy->fast_switch_possible = false;
 
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
 
return 0;
 
diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c 
b/drivers/cpufreq/vexpress-spc-cpufreq.c
index 83c85d3d67e3..4e8b1dee7c9a 100644
--- a/drivers/cpufreq/vexpress-spc-cpufreq.c
+++ b/drivers/cpufreq/vexpress-spc-cpufreq.c
@@ -450,7 +450,7 @@ static int ve_spc_cpufreq_init(struct cpufreq_policy 
*policy)
policy->freq_table = freq_table[cur_cluster];
policy->cpuinfo.transition_latency = 100; /* 1 ms */
 
-   dev_pm_opp_of_register_em(policy->cpus);
+   dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
 
if (is_bL_switching_enabled())
per_cpu(cpu_last_req_freq, policy->cpu) =
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 5b75829a915d..4500ce46d476 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -1036,18 +1036,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
 
 /*
  * Callback function provided to the Energy Model framework upon registration.
- * This computes the power estimated by @CPU at @kHz if it is the frequency
+ * This computes the power estimated by @dev at @kHz if it is the frequency
  * of an existing OPP, or at the frequency of 

[PATCH v3 1/5] ARM: dts: stm32: Add pin map for ltdc, spi5 on stm32f429-disco board

2020-05-12 Thread dillon . minfei
From: dillon min 

This patch adds the pin configuration for ltdc, spi5 controller
on stm32f429-disco board.

Signed-off-by: dillon min 
---
 arch/arm/boot/dts/stm32f4-pinctrl.dtsi | 67 ++
 1 file changed, 67 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f4-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32f4-pinctrl.dtsi
index 392fa14..0eb107f 100644
--- a/arch/arm/boot/dts/stm32f4-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32f4-pinctrl.dtsi
@@ -316,6 +316,73 @@
};
};
 
+   ltdc_pins_f429_disco: ltdc-1 {
+   pins {
+   pinmux = ,
+   /* LCD_HSYNC */
+,
+/* LCD_VSYNC */
+,
+/* LCD_CLK */
+,
+/* LCD_R2 */
+,
+/* LCD_R3 */
+,
+/* LCD_R4 */
+,
+/* LCD_R5 */
+,
+/* LCD_R6*/
+,
+/* LCD_R7 */
+,
+/* LCD_G2 */
+,
+/* LCD_G3 */
+,
+/* LCD_G4 */
+,
+/* LCD_B2 */
+,
+/* LCD_B3*/
+,
+/* LCD_G5 */
+,
+/* LCD_G6 */
+,
+/* LCD_G7 */
+,
+/* LCD_B4 */
+,
+/* LCD_B5 */
+,
+/* LCD_B6 */
+,
+/* LCD_B7 */
+;
+/* LCD_DE */
+   slew-rate = <2>;
+   };
+   };
+
+   spi5_pins: spi5-0 {
+   pins1 {
+   pinmux = ,
+   /* SPI5_CLK */
+;
+   /* SPI5_MOSI */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = ;
+   /* SPI5_MISO */
+   bias-disable;
+   };
+   };
+
dcmi_pins: dcmi-0 {
pins {
pinmux = , 
/* DCMI_HSYNC */
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC] Remove AGP support from Radeon/Nouveau/TTM

2020-05-12 Thread Christian König

Am 11.05.20 um 22:46 schrieb Alex Deucher:

On Mon, May 11, 2020 at 4:41 PM John Paul Adrian Glaubitz
 wrote:

On 5/11/20 10:05 PM, Alex Deucher wrote:

For Nouveau I'm not 100% sure, but from the code it of hand looks like we can 
do it similar to Radeon.

Please comment what you think about this.

I would be against such a move as AGP graphics is still used by people running 
the powerpc
and ppc64 Debian ports on their vintage hardware [1].

I have also CC'ed the debian-powerpc mailing list so that other users can voice 
their
opinion.

Note there is no loss of functionality here, at least on radeon
hardware.  It just comes down to which MMU gets used for access to
system memory, the AGP MMU on the chipset or the MMU built into the
GPU.  On powerpc hardware, AGP has been particularly unstable, and
IIRC, AGP has been disabled by default on radeon on powerpc for a
while.

Do you have a code reference at hand for this bit of information (AGP
being disabled on Macs)?

It was disabled 2 years ago:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=037d1a66ae640ca2723f47c0115ffa9e603699b3


To be honest from the hacks we have in there to get this working I'm 
even surprised that this ever worked at all on PowerPC.


Going to extend this patch for now and add a config option to not 
compile in AGP GART support for TTM any more instead of removing it.


Christian.



Alex


Thanks,
Adrian

--
  .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer - glaub...@debian.org
`. `'   Freie Universitaet Berlin - glaub...@physik.fu-berlin.de
   `-GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-12 Thread Pekka Paalanen
On Mon, 11 May 2020 19:47:24 +0200
Hans de Goede  wrote:

> From: Rajat Jain 
> 
> Add support for generic electronic privacy screen properties, that
> can be added by systems that have an integrated EPS.
> 
> Changes in v2 (Hans de Goede)
> - Create 2 properties, "privacy-screen sw-state" and
>   "privacy-screen hw-state", to deal with devices where the OS might be
>   locked out of making state changes
> - Write kerneldoc explaining how the 2 properties work together, what
>   happens when changes to the state are made outside of the DRM code's
>   control, etc.
> 
> Signed-off-by: Rajat Jain 
> Co-authored-by: Hans de Goede 
> Signed-off-by: Hans de Goede 
> ---
>  Documentation/gpu/drm-kms.rst |   2 +
>  drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
>  drivers/gpu/drm/drm_connector.c   | 100 ++
>  include/drm/drm_connector.h   |  50 +++
>  4 files changed, 158 insertions(+)

...

> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 644f0ad10671..01360edc2376 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list 
> dp_colorspaces[] = {
>   *   can also expose this property to external outputs, in which case they
>   *   must support "None", which should be the default (since external screens
>   *   have a built-in scaler).
> + *
> + * privacy-screen sw-state, privacy-screen hw-state:
> + *   These 2 optional properties can be used to query the state of the
> + *   electronic privacy screen that is available on some displays; and in
> + *   some cases also control the state. If a driver implements these
> + *   properties then both properties must be present.
> + *
> + *   "privacy-screen hw-state" is read-only and reflects the actual state
> + *   of the privacy-screen, possible values: "Enabled", "Disabled,
> + *   "Enabled, locked", "Disabled, locked". The locked states indicate
> + *   that the state cannot be changed through the DRM API. E.g. there
> + *   might be devices where the firmware-setup options, or a hardware
> + *   slider-switch, offer always on / off modes.
> + *
> + *   "privacy-screen sw-state" can be set to change the privacy-screen state
> + *   when not locked. In this case the driver must update the hw-state
> + *   property to reflect the new state on completion of the commit of the
> + *   sw-state property. Setting the sw-state property when the hw-state is
> + *   locked must be interpreted by the driver as a request to change the
> + *   state to the set state when the hw-state becomes unlocked. E.g. if
> + *   "privacy-screen hw-state" is "Enabled, locked" and the sw-state
> + *   gets set to "Disabled" followed by the user unlocking the state by
> + *   changing the slider-switch position, then the driver must set the
> + *   state to "Disabled" upon receiving the unlock event.
> + *
> + *   In some cases the privacy-screen state might change outside of control
> + *   of the DRM code. E.g. there might be a firmware handled hotkey which
> + *   toggles the state, or the state might be changed through another

Hi,

in the above three lines, I'd use the term "hardware state" instead of
just "state" to be explicit. Or should it be "physical state" since
"hardware state" might be confused with "hw-state" property state?

I don't mind as long as it's unambiguous and distinguishes explicitly
between actual and the two property states.

> + *   userspace API such as writing /proc/acpi/ibm/lcdshadow. In this case
> + *   the driver must update both the hw-state and the sw-state to reflect
> + *   the new value, overwriting any pending state requests in the sw-state.
> + *
> + *   Note that the ability for the state to change outside of control of
> + *   the DRM master process means that userspace must not cache the value
> + *   of the sw-state. Ccaching the sw-state value and including it in later

Extra 'c' in "Caching".

> + *   atomic commits may lead to overriding a state change done through e.g.
> + *   a firmware handled hotkey. Therefor userspace must not include the
> + *   privacy-screen sw-state in an atomic commit unless it wants to change
> + *   its value.
>   */

This documentation and intended behaviour looks perfect to me. If you
can record an R-b just for the doc, please have:

Reviewed-by: Pekka Paalanen 

You can also downgrade that to Acked-by for the whole patch from my
behalf.


Thanks,
pq


pgpCzrF5Jao93.pgp
Description: OpenPGP digital signature
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC] Remove AGP support from Radeon/Nouveau/TTM

2020-05-12 Thread Michel Dänzer
On 2020-05-11 10:51 p.m., Alex Deucher wrote:
> On Mon, May 11, 2020 at 4:25 PM Rui Salvaterra  wrote:
>> A segunda, 11/05/2020, 21:21, Alex Deucher  escreveu:
>>>
>>> Note there is no loss of functionality here, at least on radeon
>>> hardware.  It just comes down to which MMU gets used for access to
>>> system memory, the AGP MMU on the chipset or the MMU built into the
>>> GPU.  On powerpc hardware, AGP has been particularly unstable, and
>>> IIRC, AGP has been disabled by default on radeon on powerpc for a
>>> while.
>>
>> So this basically just drops support for the AGP GART? What happens to the 
>> AGP signalling rates (beyond the base rate)?
> 
> I don't remember enough of the details, but I strongly doubt it was
> related to which MMU was used per se.  On r1xx/r2xx parts, AGP was
> effectively the non-snooped route to memory and the internal MMU only
> provided snooped (coherent) access to memory.  That and the limited
> TLB space are probably want limited performance in that case.  I don't
> recall what sort of TLBs the chipset GART tables provided.  On r3xx
> and newer the, on-chip MMU supported both snooped and unsnooped
> transactions and had more TLB space so the difference wasn't
> significant IIRC.

FWIW, on my last-generation PowerBook with RV350 (IIRC), there was a big
performance difference between AGP and PCI GART. The latter was sort of
usable for normal desktop operation, but not so much for OpenGL apps
(which were usable with AGP).


-- 
Earthling Michel Dänzer   |   https://redhat.com
Libre software enthusiast | Mesa and X developer
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-12 Thread Hans de Goede

Hi,

On 5/12/20 9:49 AM, Pekka Paalanen wrote:

On Mon, 11 May 2020 19:47:24 +0200
Hans de Goede  wrote:


From: Rajat Jain 

Add support for generic electronic privacy screen properties, that
can be added by systems that have an integrated EPS.

Changes in v2 (Hans de Goede)
- Create 2 properties, "privacy-screen sw-state" and
   "privacy-screen hw-state", to deal with devices where the OS might be
   locked out of making state changes
- Write kerneldoc explaining how the 2 properties work together, what
   happens when changes to the state are made outside of the DRM code's
   control, etc.

Signed-off-by: Rajat Jain 
Co-authored-by: Hans de Goede 
Signed-off-by: Hans de Goede 
---
  Documentation/gpu/drm-kms.rst |   2 +
  drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
  drivers/gpu/drm/drm_connector.c   | 100 ++
  include/drm/drm_connector.h   |  50 +++
  4 files changed, 158 insertions(+)


...


diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 644f0ad10671..01360edc2376 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list dp_colorspaces[] 
= {
   *can also expose this property to external outputs, in which case they
   *must support "None", which should be the default (since external screens
   *have a built-in scaler).
+ *
+ * privacy-screen sw-state, privacy-screen hw-state:
+ * These 2 optional properties can be used to query the state of the
+ * electronic privacy screen that is available on some displays; and in
+ * some cases also control the state. If a driver implements these
+ * properties then both properties must be present.
+ *
+ * "privacy-screen hw-state" is read-only and reflects the actual state
+ * of the privacy-screen, possible values: "Enabled", "Disabled,
+ * "Enabled, locked", "Disabled, locked". The locked states indicate
+ * that the state cannot be changed through the DRM API. E.g. there
+ * might be devices where the firmware-setup options, or a hardware
+ * slider-switch, offer always on / off modes.
+ *
+ * "privacy-screen sw-state" can be set to change the privacy-screen state
+ * when not locked. In this case the driver must update the hw-state
+ * property to reflect the new state on completion of the commit of the
+ * sw-state property. Setting the sw-state property when the hw-state is
+ * locked must be interpreted by the driver as a request to change the
+ * state to the set state when the hw-state becomes unlocked. E.g. if
+ * "privacy-screen hw-state" is "Enabled, locked" and the sw-state
+ * gets set to "Disabled" followed by the user unlocking the state by
+ * changing the slider-switch position, then the driver must set the
+ * state to "Disabled" upon receiving the unlock event.
+ *
+ * In some cases the privacy-screen state might change outside of control
+ * of the DRM code. E.g. there might be a firmware handled hotkey which
+ * toggles the state, or the state might be changed through another


Hi,

in the above three lines, I'd use the term "hardware state" instead of
just "state" to be explicit. Or should it be "physical state" since
"hardware state" might be confused with "hw-state" property state?


Maybe "actual state"? That is what is used a few lines higher:

'"privacy-screen hw-state" is read-only and reflects the actual state'

And you use it yourself to describe what we want below:


I don't mind as long as it's unambiguous and distinguishes explicitly
between actual and the two property states.


So since you and I both naturally described it as "actual state" without
thinking too much what we where writing at the time (I guess that applies
to your use too), "actual state" seems a good fit ?



+ * userspace API such as writing /proc/acpi/ibm/lcdshadow. In this case
+ * the driver must update both the hw-state and the sw-state to reflect
+ * the new value, overwriting any pending state requests in the sw-state.
+ *
+ * Note that the ability for the state to change outside of control of
+ * the DRM master process means that userspace must not cache the value
+ * of the sw-state. Ccaching the sw-state value and including it in later


Extra 'c' in "Caching".


Ack, will fix.


+ * atomic commits may lead to overriding a state change done through e.g.
+ * a firmware handled hotkey. Therefor userspace must not include the
+ * privacy-screen sw-state in an atomic commit unless it wants to change
+ * its value.
   */


This documentation and intended behaviour looks perfect to me.


Great I'm glad you like it.


If you
can record an R-b just for the doc, please have:

Reviewed-by: Pekka Paalanen 

You can also downgrade that to Acked-by for the whole patch from my
behalf.


I don't know of a way to add partial Reviewed-by tags, so unless
some

Re: [RFC] Remove AGP support from Radeon/Nouveau/TTM

2020-05-12 Thread Christian König

Am 11.05.20 um 22:56 schrieb Al Dunsmuir:

Hello Dave,

On Monday, May 11, 2020, 4:43:01 PM, Dave Airlie wrote:

On Tue, 12 May 2020 at 06:28, Alex Deucher  wrote:

[SNIP]

Maybe we can find some way to compartmentalise AGP further?
Dave.

Significantly   reduced  caching  on memory accesses definitely sounds
like something that would be noticeable and objectionable.

I would speculate that this would also vary a lot across chipsets,
depending on the capabilities of the PCI MMU vs the AGP MMU.

In the end, it may be best to leave things as is, or as Dave suggested
try to keep AGP in the picture.


The problem is that AGP was never really supported/implemented that well 
in the first place.


The fact that the core linux kernel and the DMA API doesn't support 
uncached memory and we had to change the caching attributes of pages 
under the hood has resulted in a huge number of problems over the years.


Keeping it as it is is also not a really doable option because TTM 
already has major problems keeping up with the requirements for modern 
hardware, see my presentation here as well: 
https://fosdem.org/2020/schedule/event/ttm/


Redesigning the old AGP support into something which isn't so ugly and 
doesn't blocks the new requirements has the huge risk of breaking things 
even harder, e.g. black screen instead of just reduced performance.


So removing/disabling AGP by default still sounds like the best option 
to me for end users.



Nothing is ever simple, is it?


At least not with AGP, no :) It has been a total beast to support and 
keep working.


Do I get this right that I can ping you to test things?

Thanks for the feedback,
Christian.


Al




___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2] drm/connector: Add support for privacy-screen properties (v2)

2020-05-12 Thread Hans de Goede

Hi,

On 5/11/20 10:04 PM, Rajat Jain wrote:

On Mon, May 11, 2020 at 10:47 AM Hans de Goede  wrote:


From: Rajat Jain 

Add support for generic electronic privacy screen properties, that
can be added by systems that have an integrated EPS.

Changes in v2 (Hans de Goede)
- Create 2 properties, "privacy-screen sw-state" and
   "privacy-screen hw-state", to deal with devices where the OS might be
   locked out of making state changes
- Write kerneldoc explaining how the 2 properties work together, what
   happens when changes to the state are made outside of the DRM code's
   control, etc.

Signed-off-by: Rajat Jain 
Co-authored-by: Hans de Goede 
Signed-off-by: Hans de Goede 



Ack, Thanks for doing this.



---
  Documentation/gpu/drm-kms.rst |   2 +
  drivers/gpu/drm/drm_atomic_uapi.c |   6 ++
  drivers/gpu/drm/drm_connector.c   | 100 ++
  include/drm/drm_connector.h   |  50 +++
  4 files changed, 158 insertions(+)

diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index 906771e03103..b72b1e0db343 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -445,6 +445,8 @@ Property Types and Blob Property Support
  .. kernel-doc:: drivers/gpu/drm/drm_property.c
 :export:

+.. _standard_connector_properties:
+
  Standard Connector Properties
  -

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index a1e5e262bae2..e56a11208515 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -766,6 +766,8 @@ static int drm_atomic_connector_set_property(struct 
drm_connector *connector,
fence_ptr);
 } else if (property == connector->max_bpc_property) {
 state->max_requested_bpc = val;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   state->privacy_screen_sw_state = val;
 } else if (connector->funcs->atomic_set_property) {
 return connector->funcs->atomic_set_property(connector,
 state, property, val);
@@ -842,6 +844,10 @@ drm_atomic_connector_get_property(struct drm_connector 
*connector,
 *val = 0;
 } else if (property == connector->max_bpc_property) {
 *val = state->max_requested_bpc;
+   } else if (property == connector->privacy_screen_sw_state_property) {
+   *val = state->privacy_screen_sw_state;
+   } else if (property == connector->privacy_screen_hw_state_property) {
+   *val = state->privacy_screen_hw_state;
 } else if (connector->funcs->atomic_get_property) {
 return connector->funcs->atomic_get_property(connector,
 state, property, val);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 644f0ad10671..01360edc2376 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1186,6 +1186,45 @@ static const struct drm_prop_enum_list dp_colorspaces[] 
= {
   * can also expose this property to external outputs, in which case they
   * must support "None", which should be the default (since external 
screens
   * have a built-in scaler).
+ *
+ * privacy-screen sw-state, privacy-screen hw-state:
+ * These 2 optional properties can be used to query the state of the
+ * electronic privacy screen that is available on some displays; and in
+ * some cases also control the state. If a driver implements these
+ * properties then both properties must be present.
+ *
+ * "privacy-screen hw-state" is read-only and reflects the actual state
+ * of the privacy-screen, possible values: "Enabled", "Disabled,
+ * "Enabled, locked", "Disabled, locked". The locked states indicate
+ * that the state cannot be changed through the DRM API. E.g. there
+ * might be devices where the firmware-setup options, or a hardware
+ * slider-switch, offer always on / off modes.



May be add: "This is what the userspace tools must use to query and
report the actual status at the moment, if needed"


Thank you, suggestions for improving the doc are always very welcome, so I
have tried adding this, both as is and with slightly changed wording. But it
always feels like it is just repeating earlier info. To me the
"reflect the actual state" from the beginning of the paragraph makes it
abundantly clear that this indeed is what userspace should use to get,
well, the actual state.


+ *
+ * "privacy-screen sw-state" can be set to change the privacy-screen state
+ * when not locked. In this case the driver must update the hw-state
+ * property to reflect the new state on completion of the commit of the
+ * sw-state property. Setting the sw-state property when the hw-state is
+ * locked must be interpreted by the driver as a reques

Re: [PATCH 1/3] drm/radeon: remove AGP support

2020-05-12 Thread Michel Dänzer
On 2020-05-11 10:12 p.m., Alex Deucher wrote:
> On Mon, May 11, 2020 at 1:17 PM Christian König
>  wrote:
>>
>> AGP is deprecated for 10+ years now and not used any more on modern hardware.
>>
>> Old hardware should continue to work in PCI mode.
> 
> Might want to clarify that there is no loss of functionality here.
> Something like:
> 
> "There is no loss of functionality here.  GPUs will continue to
> function.  This just drops the use of the AGP MMU in the chipset in
> favor of the MMU on the device which has proven to be much more
> reliable.  Due to its unreliability, AGP support has been disabled on
> PowerPC for years already so there is no change on PowerPC."

There's a difference between something being disabled by default or not
being available at all. We may decide it's worth it anyway, but let's do
it based on facts.


-- 
Earthling Michel Dänzer   |   https://redhat.com
Libre software enthusiast | Mesa and X developer
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2 0/1] drm/connector: Add support for privacy-screen properties

2020-05-12 Thread Hans de Goede

Hi,

On 5/11/20 9:55 PM, Rajat Jain wrote:

Hi Hans,

On Mon, May 11, 2020 at 10:47 AM Hans de Goede mailto:hdego...@redhat.com>> wrote:

Hi All,

This RFC takes Rajat's earlier patch for adding privacy-screen properties
infra to drm_connector.c and then adds the results of the discussion from
the "RFC: Drm-connector properties managed by another driver / privacy
screen support" mail thread on top, hence the v2.


Thank you so much for doing this. I was following the said discussion and 
eventually it became quite complex for me to understand and follow :-)


I hope the new doc text makes things clear again?



The most important thing here is big kernel-doc comment which gets added in
the first patch-chunk modifying drm_connector.c, this summarizes, or at
least tries to summarize, the conclusions of our previous discussion on
the userspace API and lays down the ground rules for how the 2 new
"privacy-screen sw-state" and  "privacy-screen hw-state" properties are
to be used both from the driver side as well as from the userspace side.

Other then that this modifies Rajat's patch to add 2 properties instead
of one, without much other changes.

Rajat, perhaps you can do a new version of your patch-set integration /
using this version of the properties and then if everyone is ok with
the proposed userspace API Jani can hopefully merge the whole set
through the i915 tree sometime during the 5.9 cycle.


SGTM. I have actually moved to working on something else now, so I will most 
likely wait for this patch to get merged, before rebasing my other / remaining 
patches on top of that.


We have the rule that code like this will not be merged until it has at least
one in kernel user. I plan to eventually use this too, but that is still
a while away as I first need to write a lcdshadow subsystem which the
thinkpad_acpi code can then use to register a lcdshadow device; and when
that all is in place, then I can hook it up on the drm code.

So since Jani said your patch-set was more or less ready I think it would
be best if you add my version of this to your patch-set and then post
a new version of your patch-set. But first let me do a v3 addressing
the remarks on doc text. Note I will wait a bit before sending out v3
to see if I get more feedback.

Regards,

Hans




Thanks & Best Regards,

Rajat

This RFC takes Rajat's earlier patch for adding privacy-screen properties
infra to drm_connector.c and then adds the results of the discussion from
the "RFC: Drm-connector properties managed by another driver / privacy
screen support" mail thread on top, hence the v2.

The most important thing here is big kernel-doc comment which gets added in
the first patch-chunk modifying drm_connector.c, this summarizes, or at
least tries to summarize, the conclusions of our previous discussion on
the userspace API and lays down the ground rules for how the 2 new
"privacy-screen sw-state" and  "privacy-screen hw-state" properties are
to be used both from the driver side as well as from the userspace side.

Other then that this modifies Rajat's patch to add 2 properties instead
of one, without much other changes.

Rajat, perhaps you can do a new version of your patch-set integration /
using this version of the properties and then if everyone is ok with
the proposed userspace API Jani can hopefully merge the whole set
through the i915 tree sometime during the 5.9 cycle.

Regards,

Hans

p.s.

I plan to start working on the lcdshadow subsystem next. As discussed the
plan for this subsystem is to allow drivers outside of the DRM subsys, such
as for example the thinkpad_acpi driver, to register a lcdshadow device,
which DRM drivers can then get a reference to and use to implement these
properties.



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 08/15] drm/mgag200: Set primary plane's format in separate helper function

2020-05-12 Thread Thomas Zimmermann
The primary plane's format registers are now updated in a
mgag200_set_format_regs().

v2:
* get bpp shift from helper function
* replace uint8_t with u8

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 109 -
 1 file changed, 69 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index dee7838d7d368..38556f57ad218 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1044,6 +1044,68 @@ static void mgag200_set_offset(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
 }
 
+static void mgag200_set_format_regs(struct mga_device *mdev,
+   const struct drm_framebuffer *fb)
+{
+   struct drm_device *dev = mdev->dev;
+   const struct drm_format_info *format = fb->format;
+   unsigned int bpp, bppshift, scale;
+   u8 crtcext3, xmulctrl;
+
+   bpp = format->cpp[0] * 8;
+
+   bppshift = mgag200_get_bpp_shift(mdev, format);
+   switch (bpp) {
+   case 24:
+   scale = ((1 << bppshift) * 3) - 1;
+   break;
+   default:
+   scale = (1 << bppshift) - 1;
+   break;
+   }
+
+   RREG_ECRT(3, crtcext3);
+
+   switch (bpp) {
+   case 8:
+   xmulctrl = MGA1064_MUL_CTL_8bits;
+   break;
+   case 16:
+   if (format->depth == 15)
+   xmulctrl = MGA1064_MUL_CTL_15bits;
+   else
+   xmulctrl = MGA1064_MUL_CTL_16bits;
+   break;
+   case 24:
+   xmulctrl = MGA1064_MUL_CTL_24bits;
+   break;
+   case 32:
+   xmulctrl = MGA1064_MUL_CTL_32_24bits;
+   break;
+   default:
+   /* BUG: We should have caught this problem already. */
+   drm_WARN_ON(dev, "invalid format depth\n");
+   return;
+   }
+
+   crtcext3 &= ~GENMASK(2, 0);
+   crtcext3 |= scale;
+
+   WREG_DAC(MGA1064_MUL_CTL, xmulctrl);
+
+   WREG_GFX(0, 0x00);
+   WREG_GFX(1, 0x00);
+   WREG_GFX(2, 0x00);
+   WREG_GFX(3, 0x00);
+   WREG_GFX(4, 0x00);
+   WREG_GFX(5, 0x40);
+   WREG_GFX(6, 0x05);
+   WREG_GFX(7, 0x0f);
+   WREG_GFX(8, 0x0f);
+
+   WREG_ECRT(3, crtcext3);
+}
+
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -1055,8 +1117,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
int option = 0, option2 = 0;
int i;
unsigned char misc = 0;
-   unsigned char ext_vga[6];
-   u8 bppshift;
+   u8 crtcext3, crtcext4;
 
static unsigned char dacvalue[] = {
/* 0x00: */0,0,0,0,0,0, 0x00,0,
@@ -1071,8 +1132,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
/* 0x48: */0,0,0,0,0,0,0,0
};
 
-   bppshift = mdev->bpp_shifts[fb->format->cpp[0] - 1];
-
switch (mdev->type) {
case G200_SE_A:
case G200_SE_B:
@@ -,24 +1170,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
break;
}
 
-   switch (fb->format->cpp[0] * 8) {
-   case 8:
-   dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
-   break;
-   case 16:
-   if (fb->format->depth == 15)
-   dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
-   else
-   dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
-   break;
-   case 24:
-   dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits;
-   break;
-   case 32:
-   dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits;
-   break;
-   }
-
for (i = 0; i < sizeof(dacvalue); i++) {
if ((i <= 0x17) ||
(i == 0x1b) ||
@@ -1162,16 +1203,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_SEQ(3, 0);
WREG_SEQ(4, 0xe);
 
-   WREG_GFX(0, 0);
-   WREG_GFX(1, 0);
-   WREG_GFX(2, 0);
-   WREG_GFX(3, 0);
-   WREG_GFX(4, 0);
-   WREG_GFX(5, 0x40);
-   WREG_GFX(6, 0x5);
-   WREG_GFX(7, 0xf);
-   WREG_GFX(8, 0xf);
-
WREG_CRT(10, 0);
WREG_CRT(11, 0);
WREG_CRT(12, 0);
@@ -1179,16 +1210,13 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_CRT(14, 0);
WREG_CRT(15, 0);
 
-   /* TODO interlace */
+   RREG_ECRT(0x03, crtcext3);
 
-   if (fb->format->cpp[0] * 8 == 24)
-   ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
-   else
-   ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
-   ext_vga[4

[PATCH v2 04/15] drm/mgag200: Move mode-setting code into separate helper function

2020-05-12 Thread Thomas Zimmermann
The mode-setting code is now located in mgag200_set_mode_regs(), sans
a few flags that will be moved in a later patch for clarity.

v2:
* replace uint8_t with u8

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 140 ++---
 1 file changed, 78 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 9aa6addbbb895..7c41bd43f79e0 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -911,6 +911,79 @@ static int mga_crtc_mode_set_base(struct drm_crtc *crtc, 
int x, int y,
return mga_crtc_do_set_base(mdev, fb, old_fb);
 }
 
+static void mgag200_set_mode_regs(struct mga_device *mdev,
+ const struct drm_display_mode *mode)
+{
+   unsigned int hdisplay, hsyncstart, hsyncend, htotal;
+   unsigned int vdisplay, vsyncstart, vsyncend, vtotal;
+   u8 misc = 0;
+   u8 crtcext1, crtcext2, crtcext5;
+
+   hdisplay = mode->hdisplay / 8 - 1;
+   hsyncstart = mode->hsync_start / 8 - 1;
+   hsyncend = mode->hsync_end / 8 - 1;
+   htotal = mode->htotal / 8 - 1;
+
+   /* Work around hardware quirk */
+   if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04)
+   htotal++;
+
+   vdisplay = mode->vdisplay - 1;
+   vsyncstart = mode->vsync_start - 1;
+   vsyncend = mode->vsync_end - 1;
+   vtotal = mode->vtotal - 2;
+
+   if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+   misc |= 0x40;
+   if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+   misc |= 0x80;
+
+   crtcext1 = (((htotal - 4) & 0x100) >> 8) |
+  ((hdisplay & 0x100) >> 7) |
+  ((hsyncstart & 0x100) >> 6) |
+   (htotal & 0x40);
+   if (mdev->type == G200_WB || mdev->type == G200_EW3)
+   crtcext1 |= BIT(7) | /* vrsten */
+   BIT(3); /* hrsten */
+
+   crtcext2 = ((vtotal & 0xc00) >> 10) |
+  ((vdisplay & 0x400) >> 8) |
+  ((vdisplay & 0xc00) >> 7) |
+  ((vsyncstart & 0xc00) >> 5) |
+  ((vdisplay & 0x400) >> 3);
+   crtcext5 = 0x00;
+
+   WREG_CRT(0, htotal - 4);
+   WREG_CRT(1, hdisplay);
+   WREG_CRT(2, hdisplay);
+   WREG_CRT(3, (htotal & 0x1F) | 0x80);
+   WREG_CRT(4, hsyncstart);
+   WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F));
+   WREG_CRT(6, vtotal & 0xFF);
+   WREG_CRT(7, ((vtotal & 0x100) >> 8) |
+((vdisplay & 0x100) >> 7) |
+((vsyncstart & 0x100) >> 6) |
+((vdisplay & 0x100) >> 5) |
+((vdisplay & 0x100) >> 4) | /* linecomp */
+((vtotal & 0x200) >> 4) |
+((vdisplay & 0x200) >> 3) |
+((vsyncstart & 0x200) >> 2));
+   WREG_CRT(9, ((vdisplay & 0x200) >> 4) |
+((vdisplay & 0x200) >> 3));
+   WREG_CRT(16, vsyncstart & 0xFF);
+   WREG_CRT(17, (vsyncend & 0x0F) | 0x20);
+   WREG_CRT(18, vdisplay & 0xFF);
+   WREG_CRT(20, 0);
+   WREG_CRT(21, vdisplay & 0xFF);
+   WREG_CRT(22, (vtotal + 1) & 0xFF);
+   WREG_CRT(23, 0xc3);
+   WREG_CRT(24, vdisplay & 0xFF);
+
+   WREG_ECRT(0x01, crtcext1);
+   WREG_ECRT(0x02, crtcext2);
+   WREG_ECRT(0x05, crtcext5);
+}
+
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -919,8 +992,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
const struct drm_framebuffer *fb = crtc->primary->fb;
-   int hdisplay, hsyncstart, hsyncend, htotal;
-   int vdisplay, vsyncstart, vsyncend, vtotal;
int pitch;
int option = 0, option2 = 0;
int i;
@@ -999,12 +1070,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
break;
}
 
-   if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-   misc |= 0x40;
-   if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-   misc |= 0x80;
-
-
for (i = 0; i < sizeof(dacvalue); i++) {
if ((i <= 0x17) ||
(i == 0x1b) ||
@@ -1044,20 +1109,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
else
pitch = pitch >> (4 - bppshift);
 
-   hdisplay = mode->hdisplay / 8 - 1;
-   hsyncstart = mode->hsync_start / 8 - 1;
-   hsyncend = mode->hsync_end / 8 - 1;
-   htotal = mode->htotal / 8 - 1;
-
-   /* Work around hardware quirk */
-   if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04)
-   htotal++;
-
-   vdisplay = mode->vdisplay - 1;
-   vsyncstart = mode->vsync_start - 1;
-   v

[PATCH v2 11/15] drm/mgag200: Move register initialization into separate function

2020-05-12 Thread Thomas Zimmermann
Registers are initialized with constants. This is now done in
mgag200_init_regs(), mgag200_set_dac_regs() and mgag200_set_pci_regs().
Later patches should move these calls from mode setting to device
initialization.

v2:
* replace uint8_t with u8

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 261 ++---
 1 file changed, 147 insertions(+), 114 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 46122fa319889..199ae08976e16 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -919,6 +919,152 @@ static int mga_crtc_mode_set_base(struct drm_crtc *crtc, 
int x, int y,
return mga_crtc_do_set_base(mdev, fb, old_fb);
 }
 
+static void mgag200_set_pci_regs(struct mga_device *mdev)
+{
+   uint32_t option = 0, option2 = 0;
+   struct drm_device *dev = mdev->dev;
+
+   switch (mdev->type) {
+   case G200_SE_A:
+   case G200_SE_B:
+   if (mdev->has_sdram)
+   option = 0x40049120;
+   else
+   option = 0x4004d120;
+   option2 = 0x8000;
+   break;
+   case G200_WB:
+   case G200_EW3:
+   option = 0x41049120;
+   option2 = 0xb000;
+   break;
+   case G200_EV:
+   option = 0x0120;
+   option2 = 0xb000;
+   break;
+   case G200_EH:
+   case G200_EH3:
+   option = 0x0120;
+   option2 = 0xb000;
+   break;
+   case G200_ER:
+   break;
+   }
+
+   if (option)
+   pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
+
+   if (option2)
+   pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
+}
+
+static void mgag200_set_dac_regs(struct mga_device *mdev)
+{
+   size_t i;
+   u8 dacvalue[] = {
+   /* 0x00: */0,0,0,0,0,0, 0x00,0,
+   /* 0x08: */0,0,0,0,0,0,0,0,
+   /* 0x10: */0,0,0,0,0,0,0,0,
+   /* 0x18: */ 0x00,0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
+   /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   /* 0x28: */ 0x00, 0x00, 0x00, 0x00,0,0,0, 0x40,
+   /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
+   /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A,
+   /* 0x40: */0,0,0,0,0,0,0,0,
+   /* 0x48: */0,0,0,0,0,0,0,0
+   };
+
+   switch (mdev->type) {
+   case G200_SE_A:
+   case G200_SE_B:
+   dacvalue[MGA1064_VREF_CTL] = 0x03;
+   dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
+   dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN |
+MGA1064_MISC_CTL_VGA8 |
+MGA1064_MISC_CTL_DAC_RAM_CS;
+   break;
+   case G200_WB:
+   case G200_EW3:
+   dacvalue[MGA1064_VREF_CTL] = 0x07;
+   break;
+   case G200_EV:
+   dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
+   dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
+MGA1064_MISC_CTL_DAC_RAM_CS;
+   break;
+   case G200_EH:
+   case G200_EH3:
+   dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
+MGA1064_MISC_CTL_DAC_RAM_CS;
+   break;
+   case G200_ER:
+   break;
+   }
+
+   for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
+   if ((i <= 0x17) ||
+   (i == 0x1b) ||
+   (i == 0x1c) ||
+   ((i >= 0x1f) && (i <= 0x29)) ||
+   ((i >= 0x30) && (i <= 0x37)))
+   continue;
+   if (IS_G200_SE(mdev) &&
+   ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)))
+   continue;
+   if ((mdev->type == G200_EV ||
+   mdev->type == G200_WB ||
+   mdev->type == G200_EH ||
+   mdev->type == G200_EW3 ||
+   mdev->type == G200_EH3) &&
+   (i >= 0x44) && (i <= 0x4e))
+   continue;
+
+   WREG_DAC(i, dacvalue[i]);
+   }
+
+   if (mdev->type == G200_ER)
+   WREG_DAC(0x90, 0);
+}
+
+static void mgag200_init_regs(struct mga_device *mdev)
+{
+   u8 crtcext3, crtcext4, misc;
+
+   mgag200_set_pci_regs(mdev);
+   mgag200_set_dac_reg

[PATCH v2 00/15] drm/mgag200: Convert to atomic modesetting

2020-05-12 Thread Thomas Zimmermann
This patchset converts mgag200 to atomic modesetting. It uses simple
KMS helpers and SHMEM.

Patch 1 removes cursor support. The HW cursor is not usable with the
way universal planes work.

Patches 2 to 11 untangle the existing modesetting code into smaller
functions. Specifically, mode setting and plane updates are being
separated from each other.

Patch 12 to 14 convert mgag200 to simple KMS helpers and enables atomic
mode setting.

Atomically switching plane framebuffers, requires either source or target
buffer to be located at a non-0 offet. As some HW revisions seem to require
a framebuffer offset of 0 within the video memory, they do not work with
atomic modesetting. To resolve this problem, patch 15 converts mgag200
from VRAM helpers to SHMEM helpers. During plane updates, the content of
the SHMEM BO is memcpy'd to VRAM. From my observation, performance is not
nuch different from the original code.

The patchset has been tested on MGA G200EH hardware.

v2:
* rebase patchset
* replace uint{8,32}_t with u{8,32} through-out patchset
* define additional register constants
* use helper functions around bpp-shift computations
* split conversion patch
* cleanups

Thomas Zimmermann (15):
  drm/mgag200: Remove HW cursor
  drm/mgag200: Clean up mga_set_start_address()
  drm/mgag200: Clean up mga_crtc_do_set_base()
  drm/mgag200: Move mode-setting code into separate helper function
  drm/mgag200: Split MISC register update into PLL selection, SYNC and
I/O
  drm/mgag200: Update mode registers after plane registers
  drm/mgag200: Set pitch in a separate helper function
  drm/mgag200: Set primary plane's format in separate helper function
  drm/mgag200: Move TAGFIFO reset into separate function
  drm/mgag200: Move hiprilvl setting into separate functions
  drm/mgag200: Move register initialization into separate function
  drm/mgag200: Remove out-commented suspend/resume helpers
  drm/mgag200: Use simple-display data structures
  drm/mgag200: Convert to simple KMS helper
  drm/mgag200: Replace VRAM helpers with SHMEM helpers

 drivers/gpu/drm/mgag200/Kconfig|   4 +-
 drivers/gpu/drm/mgag200/Makefile   |   2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c  |  51 +-
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  41 +-
 drivers/gpu/drm/mgag200/mgag200_main.c |   5 -
 drivers/gpu/drm/mgag200/mgag200_mode.c | 871 ++---
 drivers/gpu/drm/mgag200/mgag200_reg.h  |  11 +-
 drivers/gpu/drm/mgag200/mgag200_ttm.c  |  28 +-
 8 files changed, 528 insertions(+), 485 deletions(-)

--
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 03/15] drm/mgag200: Clean up mga_crtc_do_set_base()

2020-05-12 Thread Thomas Zimmermann
The function now only takes the device structure, and the old and new
framebuffers.

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 80a3a805c0c4e..9aa6addbbb895 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -861,21 +861,20 @@ static void mgag200_set_startadd(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
 }
 
-static int mga_crtc_do_set_base(struct drm_crtc *crtc,
-   struct drm_framebuffer *fb,
-   int x, int y, int atomic)
+static int mga_crtc_do_set_base(struct mga_device *mdev,
+   const struct drm_framebuffer *fb,
+   const struct drm_framebuffer *old_fb)
 {
-   struct mga_device *mdev = to_mga_device(crtc->dev);
struct drm_gem_vram_object *gbo;
int ret;
s64 gpu_addr;
 
-   if (!atomic && fb) {
-   gbo = drm_gem_vram_of_gem(fb->obj[0]);
+   if (old_fb) {
+   gbo = drm_gem_vram_of_gem(old_fb->obj[0]);
drm_gem_vram_unpin(gbo);
}
 
-   gbo = drm_gem_vram_of_gem(crtc->primary->fb->obj[0]);
+   gbo = drm_gem_vram_of_gem(fb->obj[0]);
 
ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
if (ret)
@@ -900,6 +899,7 @@ static int mga_crtc_mode_set_base(struct drm_crtc *crtc, 
int x, int y,
 {
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = dev->dev_private;
+   struct drm_framebuffer *fb = crtc->primary->fb;
unsigned int count;
 
do { } while (RREG8(0x1fda) & 0x08);
@@ -908,7 +908,7 @@ static int mga_crtc_mode_set_base(struct drm_crtc *crtc, 
int x, int y,
count = RREG8(MGAREG_VCOUNT) + 2;
do { } while (RREG8(MGAREG_VCOUNT) < count);
 
-   return mga_crtc_do_set_base(crtc, old_fb, x, y, 0);
+   return mga_crtc_do_set_base(mdev, fb, old_fb);
 }
 
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
@@ -1150,7 +1150,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 
WREG8(MGA_MISC_OUT, misc);
 
-   mga_crtc_do_set_base(crtc, old_fb, x, y, 0);
+   mga_crtc_do_set_base(mdev, fb, old_fb);
 
/* reset tagfifo */
if (mdev->type == G200_ER) {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 05/15] drm/mgag200: Split MISC register update into PLL selection, SYNC and I/O

2020-05-12 Thread Thomas Zimmermann
Set different fields in MISC in their rsp location in the code. This
patch also fixes a bug in the original code where the mode's SYNC flags
were never written into the MISC register.

v2:
* use u8 instead of uint8_t
* define MGAREG_MISC_CLK_SEL_MASK

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 38 ++
 drivers/gpu/drm/mgag200/mgag200_reg.h  |  6 +++-
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 7c41bd43f79e0..2007d7a4754ac 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -704,6 +704,8 @@ static int mga_g200er_set_plls(struct mga_device *mdev, 
long clock)
 
 static int mga_crtc_set_plls(struct mga_device *mdev, long clock)
 {
+   u8 misc;
+
switch(mdev->type) {
case G200_SE_A:
case G200_SE_B:
@@ -724,6 +726,12 @@ static int mga_crtc_set_plls(struct mga_device *mdev, long 
clock)
return mga_g200er_set_plls(mdev, clock);
break;
}
+
+   misc = RREG8(MGA_MISC_IN);
+   misc &= ~MGAREG_MISC_CLK_SEL_MASK;
+   misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
+   WREG8(MGA_MISC_OUT, misc);
+
return 0;
 }
 
@@ -916,8 +924,7 @@ static void mgag200_set_mode_regs(struct mga_device *mdev,
 {
unsigned int hdisplay, hsyncstart, hsyncend, htotal;
unsigned int vdisplay, vsyncstart, vsyncend, vtotal;
-   u8 misc = 0;
-   u8 crtcext1, crtcext2, crtcext5;
+   u8 misc, crtcext1, crtcext2, crtcext5;
 
hdisplay = mode->hdisplay / 8 - 1;
hsyncstart = mode->hsync_start / 8 - 1;
@@ -933,10 +940,17 @@ static void mgag200_set_mode_regs(struct mga_device *mdev,
vsyncend = mode->vsync_end - 1;
vtotal = mode->vtotal - 2;
 
+   misc = RREG8(MGA_MISC_IN);
+
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-   misc |= 0x40;
+   misc |= MGAREG_MISC_HSYNCPOL;
+   else
+   misc &= ~MGAREG_MISC_HSYNCPOL;
+
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-   misc |= 0x80;
+   misc |= MGAREG_MISC_VSYNCPOL;
+   else
+   misc &= ~MGAREG_MISC_VSYNCPOL;
 
crtcext1 = (((htotal - 4) & 0x100) >> 8) |
   ((hdisplay & 0x100) >> 7) |
@@ -982,6 +996,10 @@ static void mgag200_set_mode_regs(struct mga_device *mdev,
WREG_ECRT(0x01, crtcext1);
WREG_ECRT(0x02, crtcext2);
WREG_ECRT(0x05, crtcext5);
+
+   WREG8(MGA_MISC_OUT, misc);
+
+   mga_crtc_set_plls(mdev, mode->clock);
 }
 
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
@@ -1140,12 +1158,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
ext_vga[4] = 0;
 
-   /* Set pixel clocks */
-   misc = 0x2d;
-   WREG8(MGA_MISC_OUT, misc);
-
-   mga_crtc_set_plls(mdev, mode->clock);
-
WREG_ECRT(0, ext_vga[0]);
WREG_ECRT(3, ext_vga[3]);
WREG_ECRT(4, ext_vga[4]);
@@ -1161,9 +1173,11 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
}
 
WREG_ECRT(0, ext_vga[0]);
-   /* Enable mga pixel clock */
-   misc = 0x2d;
 
+   misc = RREG8(MGA_MISC_IN);
+   misc |= MGAREG_MISC_IOADSEL |
+   MGAREG_MISC_RAMMAPEN |
+   MGAREG_MISC_HIGH_PG_SEL;
WREG8(MGA_MISC_OUT, misc);
 
mga_crtc_do_set_base(mdev, fb, old_fb);
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h 
b/drivers/gpu/drm/mgag200/mgag200_reg.h
index c096a9d6bcbc1..0ba6e15e97106 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -16,10 +16,11 @@
  * MGA1064SG Mystique register file
  */
 
-
 #ifndef _MGA_REG_H_
 #define _MGA_REG_H_
 
+#include 
+
 #defineMGAREG_DWGCTL   0x1c00
 #defineMGAREG_MACCESS  0x1c04
 /* the following is a mystique only register */
@@ -221,12 +222,15 @@
 
 #define MGAREG_MISC_IOADSEL(0x1 << 0)
 #define MGAREG_MISC_RAMMAPEN   (0x1 << 1)
+#define MGAREG_MISC_CLK_SEL_MASK   GENMASK(3, 2)
 #define MGAREG_MISC_CLK_SEL_VGA25  (0x0 << 2)
 #define MGAREG_MISC_CLK_SEL_VGA28  (0x1 << 2)
 #define MGAREG_MISC_CLK_SEL_MGA_PIX(0x2 << 2)
 #define MGAREG_MISC_CLK_SEL_MGA_MSK(0x3 << 2)
 #define MGAREG_MISC_VIDEO_DIS  (0x1 << 4)
 #define MGAREG_MISC_HIGH_PG_SEL(0x1 << 5)
+#define MGAREG_MISC_HSYNCPOL   BIT(6)
+#define MGAREG_MISC_VSYNCPOL   BIT(7)
 
 /* MMIO VGA registers */
 #define MGAREG_SEQ_INDEX   0x1fc4
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 07/15] drm/mgag200: Set pitch in a separate helper function

2020-05-12 Thread Thomas Zimmermann
The framebuffer's pitch is now set in mgag200_set_offset().

v2:
* move offset and bpp-shift calculation into helper functions
* use u8 instead of uint8_t
* add MGAREG_CRTCEXT0_OFFSET_MASK

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 57 +++---
 drivers/gpu/drm/mgag200/mgag200_reg.h  |  2 +
 2 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 4dba0a379c263..dee7838d7d368 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1002,6 +1002,48 @@ static void mgag200_set_mode_regs(struct mga_device 
*mdev,
mga_crtc_set_plls(mdev, mode->clock);
 }
 
+static u8 mgag200_get_bpp_shift(struct mga_device *mdev,
+   const struct drm_format_info *format)
+{
+   return mdev->bpp_shifts[format->cpp[0] - 1];
+}
+
+/*
+ * Calculates the HW offset value from the framebuffer's pitch. The
+ * offset is a multiple of the pixel size and depends on the display
+ * format.
+ */
+static u32 mgag200_calculate_offset(struct mga_device *mdev,
+   const struct drm_framebuffer *fb)
+{
+   u32 offset = fb->pitches[0] / fb->format->cpp[0];
+   u8 bppshift = mgag200_get_bpp_shift(mdev, fb->format);
+
+   if (fb->format->cpp[0] * 8 == 24)
+   offset = (offset * 3) >> (4 - bppshift);
+   else
+   offset = offset >> (4 - bppshift);
+
+   return offset;
+}
+
+static void mgag200_set_offset(struct mga_device *mdev,
+  const struct drm_framebuffer *fb)
+{
+   u8 crtc13, crtcext0;
+   u32 offset = mgag200_calculate_offset(mdev, fb);
+
+   RREG_ECRT(0, crtcext0);
+
+   crtc13 = offset & 0xff;
+
+   crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK;
+   crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK;
+
+   WREG_CRT(0x13, crtc13);
+   WREG_ECRT(0x00, crtcext0);
+}
+
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -1010,7 +1052,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
const struct drm_framebuffer *fb = crtc->primary->fb;
-   int pitch;
int option = 0, option2 = 0;
int i;
unsigned char misc = 0;
@@ -1121,12 +1162,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_SEQ(3, 0);
WREG_SEQ(4, 0xe);
 
-   pitch = fb->pitches[0] / fb->format->cpp[0];
-   if (fb->format->cpp[0] * 8 == 24)
-   pitch = (pitch * 3) >> (4 - bppshift);
-   else
-   pitch = pitch >> (4 - bppshift);
-
WREG_GFX(0, 0);
WREG_GFX(1, 0);
WREG_GFX(2, 0);
@@ -1143,20 +1178,15 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_CRT(13, 0);
WREG_CRT(14, 0);
WREG_CRT(15, 0);
-   WREG_CRT(19, pitch & 0xFF);
-
-   ext_vga[0] = 0;
 
/* TODO interlace */
 
-   ext_vga[0] |= (pitch & 0x300) >> 4;
if (fb->format->cpp[0] * 8 == 24)
ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
else
ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
ext_vga[4] = 0;
 
-   WREG_ECRT(0, ext_vga[0]);
WREG_ECRT(3, ext_vga[3]);
WREG_ECRT(4, ext_vga[4]);
 
@@ -1170,8 +1200,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_ECRT(6, 0);
}
 
-   WREG_ECRT(0, ext_vga[0]);
-
misc = RREG8(MGA_MISC_IN);
misc |= MGAREG_MISC_IOADSEL |
MGAREG_MISC_RAMMAPEN |
@@ -1179,6 +1207,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG8(MGA_MISC_OUT, misc);
 
mga_crtc_do_set_base(mdev, fb, old_fb);
+   mgag200_set_offset(mdev, fb);
 
mgag200_set_mode_regs(mdev, mode);
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h 
b/drivers/gpu/drm/mgag200/mgag200_reg.h
index 0ba6e15e97106..cd08dee29b06f 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -240,6 +240,8 @@
 #define MGAREG_CRTCEXT_INDEX   0x1fde
 #define MGAREG_CRTCEXT_DATA0x1fdf
 
+#define MGAREG_CRTCEXT0_OFFSET_MASKGENMASK(5, 4)
+
 /* Cursor X and Y position */
 #define MGA_CURPOSXL 0x3c0c
 #define MGA_CURPOSXH 0x3c0d
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 13/15] drm/mgag200: Use simple-display data structures

2020-05-12 Thread Thomas Zimmermann
The MGA CRTC data structure struct mga_crtc contains unused additional
fields; so it can removed. The standard DRM CRTC and encoder structures
are embedded now in struct drm_simple_display_pipe. Done in preparation
of converting mgag200 to simple KMS helpers.

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_drv.h  | 11 ++
 drivers/gpu/drm/mgag200/mgag200_mode.c | 28 ++
 2 files changed, 8 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 0cf498d1e900c..2392baff618aa 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "mgag200_reg.h"
 
@@ -105,16 +106,8 @@
 
 #define MATROX_DPMS_CLEARED (-1)
 
-#define to_mga_crtc(x) container_of(x, struct mga_crtc, base)
 #define to_mga_connector(x) container_of(x, struct mga_connector, base)
 
-struct mga_crtc {
-   struct drm_crtc base;
-   u8 lut_r[256], lut_g[256], lut_b[256];
-   int last_dpms;
-   bool enabled;
-};
-
 struct mga_i2c_chan {
struct i2c_adapter adapter;
struct drm_device *dev;
@@ -175,7 +168,7 @@ struct mga_device {
u32 unique_rev_id;
 
struct mga_connector connector;
-   struct drm_encoder encoder;
+   struct drm_simple_display_pipe display_pipe;
 };
 
 static inline struct mga_device *to_mga_device(struct drm_device *dev)
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index d6f9763a4a450..00bbc1f9b7db3 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1475,15 +1475,6 @@ static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 
*red, u16 *green,
return 0;
 }
 
-/* Simple cleanup function */
-static void mga_crtc_destroy(struct drm_crtc *crtc)
-{
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
-
-   drm_crtc_cleanup(crtc);
-   kfree(mga_crtc);
-}
-
 static void mga_crtc_disable(struct drm_crtc *crtc)
 {
DRM_DEBUG_KMS("\n");
@@ -1501,7 +1492,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
 static const struct drm_crtc_funcs mga_crtc_funcs = {
.gamma_set = mga_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
-   .destroy = mga_crtc_destroy,
+   .destroy = drm_crtc_cleanup,
 };
 
 static const struct drm_crtc_helper_funcs mga_helper_funcs = {
@@ -1517,20 +1508,13 @@ static const struct drm_crtc_helper_funcs 
mga_helper_funcs = {
 static void mga_crtc_init(struct mga_device *mdev)
 {
struct drm_device *dev = mdev->dev;
-   struct mga_crtc *mga_crtc;
-
-   mga_crtc = kzalloc(sizeof(struct mga_crtc) +
- (MGAG200FB_CONN_LIMIT * sizeof(struct 
drm_connector *)),
- GFP_KERNEL);
-
-   if (mga_crtc == NULL)
-   return;
+   struct drm_crtc *crtc = &mdev->display_pipe.crtc;
 
-   drm_crtc_init(dev, &mga_crtc->base, &mga_crtc_funcs);
+   drm_crtc_init(dev, crtc, &mga_crtc_funcs);
 
-   drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
+   drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
 
-   drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs);
+   drm_crtc_helper_add(crtc, &mga_helper_funcs);
 }
 
 /*
@@ -1718,7 +1702,7 @@ static unsigned int mgag200_preferred_depth(struct 
mga_device *mdev)
 int mgag200_modeset_init(struct mga_device *mdev)
 {
struct drm_device *dev = mdev->dev;
-   struct drm_encoder *encoder = &mdev->encoder;
+   struct drm_encoder *encoder = &mdev->display_pipe.encoder;
struct drm_connector *connector = &mdev->connector.base;
int ret;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 01/15] drm/mgag200: Remove HW cursor

2020-05-12 Thread Thomas Zimmermann
The HW cursor of Matrox G200 cards only supports a 16-color palette
format. Univeral planes require at least ARGB or a similar component-
based format, so remove the HW cursor.

Alternatively, the driver could dither a cursor image from ARGB to
16 colors. But this does not produce pleasent-looking results in
general, so it's useless for modern compositors.

Without HW support, compositors will use software rendering.

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/Makefile   |  2 +-
 drivers/gpu/drm/mgag200/mgag200_drv.h  | 13 -
 drivers/gpu/drm/mgag200/mgag200_main.c |  5 -
 drivers/gpu/drm/mgag200/mgag200_mode.c |  2 --
 4 files changed, 1 insertion(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
index 04b281bcf6558..63403133638a3 100644
--- a/drivers/gpu/drm/mgag200/Makefile
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-mgag200-y   := mgag200_main.o mgag200_mode.o mgag200_cursor.o \
+mgag200-y   := mgag200_main.o mgag200_mode.o \
mgag200_drv.o mgag200_i2c.o mgag200_ttm.o
 
 obj-$(CONFIG_DRM_MGAG200) += mgag200.o
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index d9b7e96b214f8..bc372c2ec79e9 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -116,11 +116,6 @@ struct mga_connector {
struct mga_i2c_chan *i2c;
 };
 
-struct mga_cursor {
-   struct drm_gem_vram_object *gbo[2];
-   unsigned int next_index;
-};
-
 struct mga_mc {
resource_size_t vram_size;
resource_size_t vram_base;
@@ -156,8 +151,6 @@ struct mga_device {
 
struct mga_mc   mc;
 
-   struct mga_cursor cursor;
-
size_t vram_fb_available;
 
boolsuspended;
@@ -207,10 +200,4 @@ int mgag200_mm_init(struct mga_device *mdev);
 void mgag200_mm_fini(struct mga_device *mdev);
 int mgag200_mmap(struct file *filp, struct vm_area_struct *vma);
 
-int mgag200_cursor_init(struct mga_device *mdev);
-void mgag200_cursor_fini(struct mga_device *mdev);
-int mgag200_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
-   uint32_t handle, uint32_t width, uint32_t height);
-int mgag200_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
-
 #endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c 
b/drivers/gpu/drm/mgag200/mgag200_main.c
index 86df799fd38c5..3298eff7bd1b4 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -135,10 +135,6 @@ int mgag200_driver_load(struct drm_device *dev, unsigned 
long flags)
goto err_mgag200_mm_fini;
}
 
-   ret = mgag200_cursor_init(mdev);
-   if (ret)
-   drm_err(dev, "Could not initialize cursors. Not doing hardware 
cursors.\n");
-
return 0;
 
 err_mgag200_mm_fini:
@@ -154,7 +150,6 @@ void mgag200_driver_unload(struct drm_device *dev)
 
if (mdev == NULL)
return;
-   mgag200_cursor_fini(mdev);
mgag200_mm_fini(mdev);
dev->dev_private = NULL;
 }
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 5f4ac36a97760..c68ed8b6faf9b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1412,8 +1412,6 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
 
 /* These provide the minimum set of functions required to handle a CRTC */
 static const struct drm_crtc_funcs mga_crtc_funcs = {
-   .cursor_set = mgag200_crtc_cursor_set,
-   .cursor_move = mgag200_crtc_cursor_move,
.gamma_set = mga_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
.destroy = mga_crtc_destroy,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 06/15] drm/mgag200: Update mode registers after plane registers

2020-05-12 Thread Thomas Zimmermann
Setting the plane registers first and the mode registers afterwards
reproduces the sequence used by atomic helpers. Done in preparation
of switching to simple KMS helpers.

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 2007d7a4754ac..4dba0a379c263 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1145,8 +1145,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_CRT(15, 0);
WREG_CRT(19, pitch & 0xFF);
 
-   mgag200_set_mode_regs(mdev, mode);
-
ext_vga[0] = 0;
 
/* TODO interlace */
@@ -1182,6 +1180,8 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 
mga_crtc_do_set_base(mdev, fb, old_fb);
 
+   mgag200_set_mode_regs(mdev, mode);
+
/* reset tagfifo */
if (mdev->type == G200_ER) {
u32 mem_ctl = RREG32(MGAREG_MEMCTL);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 02/15] drm/mgag200: Clean up mga_set_start_address()

2020-05-12 Thread Thomas Zimmermann
All register names and fields are now named according to the
MGA programming manuals. The function doesn't need the CRTC, so
callers pass in the device structure directly. The logging now
uses device-specific macros.

v2:
* use to_mga_device()
* use MiB instead of MB
* replace empty while loop with do-while, fixes checkpatch warning
* replace uint{8,32}_t with u{8,32}

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
---
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  5 ++
 drivers/gpu/drm/mgag200/mgag200_mode.c | 82 +++---
 2 files changed, 53 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index bc372c2ec79e9..1963876ef3b8c 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -61,6 +61,11 @@
WREG8(MGAREG_CRTC_DATA, v); \
} while (0) \
 
+#define RREG_ECRT(reg, v)  \
+   do {\
+   WREG8(MGAREG_CRTCEXT_INDEX, reg);   \
+   v = RREG8(MGAREG_CRTCEXT_DATA); \
+   } while (0) \
 
 #define WREG_ECRT(reg, v)  \
do {\
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index c68ed8b6faf9b..80a3a805c0c4e 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -819,49 +819,53 @@ static void mga_g200wb_commit(struct drm_crtc *crtc)
 }
 
 /*
-   This is how the framebuffer base address is stored in g200 cards:
-   * Assume @offset is the gpu_addr variable of the framebuffer object
-   * Then addr is the number of _pixels_ (not bytes) from the start of
- VRAM to the first pixel we want to display. (divided by 2 for 32bit
- framebuffers)
-   * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
-   addr<20> -> CRTCEXT0<6>
-   addr<19-16> -> CRTCEXT0<3-0>
-   addr<15-8> -> CRTCC<7-0>
-   addr<7-0> -> CRTCD<7-0>
-   CRTCEXT0 has to be programmed last to trigger an update and make the
-   new addr variable take effect.
+ * This is how the framebuffer base address is stored in g200 cards:
+ *   * Assume @offset is the gpu_addr variable of the framebuffer object
+ *   * Then addr is the number of _pixels_ (not bytes) from the start of
+ * VRAM to the first pixel we want to display. (divided by 2 for 32bit
+ * framebuffers)
+ *   * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
+ *  addr<20> -> CRTCEXT0<6>
+ *  addr<19-16> -> CRTCEXT0<3-0>
+ *  addr<15-8> -> CRTCC<7-0>
+ *  addr<7-0> -> CRTCD<7-0>
+ *
+ *  CRTCEXT0 has to be programmed last to trigger an update and make the
+ *  new addr variable take effect.
  */
-static void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
+static void mgag200_set_startadd(struct mga_device *mdev,
+unsigned long offset)
 {
-   struct mga_device *mdev = to_mga_device(crtc->dev);
-   u32 addr;
-   int count;
-   u8 crtcext0;
+   struct drm_device *dev = mdev->dev;
+   u32 startadd;
+   u8 crtcc, crtcd, crtcext0;
 
-   while (RREG8(0x1fda) & 0x08);
-   while (!(RREG8(0x1fda) & 0x08));
+   startadd = offset / 8;
 
-   count = RREG8(MGAREG_VCOUNT) + 2;
-   while (RREG8(MGAREG_VCOUNT) < count);
-
-   WREG8(MGAREG_CRTCEXT_INDEX, 0);
-   crtcext0 = RREG8(MGAREG_CRTCEXT_DATA);
-   crtcext0 &= 0xB0;
-   addr = offset / 8;
-   /* Can't store addresses any higher than that...
-  but we also don't have more than 16MB of memory, so it should be 
fine. */
-   WARN_ON(addr > 0x1f);
-   crtcext0 |= (!!(addr & (1<<20)))<<6;
-   WREG_CRT(0x0d, (u8)(addr & 0xff));
-   WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff);
-   WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0);
+   /*
+* Can't store addresses any higher than that, but we also
+* don't have more than 16 MiB of memory, so it should be fine.
+*/
+   drm_WARN_ON(dev, startadd > 0x1f);
+
+   RREG_ECRT(0x00, crtcext0);
+
+   crtcc = (startadd >> 8) & 0xff;
+   crtcd = startadd & 0xff;
+   crtcext0 &= 0xb0;
+   crtcext0 |= ((startadd >> 14) & BIT(6)) |
+   ((startadd >> 16) & 0x0f);
+
+   WREG_CRT(0x0c, crtcc);
+   WREG_CRT(0x0d, crtcd);
+   WREG_ECRT(0x00, crtcext0);
 }
 
 static int mga_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int x, int y, int atomic)
 {
+   struct mga_device *mdev = to_mga_device(crtc->dev);
struct drm_gem_vram_object *gbo;
int ret;

[PATCH v2 14/15] drm/mgag200: Convert to simple KMS helper

2020-05-12 Thread Thomas Zimmermann
The mgag200 supports a single pipeline with only a primary plane. It can
be converted to simple KMS helpers. This also adds support for atomic
modesetting. Wayland compositors, which use pageflip ioctls, can now be
used with mgag200.

v2:
* prepare encoder and CRTC in a separate patch
* remove suspend/resume code in a separate patch
* don't call set_format_regs() in pipe_update()

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_drv.c  |   2 +-
 drivers/gpu/drm/mgag200/mgag200_mode.c | 314 +
 2 files changed, 164 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c 
b/drivers/gpu/drm/mgag200/mgag200_drv.c
index c2f0e4b40b052..a06ce4198adea 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -140,7 +140,7 @@ int mgag200_driver_dumb_create(struct drm_file *file,
 }
 
 static struct drm_driver driver = {
-   .driver_features = DRIVER_GEM | DRIVER_MODESET,
+   .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
.fops = &mgag200_driver_fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 00bbc1f9b7db3..b50c1beb7b7b9 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -11,10 +11,13 @@
 #include 
 #include 
 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -30,13 +33,18 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
 {
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
-   struct drm_framebuffer *fb = crtc->primary->fb;
+   struct drm_framebuffer *fb;
u16 *r_ptr, *g_ptr, *b_ptr;
int i;
 
if (!crtc->enabled)
return;
 
+   if (!mdev->display_pipe.plane.state)
+   return;
+
+   fb = mdev->display_pipe.plane.state->fb;
+
r_ptr = crtc->gamma_store;
g_ptr = r_ptr + crtc->gamma_size;
b_ptr = g_ptr + crtc->gamma_size;
@@ -869,56 +877,6 @@ static void mgag200_set_startadd(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
 }
 
-static int mga_crtc_do_set_base(struct mga_device *mdev,
-   const struct drm_framebuffer *fb,
-   const struct drm_framebuffer *old_fb)
-{
-   struct drm_gem_vram_object *gbo;
-   int ret;
-   s64 gpu_addr;
-
-   if (old_fb) {
-   gbo = drm_gem_vram_of_gem(old_fb->obj[0]);
-   drm_gem_vram_unpin(gbo);
-   }
-
-   gbo = drm_gem_vram_of_gem(fb->obj[0]);
-
-   ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
-   if (ret)
-   return ret;
-   gpu_addr = drm_gem_vram_offset(gbo);
-   if (gpu_addr < 0) {
-   ret = (int)gpu_addr;
-   goto err_drm_gem_vram_unpin;
-   }
-
-   mgag200_set_startadd(mdev, (unsigned long)gpu_addr);
-
-   return 0;
-
-err_drm_gem_vram_unpin:
-   drm_gem_vram_unpin(gbo);
-   return ret;
-}
-
-static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
-   struct drm_device *dev = crtc->dev;
-   struct mga_device *mdev = dev->dev_private;
-   struct drm_framebuffer *fb = crtc->primary->fb;
-   unsigned int count;
-
-   do { } while (RREG8(0x1fda) & 0x08);
-   do { } while (!(RREG8(0x1fda) & 0x08));
-
-   count = RREG8(MGAREG_VCOUNT) + 2;
-   do { } while (RREG8(MGAREG_VCOUNT) < count);
-
-   return mga_crtc_do_set_base(mdev, fb, old_fb);
-}
-
 static void mgag200_set_pci_regs(struct mga_device *mdev)
 {
uint32_t option = 0, option2 = 0;
@@ -1329,34 +1287,6 @@ static void mgag200_g200ev_set_hiprilvl(struct 
mga_device *mdev)
WREG_ECRT(0x06, 0x00);
 }
 
-static int mga_crtc_mode_set(struct drm_crtc *crtc,
-   struct drm_display_mode *mode,
-   struct drm_display_mode *adjusted_mode,
-   int x, int y, struct drm_framebuffer *old_fb)
-{
-   struct drm_device *dev = crtc->dev;
-   struct mga_device *mdev = to_mga_device(dev);
-   const struct drm_framebuffer *fb = crtc->primary->fb;
-
-   mgag200_init_regs(mdev);
-
-   mgag200_set_format_regs(mdev, fb);
-   mga_crtc_do_set_base(mdev, fb, old_fb);
-   mgag200_set_offset(mdev, fb);
-
-   mgag200_set_mode_regs(mdev, mode);
-
-   if (mdev->type == G200_ER)
-   mgag200_g200er_reset_tagfifo(mdev);
-
-   if (IS_G200_SE(mdev))
-   mgag200_g200se_set_hiprilvl(mdev, mode, fb);
-   else if (mdev->type == G200_EV)
-   mgag200_g200ev_set_hiprilvl(mdev);
-
-   return 0;
-}
-
 static void mg

[PATCH v2 15/15] drm/mgag200: Replace VRAM helpers with SHMEM helpers

2020-05-12 Thread Thomas Zimmermann
The VRAM helpers managed the framebuffer memory for mgag200. This came
with several problems, as some MGA device require the scanout address
to be located at VRAM offset 0. It's incompatible with the page-flip
semantics of DRM's atomic modesettting. With atomic modesetting, old and
new framebuffers have to be located in VRAM at the same time. So at least
one of them has to reside at a non-0 offset.

This patch replaces VRAM helpers with SHMEM helpers. GEM SHMEM buffers
reside in system memory, and are shadow-copied into VRAM during page
flips. The shadow copy always starts at VRAM offset 0.

v2:
* revert dev->pdev changes

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
---
 drivers/gpu/drm/mgag200/Kconfig|  4 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c  | 49 +-
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  5 ++-
 drivers/gpu/drm/mgag200/mgag200_mode.c | 58 --
 drivers/gpu/drm/mgag200/mgag200_ttm.c  | 28 +++--
 5 files changed, 56 insertions(+), 88 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
index d60aa4b9ccd47..93be766715c9b 100644
--- a/drivers/gpu/drm/mgag200/Kconfig
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -2,10 +2,8 @@
 config DRM_MGAG200
tristate "Kernel modesetting driver for MGA G200 server engines"
depends on DRM && PCI && MMU
+   select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
-   select DRM_VRAM_HELPER
-   select DRM_TTM
-   select DRM_TTM_HELPER
help
 This is a KMS driver for the MGA G200 server chips, it
 does not support the original MGA G200 or any of the desktop
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c 
b/drivers/gpu/drm/mgag200/mgag200_drv.c
index a06ce4198adea..00ddea7d7d270 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -22,15 +22,11 @@
  * which then performs further device association and calls our graphics init
  * functions
  */
-int mgag200_modeset = -1;
 
+int mgag200_modeset = -1;
 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
 module_param_named(modeset, mgag200_modeset, int, 0400);
 
-int mgag200_hw_bug_no_startadd = -1;
-MODULE_PARM_DESC(modeset, "HW does not interpret scanout-buffer start address 
correctly");
-module_param_named(hw_bug_no_startadd, mgag200_hw_bug_no_startadd, int, 0400);
-
 static struct drm_driver driver;
 
 static const struct pci_device_id pciidlist[] = {
@@ -101,44 +97,6 @@ static void mga_pci_remove(struct pci_dev *pdev)
 
 DEFINE_DRM_GEM_FOPS(mgag200_driver_fops);
 
-static bool mgag200_pin_bo_at_0(const struct mga_device *mdev)
-{
-   if (mgag200_hw_bug_no_startadd > 0) {
-   DRM_WARN_ONCE("Option hw_bug_no_startradd is enabled. Please "
- "report the output of 'lspci -vvnn' to "
- " if this "
- "option is required to make mgag200 work "
- "correctly on your system.\n");
-   return true;
-   } else if (!mgag200_hw_bug_no_startadd) {
-   return false;
-   }
-   return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD;
-}
-
-int mgag200_driver_dumb_create(struct drm_file *file,
-  struct drm_device *dev,
-  struct drm_mode_create_dumb *args)
-{
-   struct mga_device *mdev = to_mga_device(dev);
-   unsigned long pg_align;
-
-   if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
-   return -EINVAL;
-
-   pg_align = 0ul;
-
-   /*
-* Aligning scanout buffers to the size of the video ram forces
-* placement at offset 0. Works around a bug where HW does not
-* respect 'startadd' field.
-*/
-   if (mgag200_pin_bo_at_0(mdev))
-   pg_align = PFN_UP(mdev->mc.vram_size);
-
-   return drm_gem_vram_fill_create_dumb(file, dev, pg_align, 0, args);
-}
-
 static struct drm_driver driver = {
.driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
.fops = &mgag200_driver_fops,
@@ -148,10 +106,7 @@ static struct drm_driver driver = {
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
-   .debugfs_init = drm_vram_mm_debugfs_init,
-   .dumb_create = mgag200_driver_dumb_create,
-   .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset,
-   .gem_prime_mmap = drm_gem_prime_mmap,
+   DRM_GEM_SHMEM_DRIVER_OPS,
 };
 
 static struct pci_driver mgag200_pci_driver = {
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 2392baff618aa..d530df25c822d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -18,7 +18,7 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 
 #include "mgag200_reg.h"
@@ -155,7 +155,8 @@ struct mga_devic

[PATCH v2 12/15] drm/mgag200: Remove out-commented suspend/resume helpers

2020-05-12 Thread Thomas Zimmermann
The suspend/resume helpers are unused. Also remove associated state
from struct mga_device.

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  1 -
 drivers/gpu/drm/mgag200/mgag200_mode.c | 71 --
 2 files changed, 72 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index cf71a4ec84158..0cf498d1e900c 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -164,7 +164,6 @@ struct mga_device {
 
size_t vram_fb_available;
 
-   boolsuspended;
enum mga_type   type;
int has_sdram;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 199ae08976e16..d6f9763a4a450 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1357,65 +1357,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
return 0;
 }
 
-#if 0 /* code from mjg to attempt D3 on crtc dpms off - revisit later */
-static int mga_suspend(struct drm_crtc *crtc)
-{
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
-   struct drm_device *dev = crtc->dev;
-   struct mga_device *mdev = dev->dev_private;
-   struct pci_dev *pdev = dev->pdev;
-   int option;
-
-   if (mdev->suspended)
-   return 0;
-
-   WREG_SEQ(1, 0x20);
-   WREG_ECRT(1, 0x30);
-   /* Disable the pixel clock */
-   WREG_DAC(0x1a, 0x05);
-   /* Power down the DAC */
-   WREG_DAC(0x1e, 0x18);
-   /* Power down the pixel PLL */
-   WREG_DAC(0x1a, 0x0d);
-
-   /* Disable PLLs and clocks */
-   pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
-   option &= ~(0x1F8024);
-   pci_write_config_dword(pdev, PCI_MGA_OPTION, option);
-   pci_set_power_state(pdev, PCI_D3hot);
-   pci_disable_device(pdev);
-
-   mdev->suspended = true;
-
-   return 0;
-}
-
-static int mga_resume(struct drm_crtc *crtc)
-{
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
-   struct drm_device *dev = crtc->dev;
-   struct mga_device *mdev = dev->dev_private;
-   struct pci_dev *pdev = dev->pdev;
-   int option;
-
-   if (!mdev->suspended)
-   return 0;
-
-   pci_set_power_state(pdev, PCI_D0);
-   pci_enable_device(pdev);
-
-   /* Disable sysclk */
-   pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
-   option &= ~(0x4);
-   pci_write_config_dword(pdev, PCI_MGA_OPTION, option);
-
-   mdev->suspended = false;
-
-   return 0;
-}
-
-#endif
-
 static void mga_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
struct drm_device *dev = crtc->dev;
@@ -1442,11 +1383,6 @@ static void mga_crtc_dpms(struct drm_crtc *crtc, int 
mode)
break;
}
 
-#if 0
-   if (mode == DRM_MODE_DPMS_OFF) {
-   mga_suspend(crtc);
-   }
-#endif
WREG8(MGAREG_SEQ_INDEX, 0x01);
seq1 |= RREG8(MGAREG_SEQ_DATA) & ~0x20;
mga_wait_vsync(mdev);
@@ -1456,13 +1392,6 @@ static void mga_crtc_dpms(struct drm_crtc *crtc, int 
mode)
WREG8(MGAREG_CRTCEXT_INDEX, 0x01);
crtcext1 |= RREG8(MGAREG_CRTCEXT_DATA) & ~0x30;
WREG8(MGAREG_CRTCEXT_DATA, crtcext1);
-
-#if 0
-   if (mode == DRM_MODE_DPMS_ON && mdev->suspended == true) {
-   mga_resume(crtc);
-   drm_helper_resume_force_mode(dev);
-   }
-#endif
 }
 
 /*
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 10/15] drm/mgag200: Move hiprilvl setting into separate functions

2020-05-12 Thread Thomas Zimmermann
The hiprivlvl settings are now updated in mgag200_g200se_set_hiprilvl()
and mgag200_g200ev_set_hiprilvl().

v2:
* replace uint8_t with u8

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_mode.c | 98 ++
 1 file changed, 54 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 68ae604926757..46122fa319889 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1133,6 +1133,56 @@ static void mgag200_g200er_reset_tagfifo(struct 
mga_device *mdev)
WREG_SEQ(0x01, seq1);
 }
 
+static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
+   const struct drm_display_mode *mode,
+   const struct drm_framebuffer *fb)
+{
+   unsigned int hiprilvl;
+   u8 crtcext6;
+
+   if  (mdev->unique_rev_id >= 0x04) {
+   hiprilvl = 0;
+   } else if (mdev->unique_rev_id >= 0x02) {
+   unsigned int bpp;
+   unsigned long mb;
+
+   if (fb->format->cpp[0] * 8 > 16)
+   bpp = 32;
+   else if (fb->format->cpp[0] * 8 > 8)
+   bpp = 16;
+   else
+   bpp = 8;
+
+   mb = (mode->clock * bpp) / 1000;
+   if (mb > 3100)
+   hiprilvl = 0;
+   else if (mb > 2600)
+   hiprilvl = 1;
+   else if (mb > 1900)
+   hiprilvl = 2;
+   else if (mb > 1160)
+   hiprilvl = 3;
+   else if (mb > 440)
+   hiprilvl = 4;
+   else
+   hiprilvl = 5;
+
+   } else if (mdev->unique_rev_id >= 0x01) {
+   hiprilvl = 3;
+   } else {
+   hiprilvl = 4;
+   }
+
+   crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */
+
+   WREG_ECRT(0x06, crtcext6);
+}
+
+static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)
+{
+   WREG_ECRT(0x06, 0x00);
+}
+
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -1251,10 +1301,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (mdev->type == G200_EW3)
WREG_ECRT(0x34, 0x5);
 
-   if (mdev->type == G200_EV) {
-   WREG_ECRT(6, 0);
-   }
-
misc = RREG8(MGA_MISC_IN);
misc |= MGAREG_MISC_IOADSEL |
MGAREG_MISC_RAMMAPEN |
@@ -1270,47 +1316,11 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (mdev->type == G200_ER)
mgag200_g200er_reset_tagfifo(mdev);
 
+   if (IS_G200_SE(mdev))
+   mgag200_g200se_set_hiprilvl(mdev, mode, fb);
+   else if (mdev->type == G200_EV)
+   mgag200_g200ev_set_hiprilvl(mdev);
 
-   if (IS_G200_SE(mdev)) {
-   if  (mdev->unique_rev_id >= 0x04) {
-   WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
-   WREG8(MGAREG_CRTCEXT_DATA, 0);
-   } else if (mdev->unique_rev_id >= 0x02) {
-   u8 hi_pri_lvl;
-   u32 bpp;
-   u32 mb;
-
-   if (fb->format->cpp[0] * 8 > 16)
-   bpp = 32;
-   else if (fb->format->cpp[0] * 8 > 8)
-   bpp = 16;
-   else
-   bpp = 8;
-
-   mb = (mode->clock * bpp) / 1000;
-   if (mb > 3100)
-   hi_pri_lvl = 0;
-   else if (mb > 2600)
-   hi_pri_lvl = 1;
-   else if (mb > 1900)
-   hi_pri_lvl = 2;
-   else if (mb > 1160)
-   hi_pri_lvl = 3;
-   else if (mb > 440)
-   hi_pri_lvl = 4;
-   else
-   hi_pri_lvl = 5;
-
-   WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
-   WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl);
-   } else {
-   WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
-   if (mdev->unique_rev_id >= 0x01)
-   WREG8(MGAREG_CRTCEXT_DATA, 0x03);
-   else
-   WREG8(MGAREG_CRTCEXT_DATA, 0x04);
-   }
-   }
return 0;
 }
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 09/15] drm/mgag200: Move TAGFIFO reset into separate function

2020-05-12 Thread Thomas Zimmermann
The TAGFIFO state is now reset in mgag200_g200er_reset_tagfifo().

v2:
* define MGAREG_SEQ1_SCROFF

Signed-off-by: Thomas Zimmermann 
Tested-by: John Donnelly 
Acked-by: Sam Ravnborg 
---
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  6 
 drivers/gpu/drm/mgag200/mgag200_mode.c | 45 +-
 drivers/gpu/drm/mgag200/mgag200_reg.h  |  3 ++
 3 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 1963876ef3b8c..cf71a4ec84158 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -49,6 +49,12 @@
WREG8(ATTR_DATA, v);\
} while (0) \
 
+#define RREG_SEQ(reg, v)   \
+   do {\
+   WREG8(MGAREG_SEQ_INDEX, reg);   \
+   v = RREG8(MGAREG_SEQ_DATA); \
+   } while (0) \
+
 #define WREG_SEQ(reg, v)   \
do {\
WREG8(MGAREG_SEQ_INDEX, reg);   \
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 38556f57ad218..68ae604926757 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1106,6 +1106,33 @@ static void mgag200_set_format_regs(struct mga_device 
*mdev,
WREG_ECRT(3, crtcext3);
 }
 
+static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
+{
+   static uint32_t RESET_FLAG = 0x0020; /* undocumented magic value */
+   u8 seq1;
+   u32 memctl;
+
+   /* screen off */
+   RREG_SEQ(0x01, seq1);
+   seq1 |= MGAREG_SEQ1_SCROFF;
+   WREG_SEQ(0x01, seq1);
+
+   memctl = RREG32(MGAREG_MEMCTL);
+
+   memctl |= RESET_FLAG;
+   WREG32(MGAREG_MEMCTL, memctl);
+
+   udelay(1000);
+
+   memctl &= ~RESET_FLAG;
+   WREG32(MGAREG_MEMCTL, memctl);
+
+   /* screen on */
+   RREG_SEQ(0x01, seq1);
+   seq1 &= ~MGAREG_SEQ1_SCROFF;
+   WREG_SEQ(0x01, seq1);
+}
+
 static int mga_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -1240,22 +1267,8 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 
mgag200_set_mode_regs(mdev, mode);
 
-   /* reset tagfifo */
-   if (mdev->type == G200_ER) {
-   u32 mem_ctl = RREG32(MGAREG_MEMCTL);
-   u8 seq1;
-
-   /* screen off */
-   WREG8(MGAREG_SEQ_INDEX, 0x01);
-   seq1 = RREG8(MGAREG_SEQ_DATA) | 0x20;
-   WREG8(MGAREG_SEQ_DATA, seq1);
-
-   WREG32(MGAREG_MEMCTL, mem_ctl | 0x0020);
-   udelay(1000);
-   WREG32(MGAREG_MEMCTL, mem_ctl & ~0x0020);
-
-   WREG8(MGAREG_SEQ_DATA, seq1 & ~0x20);
-   }
+   if (mdev->type == G200_ER)
+   mgag200_g200er_reset_tagfifo(mdev);
 
 
if (IS_G200_SE(mdev)) {
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h 
b/drivers/gpu/drm/mgag200/mgag200_reg.h
index cd08dee29b06f..29f7194faadc0 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -235,6 +235,9 @@
 /* MMIO VGA registers */
 #define MGAREG_SEQ_INDEX   0x1fc4
 #define MGAREG_SEQ_DATA0x1fc5
+
+#define MGAREG_SEQ1_SCROFF BIT(5)
+
 #define MGAREG_CRTC_INDEX  0x1fd4
 #define MGAREG_CRTC_DATA   0x1fd5
 #define MGAREG_CRTCEXT_INDEX   0x1fde
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH] dma-buf: fix use-after-free in dmabuffs_dname

2020-05-12 Thread Greg KH
On Tue, May 12, 2020 at 10:43:18AM +0530, Charan Teja Kalla wrote:
> > Ok, but watch out, now you have 2 different reference counts for the
> > same structure.  Keeping them coordinated is almost always an impossible
> > task so you need to only rely on one.  If you can't use the file api,
> > just drop all of the reference counting logic in there and only use the
> > kref one.
> 
> I feel that changing the refcount logic now to dma-buf objects involve
> changes in
> 
> the core dma-buf framework. NO? Instead, how about passing the user passed
> name directly
> 
> in the ->d_fsdata inplace of dmabuf object? Because we just need user passed
> name in the
> 
> dmabuffs_dname(). With this we can avoid the need for extra refcount on
> dmabuf.

Odd formatting :(

> Posted patch-V2: https://lkml.org/lkml/2020/5/8/158

Please just post links to lore.kernel.org, we have no control over
lkml.org at all.

I'll go review that patch now...

greg k-h
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v2] dma-buf: fix use-after-free in dmabuffs_dname

2020-05-12 Thread Greg KH
On Fri, May 08, 2020 at 12:11:03PM +0530, Charan Teja Reddy wrote:
> The following race occurs while accessing the dmabuf object exported as
> file:
> P1P2
> dma_buf_release()  dmabuffs_dname()
>  [say lsof reading /proc//fd/]
> 
>  read dmabuf stored in dentry->d_fsdata
> Free the dmabuf object
>  Start accessing the dmabuf structure
> 
> In the above description, the dmabuf object freed in P1 is being
> accessed from P2 which is resulting into the use-after-free. Below is
> the dump stack reported.
> 
> We are reading the dmabuf object stored in the dentry->d_fsdata but
> there is no binding between the dentry and the dmabuf which means that
> the dmabuf can be freed while it is being read from ->d_fsdata and
> inuse. Reviews on the patch V1 says that protecting the dmabuf inuse
> with an extra refcount is not a viable solution as the exported dmabuf
> is already under file's refcount and keeping the multiple refcounts on
> the same object coordinated is not possible.
> 
> As we are reading the dmabuf in ->d_fsdata just to get the user passed
> name, we can directly store the name in d_fsdata thus can avoid the
> reading of dmabuf altogether.
> 
> Call Trace:
>  kasan_report+0x12/0x20
>  __asan_report_load8_noabort+0x14/0x20
>  dmabuffs_dname+0x4f4/0x560
>  tomoyo_realpath_from_path+0x165/0x660
>  tomoyo_get_realpath
>  tomoyo_check_open_permission+0x2a3/0x3e0
>  tomoyo_file_open
>  tomoyo_file_open+0xa9/0xd0
>  security_file_open+0x71/0x300
>  do_dentry_open+0x37a/0x1380
>  vfs_open+0xa0/0xd0
>  path_openat+0x12ee/0x3490
>  do_filp_open+0x192/0x260
>  do_sys_openat2+0x5eb/0x7e0
>  do_sys_open+0xf2/0x180
> 
> Fixes: bb2bb9030425 ("dma-buf: add DMA_BUF_SET_NAME ioctls")
> Reported-by: syzbot+3643a18836bce555b...@syzkaller.appspotmail.com
> Cc:  [5.3+]
> Signed-off-by: Charan Teja Reddy 
> ---
> 
> Changes in v2: 
> 
> - Pass the user passed name in ->d_fsdata instead of dmabuf
> - Improve the commit message
> 
> Changes in v1: (https://patchwork.kernel.org/patch/11514063/)
> 
>  drivers/dma-buf/dma-buf.c | 17 ++---
>  1 file changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index 01ce125..0071f7d 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -25,6 +25,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  #include 
> @@ -40,15 +41,13 @@ struct dma_buf_list {
>  
>  static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
>  {
> - struct dma_buf *dmabuf;
>   char name[DMA_BUF_NAME_LEN];
>   size_t ret = 0;
>  
> - dmabuf = dentry->d_fsdata;
> - dma_resv_lock(dmabuf->resv, NULL);
> - if (dmabuf->name)
> - ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
> - dma_resv_unlock(dmabuf->resv);
> + spin_lock(&dentry->d_lock);

Are you sure this lock always protects d_fsdata?

> + if (dentry->d_fsdata)
> + ret = strlcpy(name, dentry->d_fsdata, DMA_BUF_NAME_LEN);
> + spin_unlock(&dentry->d_lock);
>  
>   return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
>dentry->d_name.name, ret > 0 ? name : "");

If the above check fails the name will be what?  How could d_name.name
be valid but d_fsdata not be valid?


> @@ -80,12 +79,16 @@ static int dma_buf_fs_init_context(struct fs_context *fc)
>  static int dma_buf_release(struct inode *inode, struct file *file)
>  {
>   struct dma_buf *dmabuf;
> + struct dentry *dentry = file->f_path.dentry;
>  
>   if (!is_dma_buf_file(file))
>   return -EINVAL;
>  
>   dmabuf = file->private_data;
>  
> + spin_lock(&dentry->d_lock);
> + dentry->d_fsdata = NULL;
> + spin_unlock(&dentry->d_lock);
>   BUG_ON(dmabuf->vmapping_counter);
>  
>   /*
> @@ -343,6 +346,7 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, 
> const char __user *buf)
>   }
>   kfree(dmabuf->name);
>   dmabuf->name = name;
> + dmabuf->file->f_path.dentry->d_fsdata = name;

You are just changing the use of d_fsdata from being a pointer to the
dmabuf to being a pointer to the name string?  What's to keep that name
string around and not have the same reference counting issues that the
dmabuf structure itself has?  Who frees that string memory?

thanks,

greg k-h
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 00/38] DRM: fix struct sg_table nents vs. orig_nents misuse

2020-05-12 Thread Marek Szyprowski
Dear All,

During the Exynos DRM GEM rework and fixing the issues in the.
drm_prime_sg_to_page_addr_arrays() function [1] I've noticed that most
drivers in DRM framework incorrectly use nents and orig_nents entries of
the struct sg_table.

In case of the most DMA-mapping implementations exchanging those two
entries or using nents for all loops on the scatterlist is harmless,
because they both have the same value. There exists however a DMA-mapping
implementations, for which such incorrect usage breaks things. The nents
returned by dma_map_sg() might be lower than the nents passed as its
parameter and this is perfectly fine. DMA framework or IOMMU is allowed
to join consecutive chunks while mapping if such operation is supported
by the underlying HW (bus, bridge, IOMMU, etc). Example of the case
where dma_map_sg() might return 1 'DMA' chunk for the 4 'physical' pages
is described here [2]

The DMA-mapping framework documentation [3] states that dma_map_sg()
returns the numer of the created entries in the DMA address space.
However the subsequent calls to dma_sync_sg_for_{device,cpu} and
dma_unmap_sg must be called with the original number of entries passed to
dma_map_sg. The common pattern in DRM drivers were to assign the
dma_map_sg() return value to sg_table->nents and use that value for
the subsequent calls to dma_sync_sg_* or dma_unmap_sg functions. Also
the code iterated over nents times to access the pages stored in the
processed scatterlist, while it should use orig_nents as the numer of
the page entries.

I've tried to identify all such incorrect usage of sg_table->nents and
this is a result of my research. It looks that the incorrect pattern has
been copied over the many drivers mainly in the DRM subsystem. Too bad in
most cases it even worked correctly if the system used a simple, linear
DMA-mapping implementation, for which swapping nents and orig_nents
doesn't make any difference. To avoid similar issues in the future, I've
introduced a common wrappers for DMA-mapping calls, which operate directly
on the sg_table objects. I've also added wrappers for iterating over the
scatterlists stored in the sg_table objects and applied them where
possible. This, together with some common DRM prime helpers, allowed me
to almost get rid of all nents/orig_nents usage in the drivers. I hope
that such change makes the code robust, easier to follow and copy/paste
safe.

The biggest TODO is DRM/i915 driver and I don't feel brave enough to fix
it fully. The driver creatively uses sg_table->orig_nents to store the
size of the allocate scatterlist and ignores the number of the entries
returned by dma_map_sg function. In this patchset I only fixed the
sg_table objects exported by dmabuf related functions. I hope that I
didn't break anything there.

Patches are based on top of Linux next-20200511.

Best regards,
Marek Szyprowski


References:

[1] https://lkml.org/lkml/2020/3/27/555.
[2] https://lkml.org/lkml/2020/3/29/65
[3] Documentation/DMA-API-HOWTO.txt


Changelog:

v4:
- added for_each_sgtable_* wrappers and applied where possible
- added drm_prime_get_contiguous_size() and applied where possible
- applied drm_prime_sg_to_page_addr_arrays() where possible to remove page
  extraction from sg_table objects
- added documentation for the introduced wrappers
- improved patches description a bit

v3: 
https://lore.kernel.org/dri-devel/20200505083926.28503-1-m.szyprow...@samsung.com/
- introduce dma_*_sgtable_* wrappers and use them in all patches

v2: 
https://lore.kernel.org/linux-iommu/c01c9766-9778-fd1f-f36e-2dc7bd376...@arm.com/T/
- dropped most of the changes to drm/i915
- added fixes for rcar-du, xen, media and ion
- fixed a few issues pointed by kbuild test robot
- added wide cc: list for each patch

v1: 
https://lore.kernel.org/linux-iommu/c01c9766-9778-fd1f-f36e-2dc7bd376...@arm.com/T/
- initial version


Patch summary:

Marek Szyprowski (38):
  dma-mapping: add generic helpers for mapping sgtable objects
  scatterlist: add generic wrappers for iterating over sgtable objects
  iommu: add generic helper for mapping sgtable objects
  drm: prime: add common helper to check scatterlist contiguity
  drm: prime: use sgtable iterators in
drm_prime_sg_to_page_addr_arrays()
  drm: core: fix common struct sg_table related issues
  drm: amdgpu: fix common struct sg_table related issues
  drm: armada: fix common struct sg_table related issues
  drm: etnaviv: fix common struct sg_table related issues
  drm: exynos: use common helper for a scatterlist contiguity check
  drm: exynos: fix common struct sg_table related issues
  drm: i915: fix common struct sg_table related issues
  drm: lima: fix common struct sg_table related issues
  drm: mediatek: use common helper for a scatterlist contiguity check
  drm: mediatek: use common helper for extracting pages array
  drm: msm: fix common struct sg_table related issues
  drm: omapdrm: use common helper for extracting pages array
  drm: omapdrm: fix common struct sg_table rel

[RFC 08/17] drm/scheduler: use dma-fence annotations in main thread

2020-05-12 Thread Daniel Vetter
If the scheduler rt thread gets stuck on a mutex that we're holding
while waiting for gpu workloads to complete, we have a problem.

Add dma-fence annotations so that lockdep can check this for us.

I've tried to quite carefully review this, and I think it's at the
right spot. But obviosly no expert on drm scheduler.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/scheduler/sched_main.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/scheduler/sched_main.c 
b/drivers/gpu/drm/scheduler/sched_main.c
index 2f319102ae9f..06a736e506ad 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -763,9 +763,12 @@ static int drm_sched_main(void *param)
struct sched_param sparam = {.sched_priority = 1};
struct drm_gpu_scheduler *sched = (struct drm_gpu_scheduler *)param;
int r;
+   bool fence_cookie;
 
sched_setscheduler(current, SCHED_FIFO, &sparam);
 
+   fence_cookie = dma_fence_begin_signalling();
+
while (!kthread_should_stop()) {
struct drm_sched_entity *entity = NULL;
struct drm_sched_fence *s_fence;
@@ -823,6 +826,9 @@ static int drm_sched_main(void *param)
 
wake_up(&sched->job_scheduled);
}
+
+   dma_fence_end_signalling(fence_cookie);
+
return 0;
 }
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 12/17] drm/amdgpu/dc: Stop dma_resv_lock inversion in commit_tail

2020-05-12 Thread Daniel Vetter
Trying to grab dma_resv_lock while in commit_tail before we've done
all the code that leads to the eventual signalling of the vblank event
(which can be a dma_fence) is deadlock-y. Don't do that.

Here the solution is easy because just grabbing locks to read
something races anyway. We don't need to bother, READ_ONCE is
equivalent. And avoids the locking issue.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 9bfaa4cad483..28e1af9f823c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6699,7 +6699,11 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
 * explicitly on fences instead
 * and in general should be called for
 * blocking commit to as per framework helpers
+*
+* Yes, this deadlocks, since you're calling dma_resv_lock in a
+* path that leads to a dma_fence_signal(). Don't do that.
 */
+#if 0
r = amdgpu_bo_reserve(abo, true);
if (unlikely(r != 0))
DRM_ERROR("failed to reserve buffer before flip\n");
@@ -6709,6 +6713,12 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
tmz_surface = amdgpu_bo_encrypted(abo);
 
amdgpu_bo_unreserve(abo);
+#endif
+   /*
+* this races anyway, so READ_ONCE isn't any better or worse
+* than the stuff above. Except the stuff above can deadlock.
+*/
+   tiling_flags = READ_ONCE(abo->tiling_flags);
 
fill_dc_plane_info_and_addr(
dm->adev, new_plane_state, tiling_flags,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 01/17] dma-fence: add might_sleep annotation to _wait()

2020-05-12 Thread Daniel Vetter
But only for non-zero timeout, to avoid false positives.

One question here is whether the might_sleep should be unconditional,
or only for real timeouts. I'm not sure, so went with the more
defensive option. But in the interest of locking down the cross-driver
dma_fence rules we might want to be more aggressive.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/dma-buf/dma-fence.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 052a41e2451c..6802125349fb 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -208,6 +208,9 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, 
signed long timeout)
if (WARN_ON(timeout < 0))
return -EINVAL;
 
+   if (timeout > 0)
+   might_sleep();
+
trace_dma_fence_wait_start(fence);
if (fence->ops->wait)
ret = fence->ops->wait(fence, intr, timeout);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 13/17] drm/scheduler: use dma-fence annotations in tdr work

2020-05-12 Thread Daniel Vetter
In the face of unpriviledged userspace being able to submit bogus gpu
workloads the kernel needs gpu timeout and reset (tdr) to guarantee
that dma_fences actually complete. Annotate this worker to make sure
we don't have any accidental locking inversions or other problems
lurking.

Originally this was part of the overall scheduler annotation patch.
But amdgpu has some glorious inversions here:

- grabs console_lock
- does a full modeset, which grabs all kinds of locks
  (drm_modeset_lock, dma_resv_lock) which can deadlock with
  dma_fence_wait held inside them.
- almost minor at that point, but the modeset code also allocates
  memory

These all look like they'll be very hard to fix properly, the hardware
seems to require a full display reset with any gpu recovery.

Hence split out as a seperate patch.

Since amdgpu isn't the only hardware driver that needs to reset the
display (at least gen2/3 on intel have the same problem) we need a
generic solution for this. There's two tricks we could still from
drm/i915 and lift to dma-fence:

- The big whack, aka force-complete all fences. i915 does this for all
  pending jobs if the reset is somehow stuck. Trouble is we'd need to
  do this for all fences in the entire system, and just the
  book-keeping for that will be fun. Plus lots of drivers use fences
  for all kinds of internal stuff like memory management, so
  unconditionally resetting all of them doesn't work.

  I'm also hoping that with these fence annotations we could enlist
  lockdep in finding the last offenders causing deadlocks, and we
  could remove this get-out-of-jail trick.

- The more feasible approach (across drivers at least as part of the
  dma_fence contract) is what drm/i915 does for gen2/3: When we need
  to reset the display we wake up all dma_fence_wait_interruptible
  calls, or well at least the equivalent of those in i915 internally.

  Relying on ioctl restart we force all other threads to release their
  locks, which means the tdr thread is guaranteed to be able to get
  them. I think we could implement this at the dma_fence level,
  including proper lockdep annotations.

  dma_fence_begin_tdr():
  - must be nested within a dma_fence_begin/end_signalling section
  - will wake up all interruptible (but not the non-interruptible)
dma_fence_wait() calls and force them to complete with a
-ERESTARTSYS errno code. All new interrupitble calls to
dma_fence_wait() will immeidately fail with the same error code.

  dma_fence_end_trdr():
  - this will convert dma_fence_wait() calls back to normal.

  Of course interrupting dma_fence_wait is only ok if the caller
  specified that, which means we need to split the annotations into
  interruptible and non-interruptible version. If we then make sure
  that we only use interruptible dma_fence_wait() calls while holding
  drm_modeset_lock we can grab them in tdr code, and allow display
  resets. Doing the same for dma_resv_lock might be a lot harder, so
  buffer updates must be avoided.

  What's worse, we're not going to be able to make the dma_fence_wait
  calls in mmu-notifiers interruptible, that doesn't work. So
  allocating memory still wont' be allowed, even in tdr sections. Plus
  obviously we can use this trick only in tdr, it is rather intrusive.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/scheduler/sched_main.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/scheduler/sched_main.c 
b/drivers/gpu/drm/scheduler/sched_main.c
index 06a736e506ad..e34a44376e87 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -279,9 +279,12 @@ static void drm_sched_job_timedout(struct work_struct 
*work)
 {
struct drm_gpu_scheduler *sched;
struct drm_sched_job *job;
+   bool fence_cookie;
 
sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work);
 
+   fence_cookie = dma_fence_begin_signalling();
+
/* Protects against concurrent deletion in drm_sched_get_cleanup_job */
spin_lock(&sched->job_list_lock);
job = list_first_entry_or_null(&sched->ring_mirror_list,
@@ -313,6 +316,8 @@ static void drm_sched_job_timedout(struct work_struct *work)
spin_lock(&sched->job_list_lock);
drm_sched_start_timeout(sched);
spin_unlock(&sched->job_list_lock);
+
+   dma_fence_end_signalling(fence_cookie);
 }
 
  /**
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 10/17] drm/amdgpu: s/GFP_KERNEL/GFP_ATOMIC in scheduler code

2020-05-12 Thread Daniel Vetter
My dma-fence lockdep annotations caught an inversion because we
allocate memory where we really shouldn't:

kmem_cache_alloc+0x2b/0x6d0
amdgpu_fence_emit+0x30/0x330 [amdgpu]
amdgpu_ib_schedule+0x306/0x550 [amdgpu]
amdgpu_job_run+0x10f/0x260 [amdgpu]
drm_sched_main+0x1b9/0x490 [gpu_sched]
kthread+0x12e/0x150

Trouble right now is that lockdep only validates against GFP_FS, which
would be good enough for shrinkers. But for mmu_notifiers we actually
need !GFP_ATOMIC, since they can be called from any page laundering,
even if GFP_NOFS or GFP_NOIO are set.

I guess we should improve the lockdep annotations for
fs_reclaim_acquire/release.

Ofc real fix is to properly preallocate this fence and stuff it into
the amdgpu job structure. But GFP_ATOMIC gets the lockdep splat out of
the way.

v2: Two more allocations in scheduler paths.

Frist one:

__kmalloc+0x58/0x720
amdgpu_vmid_grab+0x100/0xca0 [amdgpu]
amdgpu_job_dependency+0xf9/0x120 [amdgpu]
drm_sched_entity_pop_job+0x3f/0x440 [gpu_sched]
drm_sched_main+0xf9/0x490 [gpu_sched]

Second one:

kmem_cache_alloc+0x2b/0x6d0
amdgpu_sync_fence+0x7e/0x110 [amdgpu]
amdgpu_vmid_grab+0x86b/0xca0 [amdgpu]
amdgpu_job_dependency+0xf9/0x120 [amdgpu]
drm_sched_entity_pop_job+0x3f/0x440 [gpu_sched]
drm_sched_main+0xf9/0x490 [gpu_sched]

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c   | 2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index d878fe7fee51..055b47241bb1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -143,7 +143,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct 
dma_fence **f,
uint32_t seq;
int r;
 
-   fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL);
+   fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_ATOMIC);
if (fence == NULL)
return -ENOMEM;
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index fe92dcd94d4a..fdcd6659f5ad 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -208,7 +208,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm,
if (ring->vmid_wait && !dma_fence_is_signaled(ring->vmid_wait))
return amdgpu_sync_fence(sync, ring->vmid_wait, false);
 
-   fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL);
+   fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_ATOMIC);
if (!fences)
return -ENOMEM;
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
index b87ca171986a..330476cc0c86 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -168,7 +168,7 @@ int amdgpu_sync_fence(struct amdgpu_sync *sync, struct 
dma_fence *f,
if (amdgpu_sync_add_later(sync, f, explicit))
return 0;
 
-   e = kmem_cache_alloc(amdgpu_sync_slab, GFP_KERNEL);
+   e = kmem_cache_alloc(amdgpu_sync_slab, GFP_ATOMIC);
if (!e)
return -ENOMEM;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 11/17] drm/amdgpu: DC also loves to allocate stuff where it shouldn't

2020-05-12 Thread Daniel Vetter
Not going to bother with a complete&pretty commit message, just
offending backtrace:

kvmalloc_node+0x47/0x80
dc_create_state+0x1f/0x60 [amdgpu]
dc_commit_state+0xcb/0x9b0 [amdgpu]
amdgpu_dm_atomic_commit_tail+0xd31/0x2010 [amdgpu]
commit_tail+0xa4/0x140 [drm_kms_helper]
drm_atomic_helper_commit+0x152/0x180 [drm_kms_helper]
drm_client_modeset_commit_atomic+0x1ea/0x250 [drm]
drm_client_modeset_commit_locked+0x55/0x190 [drm]
drm_client_modeset_commit+0x24/0x40 [drm]

v2: Found more in DC code, I'm just going to pile them all up.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/amd/amdgpu/atom.c | 2 +-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
 drivers/gpu/drm/amd/display/dc/core/dc.c  | 4 +++-
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c 
b/drivers/gpu/drm/amd/amdgpu/atom.c
index 4cfc786699c7..1b0c674fab25 100644
--- a/drivers/gpu/drm/amd/amdgpu/atom.c
+++ b/drivers/gpu/drm/amd/amdgpu/atom.c
@@ -1226,7 +1226,7 @@ static int amdgpu_atom_execute_table_locked(struct 
atom_context *ctx, int index,
ectx.abort = false;
ectx.last_jump = 0;
if (ws)
-   ectx.ws = kcalloc(4, ws, GFP_KERNEL);
+   ectx.ws = kcalloc(4, ws, GFP_ATOMIC);
else
ectx.ws = NULL;
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 4469a8c96b08..9bfaa4cad483 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6622,7 +6622,7 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
struct dc_stream_update stream_update;
} *bundle;
 
-   bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
+   bundle = kzalloc(sizeof(*bundle), GFP_ATOMIC);
 
if (!bundle) {
dm_error("Failed to allocate update bundle\n");
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 401d1c66a411..a37a32442a5a 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1416,8 +1416,10 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
 
 struct dc_state *dc_create_state(struct dc *dc)
 {
+   /* No you really cant allocate random crap here this late in
+* atomic_commit_tail. */
struct dc_state *context = kvzalloc(sizeof(struct dc_state),
-   GFP_KERNEL);
+   GFP_ATOMIC);
 
if (!context)
return NULL;
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 14/17] drm/amdgpu: use dma-fence annotations for gpu reset code

2020-05-12 Thread Daniel Vetter
To improve coverage also annotate the gpu reset code itself, since
that's called from other places than drm/scheduler (which is already
annotated). Annotations nests, so this doesn't break anything, and
allows easier testing.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index b038ddbb2ece..5560d045b2e0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4140,6 +4140,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
bool use_baco =
(amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) ?
true : false;
+   bool fence_cookie;
+
+   fence_cookie = dma_fence_begin_signalling();
 
/*
 * Flush RAM to disk so that after reboot
@@ -4168,6 +4171,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another 
already in progress",
  job ? job->base.id : -1, hive->hive_id);
mutex_unlock(&hive->hive_lock);
+   dma_fence_end_signalling(fence_cookie);
return 0;
}
 
@@ -4178,8 +4182,10 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
 */
INIT_LIST_HEAD(&device_list);
if (adev->gmc.xgmi.num_physical_nodes > 1) {
-   if (!hive)
+   if (!hive) {
+   dma_fence_end_signalling(fence_cookie);
return -ENODEV;
+   }
if (!list_is_first(&adev->gmc.xgmi.head, &hive->device_list))
list_rotate_to_front(&adev->gmc.xgmi.head, 
&hive->device_list);
device_list_handle = &hive->device_list;
@@ -4194,6 +4200,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
DRM_INFO("Bailing on TDR for s_job:%llx, as another 
already in progress",
  job ? job->base.id : -1);
mutex_unlock(&hive->hive_lock);
+   dma_fence_end_signalling(fence_cookie);
return 0;
}
 
@@ -4319,6 +4326,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
 
if (r)
dev_info(adev->dev, "GPU reset end with ret = %d\n", r);
+   dma_fence_end_signalling(fence_cookie);
return r;
 }
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 00/17] dma-fence lockdep annotations

2020-05-12 Thread Daniel Vetter
Hi all,

I've dragged my feet for years on this, hoping that cross-release lockdep
would do this for us, but well that never really happened unfortunately.
So here we are.

Cc'ed quite a pile of people since this is about the cross-driver contract
around dma_fences. Which is heavily used for dma_buf, and I'm hearing more
noises that rdma folks are looking into this, hence also on cc.

There's a bunch of different parts to this RFC:

- The annotations itself, in the 2nd patch after the prep patch to add
  might_sleep annotations. Commit message has all the motivation for what
  kind of deadlocks I want to catch, best you just read it.

  Since lockdep doesn't understand cross-release natively we need to
  cobble something together using rwlocks and a few more tricks, but from
  the test rollout in a few places in drm/vkms, amdgpu & i915 I think what
  I have now seems to actually work. Downside is that we have to
  explicitly annotate all code involved in eventual dma_fence signalling.

- Second important part is locking down the current dma-fence cross-driver
  contract, using lockdep priming like we already do for dma_resv_lock.
  I've just started with my own take on what we probably need to make the
  current code work (-ish), but both amdgpu and i915 have issues with
  that. So this needs some careful discussions, and also some thought on
  how we land it all eventually to not break lockdep completely for
  everyone.

  The important patch for that is "dma-fence: prime lockdep annotations"
  plus of course the various annotations patches and driver hacks to
  highlight some of the issues caught.

  Note that depending upon what exactly we end up deciding we might need
  to improve the annotations for fs_reclaim_acquire/release - for
  dma_fence_wait in mmu notifiers we can only allow GFP_NOWAIT (afaiui),
  and currently fs_reclaim_acquire/release only has a lockdep class for
  __GFP_FS only, we'd need to add another one for __GFP_DIRECT_RECLAIM in
  general maybe.

- Finally there's clearly some gaps in the current dma_fence driver
  interfaces: Amdgpu's hang recovery is essentially impossible to fix
  as-is - it needs to reset the display state and you can't get at modeset
  locks from tdr without deadlock potential. i915 has an internal trick
  (but it stops working once we involve real cross-driver fences) for this
  issues, but then for i915 modeset reset is only needed on very ancient
  gen2/3. Modern hw is a lot more reasonable.

  I'm kinda hoping that the annotations and priming for basic command
  submission and atomic modeset paths could be merged soonish, while we
  the tdr side clearly needs a pile more work to get going. But since we
  have to explicitly annotate all code paths anyway we can hide bugs in
  e.g. tdr code by simply not yet annotating those functions.

  I'm trying to lay out at least one idea for solving the tdr issue in the
  patch titled "drm/scheduler: use dma-fence annotations in tdr work".

Finally, once we have some agreement on where we're going with all this,
we also need some documentation. Currently that's missing because I don't
want to re-edit the text all the time while we still figure out the
details of the exact cross-driver semantics.

My goal here is that with this we can lock down the cross-driver contract
for the last bit of the dma_buf/resv/fence story and make sure this stops
being such a wobbly thing where everyone just does whatever they feel
like.

Ideas, thoughts, reviews, testing (with specific annotations for that
driver) on other drivers very much welcome.

Cheers, Daniel

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 

Daniel Vetter (17):
  dma-fence: add might_sleep annotation to _wait()
  dma-fence: basic lockdep annotations
  dma-fence: prime lockdep annotations
  drm/vkms: Annotate vblank timer
  drm/vblank: Annotate with dma-fence signalling section
  drm/atomic-helper: Add dma-fence annotations
  drm/amdgpu: add dma-fence annotations to atomic commit path
  drm/scheduler: use dma-fence annotations in main thread
  drm/amdgpu: use dma-fence annotations in cs_submit()
  drm/amdgpu: s/GFP_KERNEL/GFP_ATOMIC in scheduler code
  drm/amdgpu: DC also loves to allocate stuff where it shouldn't
  drm/amdgpu/dc: Stop dma_resv_lock inversion in commit_tail
  drm/scheduler: use dma-fence annotations in tdr work
  drm/amdgpu: use dma-fence annotations for gpu reset code
  Revert "drm/amdgpu: add fbdev suspend/resume on gpu reset"
  drm/amdgpu: gpu recovery does full modesets
  drm/i915: Annotate dma_fence_work

 drivers/dma-buf/dma-fence.c   | 56 +++
 drivers/dma-buf/dma-resv.c|  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c|  5 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c| 22 ++--
 drivers/gpu/drm/amd/amdgp

[RFC 09/17] drm/amdgpu: use dma-fence annotations in cs_submit()

2020-05-12 Thread Daniel Vetter
This is a bit tricky, since ->notifier_lock is held while calling
dma_fence_wait we must ensure that also the read side (i.e.
dma_fence_begin_signalling) is on the same side. If we mix this up
lockdep complaints, and that's again why we want to have these
annotations.

A nice side effect of this is that because of the fs_reclaim priming
for dma_fence_enable lockdep now automatically checks for us that
nothing in here allocates memory, without even running any userptr
workloads.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 7653f62b1b2d..6db3f3c629b0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -1213,6 +1213,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
struct amdgpu_job *job;
uint64_t seq;
int r;
+   bool fence_cookie;
 
job = p->job;
p->job = NULL;
@@ -1227,6 +1228,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
 */
mutex_lock(&p->adev->notifier_lock);
 
+   fence_cookie = dma_fence_begin_signalling();
+
/* If userptr are invalidated after amdgpu_cs_parser_bos(), return
 * -EAGAIN, drmIoctl in libdrm will restart the amdgpu_cs_ioctl.
 */
@@ -1264,12 +1267,14 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm);
 
ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence);
+   dma_fence_end_signalling(fence_cookie);
mutex_unlock(&p->adev->notifier_lock);
 
return 0;
 
 error_abort:
drm_sched_job_cleanup(&job->base);
+   dma_fence_end_signalling(fence_cookie);
mutex_unlock(&p->adev->notifier_lock);
 
 error_unlock:
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 16/17] drm/amdgpu: gpu recovery does full modesets

2020-05-12 Thread Daniel Vetter
...

I think it's time to stop this little exercise.

The lockdep splat, for the record:

[  132.583381] ==
[  132.584091] WARNING: possible circular locking dependency detected
[  132.584775] 5.7.0-rc3+ #346 Tainted: GW
[  132.585461] --
[  132.586184] kworker/2:3/865 is trying to acquire lock:
[  132.586857] c9677c70 (crtc_ww_class_acquire){+.+.}-{0:0}, at: 
drm_atomic_helper_suspend+0x38/0x120 [drm_kms_helper]
[  132.587569]
   but task is already holding lock:
[  132.589044] 82318c80 (dma_fence_map){}-{0:0}, at: 
drm_sched_job_timedout+0x25/0xf0 [gpu_sched]
[  132.589803]
   which lock already depends on the new lock.

[  132.592009]
   the existing dependency chain (in reverse order) is:
[  132.593507]
   -> #2 (dma_fence_map){}-{0:0}:
[  132.595019]dma_fence_begin_signalling+0x50/0x60
[  132.595767]drm_atomic_helper_commit+0xa1/0x180 [drm_kms_helper]
[  132.596567]drm_client_modeset_commit_atomic+0x1ea/0x250 [drm]
[  132.597420]drm_client_modeset_commit_locked+0x55/0x190 [drm]
[  132.598178]drm_client_modeset_commit+0x24/0x40 [drm]
[  132.598948]drm_fb_helper_restore_fbdev_mode_unlocked+0x4b/0xa0 
[drm_kms_helper]
[  132.599738]drm_fb_helper_set_par+0x30/0x40 [drm_kms_helper]
[  132.600539]fbcon_init+0x2e8/0x660
[  132.601344]visual_init+0xce/0x130
[  132.602156]do_bind_con_driver+0x1bc/0x2b0
[  132.602970]do_take_over_console+0x115/0x180
[  132.603763]do_fbcon_takeover+0x58/0xb0
[  132.604564]register_framebuffer+0x1ee/0x300
[  132.605369]__drm_fb_helper_initial_config_and_unlock+0x36e/0x520 
[drm_kms_helper]
[  132.606187]amdgpu_fbdev_init+0xb3/0xf0 [amdgpu]
[  132.607032]amdgpu_device_init.cold+0xe90/0x1677 [amdgpu]
[  132.607862]amdgpu_driver_load_kms+0x5a/0x200 [amdgpu]
[  132.608697]amdgpu_pci_probe+0xf7/0x180 [amdgpu]
[  132.609511]local_pci_probe+0x42/0x80
[  132.610324]pci_device_probe+0x104/0x1a0
[  132.611130]really_probe+0x147/0x3c0
[  132.611939]driver_probe_device+0xb6/0x100
[  132.612766]device_driver_attach+0x53/0x60
[  132.613593]__driver_attach+0x8c/0x150
[  132.614419]bus_for_each_dev+0x7b/0xc0
[  132.615249]bus_add_driver+0x14c/0x1f0
[  132.616071]driver_register+0x6c/0xc0
[  132.616902]do_one_initcall+0x5d/0x2f0
[  132.617731]do_init_module+0x5c/0x230
[  132.618560]load_module+0x2981/0x2bc0
[  132.619391]__do_sys_finit_module+0xaa/0x110
[  132.620228]do_syscall_64+0x5a/0x250
[  132.621064]entry_SYSCALL_64_after_hwframe+0x49/0xb3
[  132.621903]
   -> #1 (crtc_ww_class_mutex){+.+.}-{3:3}:
[  132.623587]__ww_mutex_lock.constprop.0+0xcc/0x10c0
[  132.624448]ww_mutex_lock+0x43/0xb0
[  132.625315]drm_modeset_lock+0x44/0x120 [drm]
[  132.626184]drmm_mode_config_init+0x2db/0x8b0 [drm]
[  132.627098]amdgpu_device_init.cold+0xbd1/0x1677 [amdgpu]
[  132.628007]amdgpu_driver_load_kms+0x5a/0x200 [amdgpu]
[  132.628920]amdgpu_pci_probe+0xf7/0x180 [amdgpu]
[  132.629804]local_pci_probe+0x42/0x80
[  132.630690]pci_device_probe+0x104/0x1a0
[  132.631583]really_probe+0x147/0x3c0
[  132.632479]driver_probe_device+0xb6/0x100
[  132.633379]device_driver_attach+0x53/0x60
[  132.634275]__driver_attach+0x8c/0x150
[  132.635170]bus_for_each_dev+0x7b/0xc0
[  132.636069]bus_add_driver+0x14c/0x1f0
[  132.636974]driver_register+0x6c/0xc0
[  132.637870]do_one_initcall+0x5d/0x2f0
[  132.638765]do_init_module+0x5c/0x230
[  132.639654]load_module+0x2981/0x2bc0
[  132.640522]__do_sys_finit_module+0xaa/0x110
[  132.641372]do_syscall_64+0x5a/0x250
[  132.642203]entry_SYSCALL_64_after_hwframe+0x49/0xb3
[  132.643022]
   -> #0 (crtc_ww_class_acquire){+.+.}-{0:0}:
[  132.644643]__lock_acquire+0x1241/0x23f0
[  132.645469]lock_acquire+0xad/0x370
[  132.646274]drm_modeset_acquire_init+0xd2/0x100 [drm]
[  132.647071]drm_atomic_helper_suspend+0x38/0x120 [drm_kms_helper]
[  132.647902]dm_suspend+0x1c/0x60 [amdgpu]
[  132.648698]amdgpu_device_ip_suspend_phase1+0x83/0xe0 [amdgpu]
[  132.649498]amdgpu_device_ip_suspend+0x1c/0x60 [amdgpu]
[  132.650300]amdgpu_device_gpu_recover.cold+0x4e6/0xe64 [amdgpu]
[  132.651084]amdgpu_job_timedout+0xfb/0x150 [amdgpu]
[  132.651825]drm_sched_job_timedout+0x8a/0xf0 [gpu_sched]
[  132.652594]process_one_work+0x23c/0x580
[  132.653402]worker_thread+0x50/0x3b0
[  132.654139]kthread+0x12e/0x150
[  132.654868]ret_from_fork+0x27/0x50
[  132.655598]
  

[RFC 07/17] drm/amdgpu: add dma-fence annotations to atomic commit path

2020-05-12 Thread Daniel Vetter
I need a canary in a ttm-based atomic driver to make sure the
dma_fence_begin/end_signalling annotations actually work.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ea0e039a667a..4469a8c96b08 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -57,6 +57,7 @@
 
 #include "ivsrcid/ivsrcid_vislands30.h"
 
+#include 
 #include 
 #include 
 #include 
@@ -7109,6 +7110,9 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
struct drm_connector_state *old_con_state, *new_con_state;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
int crtc_disable_count = 0;
+   bool fence_cookie;
+
+   fence_cookie = dma_fence_begin_signalling();
 
drm_atomic_helper_update_legacy_modeset_state(dev, state);
 
@@ -7389,6 +7393,8 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
/* Signal HW programming completion */
drm_atomic_helper_commit_hw_done(state);
 
+   dma_fence_end_signalling(fence_cookie);
+
if (wait_for_vblank)
drm_atomic_helper_wait_for_flip_done(dev, state);
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 04/17] drm/vkms: Annotate vblank timer

2020-05-12 Thread Daniel Vetter
This is needed to signal the fences from page flips, annotate it
accordingly. We need to annotate entire timer callback since if we get
stuck anywhere in there, then the timer stops, and hence fences stop.
Just annotating the top part that does the vblank handling isn't
enough.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
Cc: Rodrigo Siqueira 
Cc: Haneen Mohammed 
Cc: Daniel Vetter 
---
 drivers/gpu/drm/vkms/vkms_crtc.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index ac85e17428f8..a53a40848a72 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 
+#include 
+
 #include 
 #include 
 #include 
@@ -14,7 +16,9 @@ static enum hrtimer_restart vkms_vblank_simulate(struct 
hrtimer *timer)
struct drm_crtc *crtc = &output->crtc;
struct vkms_crtc_state *state;
u64 ret_overrun;
-   bool ret;
+   bool ret, fence_cookie;
+
+   fence_cookie = dma_fence_begin_signalling();
 
ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
  output->period_ns);
@@ -49,6 +53,8 @@ static enum hrtimer_restart vkms_vblank_simulate(struct 
hrtimer *timer)
DRM_DEBUG_DRIVER("Composer worker already queued\n");
}
 
+   dma_fence_end_signalling(fence_cookie);
+
return HRTIMER_RESTART;
 }
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 02/17] dma-fence: basic lockdep annotations

2020-05-12 Thread Daniel Vetter
Design is similar to the lockdep annotations for workers, but with
some twists:

- We use a read-lock for the execution/worker/completion side, so that
  this explicit annotation can be more liberally sprinkled around.
  With read locks lockdep isn't going to complain if the read-side
  isn't nested the same way under all circumstances, so ABBA deadlocks
  are ok. Which they are, since this is an annotation only.

- We're using non-recursive lockdep read lock mode, since in recursive
  read lock mode lockdep does not catch read side hazards. And we
  _very_ much want read side hazards to be caught. For full details of
  this limitation see

  commit e91498589746065e3ae95d9a00b068e525eec34f
  Author: Peter Zijlstra 
  Date:   Wed Aug 23 13:13:11 2017 +0200

  locking/lockdep/selftests: Add mixed read-write ABBA tests

- To allow nesting of the read-side explicit annotations we explicitly
  keep track of the nesting. lock_is_held() allows us to do that.

- The wait-side annotation is a write lock, and entirely done within
  dma_fence_wait() for everyone by default.

- To be able to freely annotate helper functions I want to make it ok
  to call dma_fence_begin/end_signalling from soft/hardirq context.
  First attempt was using the hardirq locking context for the write
  side in lockdep, but this forces all normal spinlocks nested within
  dma_fence_begin/end_signalling to be spinlocks. That bollocks.

  The approach now is to simple check in_atomic(), and for these cases
  entirely rely on the might_sleep() check in dma_fence_wait(). That
  will catch any wrong nesting against spinlocks from soft/hardirq
  contexts.

The idea here is that every code path that's critical for eventually
signalling a dma_fence should be annotated with
dma_fence_begin/end_signalling. The annotation ideally starts right
after a dma_fence is published (added to a dma_resv, exposed as a
sync_file fd, attached to a drm_syncobj fd, or anything else that
makes the dma_fence visible to other kernel threads), up to and
including the dma_fence_wait(). Examples are irq handlers, the
scheduler rt threads, the tail of execbuf (after the corresponding
fences are visible), any workers that end up signalling dma_fences and
really anything else. Not annotated should be code paths that only
complete fences opportunistically as the gpu progresses, like e.g.
shrinker/eviction code.

The main class of deadlocks this is supposed to catch are:

Thread A:

mutex_lock(A);
mutex_unlock(A);

dma_fence_signal();

Thread B:

mutex_lock(A);
dma_fence_wait();
mutex_unlock(A);

Thread B is blocked on A signalling the fence, but A never gets around
to that because it cannot acquire the lock A.

Note that dma_fence_wait() is allowed to be nested within
dma_fence_begin/end_signalling sections. To allow this to happen the
read lock needs to be upgraded to a write lock, which means that any
other lock is acquired between the dma_fence_begin_signalling() call and
the call to dma_fence_wait(), and still held, this will result in an
immediate lockdep complaint. The only other option would be to not
annotate such calls, defeating the point. Therefore these annotations
cannot be sprinkled over the code entirely mindless to avoid false
positives.

v2: handle soft/hardirq ctx better against write side and dont forget
EXPORT_SYMBOL, drivers can't use this otherwise.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/dma-buf/dma-fence.c | 53 +
 include/linux/dma-fence.h   | 12 +
 2 files changed, 65 insertions(+)

diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 6802125349fb..d5c0fd2efc70 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -110,6 +110,52 @@ u64 dma_fence_context_alloc(unsigned num)
 }
 EXPORT_SYMBOL(dma_fence_context_alloc);
 
+#ifdef CONFIG_LOCKDEP
+struct lockdep_map dma_fence_lockdep_map = {
+   .name = "dma_fence_map"
+};
+
+bool dma_fence_begin_signalling(void)
+{
+   /* explicitly nesting ... */
+   if (lock_is_held_type(&dma_fence_lockdep_map, 1))
+   return true;
+
+   /* rely on might_sleep check for soft/hardirq locks */
+   if (in_atomic())
+   return true;
+
+   /* ... and non-recursive readlock */
+   lock_acquire(&dma_fence_lockdep_map, 0, 0, 1, 1, NULL, _RET_IP_);
+
+   return false;
+}
+EXPORT_SYMBOL(dma_fence_begin_signalling);
+
+void dma_fence_end_signalling(bool cookie)
+{
+   if (cookie)
+   return;
+
+   lock_release(&dma_fence_lockdep_map, _RET_IP_);
+}
+EXPORT_SYMBOL(dma_fence_end_signalling);
+
+void __dma_fence_might_wait(void)
+{
+   bool tmp;
+
+   tmp = lock_is_held_type(&dma

[RFC 15/17] Revert "drm/amdgpu: add fbdev suspend/resume on gpu reset"

2020-05-12 Thread Daniel Vetter
This is one from the department of "maybe play lottery if you hit
this, karma compensation might work". Or at least lockdep ftw!

This reverts commit 565d1941557756a584ac357d945bc374d5fcd1d0.

It's not quite as low-risk as the commit message claims, because this
grabs console_lock, which might be held when we allocate memory, which
might never happen because the dma_fence_wait() is stuck waiting on
our gpu reset:

[  136.763714] ==
[  136.763714] WARNING: possible circular locking dependency detected
[  136.763715] 5.7.0-rc3+ #346 Tainted: GW
[  136.763716] --
[  136.763716] kworker/2:3/682 is trying to acquire lock:
[  136.763716] 8226f140 (console_lock){+.+.}-{0:0}, at: 
drm_fb_helper_set_suspend_unlocked+0x7b/0xa0 [drm_kms_helper]
[  136.763723]
   but task is already holding lock:
[  136.763724] 82318c80 (dma_fence_map){}-{0:0}, at: 
drm_sched_job_timedout+0x25/0xf0 [gpu_sched]
[  136.763726]
   which lock already depends on the new lock.

[  136.763726]
   the existing dependency chain (in reverse order) is:
[  136.763727]
   -> #2 (dma_fence_map){}-{0:0}:
[  136.763730]__dma_fence_might_wait+0x41/0xb0
[  136.763732]dma_resv_lockdep+0x171/0x202
[  136.763734]do_one_initcall+0x5d/0x2f0
[  136.763736]kernel_init_freeable+0x20d/0x26d
[  136.763738]kernel_init+0xa/0xfb
[  136.763740]ret_from_fork+0x27/0x50
[  136.763740]
   -> #1 (fs_reclaim){+.+.}-{0:0}:
[  136.763743]fs_reclaim_acquire.part.0+0x25/0x30
[  136.763745]kmem_cache_alloc_trace+0x2e/0x6e0
[  136.763747]device_create_groups_vargs+0x52/0xf0
[  136.763747]device_create+0x49/0x60
[  136.763749]fb_console_init+0x25/0x145
[  136.763750]fbmem_init+0xcc/0xe2
[  136.763750]do_one_initcall+0x5d/0x2f0
[  136.763751]kernel_init_freeable+0x20d/0x26d
[  136.763752]kernel_init+0xa/0xfb
[  136.763753]ret_from_fork+0x27/0x50
[  136.763753]
   -> #0 (console_lock){+.+.}-{0:0}:
[  136.763755]__lock_acquire+0x1241/0x23f0
[  136.763756]lock_acquire+0xad/0x370
[  136.763757]console_lock+0x47/0x70
[  136.763761]drm_fb_helper_set_suspend_unlocked+0x7b/0xa0 
[drm_kms_helper]
[  136.763809]amdgpu_device_gpu_recover.cold+0x21e/0xe7b [amdgpu]
[  136.763850]amdgpu_job_timedout+0xfb/0x150 [amdgpu]
[  136.763851]drm_sched_job_timedout+0x8a/0xf0 [gpu_sched]
[  136.763852]process_one_work+0x23c/0x580
[  136.763853]worker_thread+0x50/0x3b0
[  136.763854]kthread+0x12e/0x150
[  136.763855]ret_from_fork+0x27/0x50
[  136.763855]
   other info that might help us debug this:

[  136.763856] Chain exists of:
 console_lock --> fs_reclaim --> dma_fence_map

[  136.763857]  Possible unsafe locking scenario:

[  136.763857]CPU0CPU1
[  136.763857]
[  136.763857]   lock(dma_fence_map);
[  136.763858]lock(fs_reclaim);
[  136.763858]lock(dma_fence_map);
[  136.763858]   lock(console_lock);
[  136.763859]
*** DEADLOCK ***

[  136.763860] 4 locks held by kworker/2:3/682:
[  136.763860]  #0: 8887fb81c938 ((wq_completion)events){+.+.}-{0:0}, at: 
process_one_work+0x1bc/0x580
[  136.763862]  #1: c9cafe58 
((work_completion)(&(&sched->work_tdr)->work)){+.+.}-{0:0}, at: 
process_one_work+0x1bc/0x580
[  136.763863]  #2: 82318c80 (dma_fence_map){}-{0:0}, at: 
drm_sched_job_timedout+0x25/0xf0 [gpu_sched]
[  136.763865]  #3: 8887ab621748 (&adev->lock_reset){+.+.}-{3:3}, at: 
amdgpu_device_gpu_recover.cold+0x5ab/0xe7b [amdgpu]
[  136.763914]
   stack backtrace:
[  136.763915] CPU: 2 PID: 682 Comm: kworker/2:3 Tainted: GW 
5.7.0-rc3+ #346
[  136.763916] Hardware name: System manufacturer System Product Name/PRIME 
X370-PRO, BIOS 4011 04/19/2018
[  136.763918] Workqueue: events drm_sched_job_timedout [gpu_sched]
[  136.763919] Call Trace:
[  136.763922]  dump_stack+0x8f/0xd0
[  136.763924]  check_noncircular+0x162/0x180
[  136.763926]  __lock_acquire+0x1241/0x23f0
[  136.763927]  lock_acquire+0xad/0x370
[  136.763932]  ? drm_fb_helper_set_suspend_unlocked+0x7b/0xa0 [drm_kms_helper]
[  136.763933]  ? mark_held_locks+0x2d/0x80
[  136.763934]  ? _raw_spin_unlock_irqrestore+0x46/0x60
[  136.763936]  console_lock+0x47/0x70
[  136.763940]  ? drm_fb_helper_set_suspend_unlocked+0x7b/0xa0 [drm_kms_helper]
[  136.763944]  drm_fb_helper_set_suspend_unlocked+0x7b/0xa0 [drm_kms_helper]
[  136.763993]  amdgpu_device_gpu_recover.cold+0x21e/0xe7b [amdgpu]
[  136.764036]  amdgpu_job_timedout+0xfb/0x150 [amdgpu]
[  136.764038]  drm_sched_job_timedout+0x8a/0xf0 [gpu_sched]
[  136.764

[RFC 06/17] drm/atomic-helper: Add dma-fence annotations

2020-05-12 Thread Daniel Vetter
This is a bit disappointing since we need to split the annotations
over all the different parts.

I was considering just leaking the critical section into the
->atomic_commit_tail callback of each driver. But that would mean we
need to pass the fence_cookie into each driver (there's a total of 13
implementations of this hook right now), so bad flag day. And also a
bit leaky abstraction.

Hence just do it function-by-function.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_atomic_helper.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index 8ac3aa068261..0a541368246e 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1549,6 +1549,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done);
 void drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state)
 {
struct drm_device *dev = old_state->dev;
+   bool fence_cookie = dma_fence_begin_signalling();
 
drm_atomic_helper_commit_modeset_disables(dev, old_state);
 
@@ -1560,6 +1561,8 @@ void drm_atomic_helper_commit_tail(struct 
drm_atomic_state *old_state)
 
drm_atomic_helper_commit_hw_done(old_state);
 
+   dma_fence_end_signalling(fence_cookie);
+
drm_atomic_helper_wait_for_vblanks(dev, old_state);
 
drm_atomic_helper_cleanup_planes(dev, old_state);
@@ -1579,6 +1582,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_tail);
 void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
 {
struct drm_device *dev = old_state->dev;
+   bool fence_cookie = dma_fence_begin_signalling();
 
drm_atomic_helper_commit_modeset_disables(dev, old_state);
 
@@ -1591,6 +1595,8 @@ void drm_atomic_helper_commit_tail_rpm(struct 
drm_atomic_state *old_state)
 
drm_atomic_helper_commit_hw_done(old_state);
 
+   dma_fence_end_signalling(fence_cookie);
+
drm_atomic_helper_wait_for_vblanks(dev, old_state);
 
drm_atomic_helper_cleanup_planes(dev, old_state);
@@ -1606,6 +1612,9 @@ static void commit_tail(struct drm_atomic_state 
*old_state)
ktime_t start;
s64 commit_time_ms;
unsigned int i, new_self_refresh_mask = 0;
+   bool fence_cookie;
+
+   fence_cookie = dma_fence_begin_signalling();
 
funcs = dev->mode_config.helper_private;
 
@@ -1634,6 +1643,8 @@ static void commit_tail(struct drm_atomic_state 
*old_state)
if (new_crtc_state->self_refresh_active)
new_self_refresh_mask |= BIT(i);
 
+   dma_fence_end_signalling(fence_cookie);
+
if (funcs && funcs->atomic_commit_tail)
funcs->atomic_commit_tail(old_state);
else
@@ -1789,6 +1800,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 bool nonblock)
 {
int ret;
+   bool fence_cookie;
 
if (state->async_update) {
ret = drm_atomic_helper_prepare_planes(dev, state);
@@ -1811,6 +1823,8 @@ int drm_atomic_helper_commit(struct drm_device *dev,
if (ret)
return ret;
 
+   fence_cookie = dma_fence_begin_signalling();
+
if (!nonblock) {
ret = drm_atomic_helper_wait_for_fences(dev, state, true);
if (ret)
@@ -1848,6 +1862,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 */
 
drm_atomic_state_get(state);
+   dma_fence_end_signalling(fence_cookie);
if (nonblock)
queue_work(system_unbound_wq, &state->commit_work);
else
@@ -1856,6 +1871,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
return 0;
 
 err:
+   dma_fence_end_signalling(fence_cookie);
drm_atomic_helper_cleanup_planes(dev, state);
return ret;
 }
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 05/17] drm/vblank: Annotate with dma-fence signalling section

2020-05-12 Thread Daniel Vetter
This is rather overkill since currently all drivers call this from
hardirq (or at least timers). But maybe in the future we're going to
have thread irq handlers and what not, doesn't hurt to be prepared.
Plus this is an easy start for sprinkling these fence annotations into
shared code.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_vblank.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 758bf74e1cab..125ef0c0f9a1 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -24,6 +24,7 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 
@@ -1895,7 +1896,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned 
int pipe)
 {
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
unsigned long irqflags;
-   bool disable_irq;
+   bool disable_irq, fence_cookie;
 
if (WARN_ON_ONCE(!dev->num_crtcs))
return false;
@@ -1903,6 +1904,8 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned 
int pipe)
if (WARN_ON(pipe >= dev->num_crtcs))
return false;
 
+   fence_cookie = dma_fence_begin_signalling();
+
spin_lock_irqsave(&dev->event_lock, irqflags);
 
/* Need timestamp lock to prevent concurrent execution with
@@ -1915,6 +1918,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned 
int pipe)
if (!vblank->enabled) {
spin_unlock(&dev->vblank_time_lock);
spin_unlock_irqrestore(&dev->event_lock, irqflags);
+   dma_fence_end_signalling(fence_cookie);
return false;
}
 
@@ -1940,6 +1944,8 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned 
int pipe)
if (disable_irq)
vblank_disable_fn(&vblank->disable_timer);
 
+   dma_fence_end_signalling(fence_cookie);
+
return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 03/17] dma-fence: prime lockdep annotations

2020-05-12 Thread Daniel Vetter
Two in one go:
- it is allowed to call dma_fence_wait() while holding a
  dma_resv_lock(). This is fundamental to how eviction works with ttm,
  so required.

- it is allowed to call dma_fence_wait() from memory reclaim contexts,
  specifically from shrinker callbacks (which i915 does), and from mmu
  notifier callbacks (which amdgpu does, and which i915 sometimes also
  does, and probably always should, but that's kinda a debate). Also
  for stuff like HMM we really need to be able to do this, or things
  get real dicey.

Consequence is that any critical path necessary to get to a
dma_fence_signal for a fence must never a) call dma_resv_lock nor b)
allocate memory with GFP_KERNEL. Also by implication of
dma_resv_lock(), no userspace faulting allowed. That's some supremely
obnoxious limitations, which is why we need to sprinkle the right
annotations to all relevant paths.

The one big locking context we're leaving out here is mmu notifiers,
added in

commit 23b68395c7c78a764e8963fc15a7cfd318bf187f
Author: Daniel Vetter 
Date:   Mon Aug 26 22:14:21 2019 +0200

mm/mmu_notifiers: add a lockdep map for invalidate_range_start/end

that one covers a lot of other callsites, and it's also allowed to
wait on dma-fences from mmu notifiers. But there's no ready-made
functions exposed to prime this, so I've left it out for now.

Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/dma-buf/dma-resv.c | 1 +
 include/linux/dma-fence.h  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 99c0a33c918d..392c336f0732 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -115,6 +115,7 @@ static int __init dma_resv_lockdep(void)
if (ret == -EDEADLK)
dma_resv_lock_slow(&obj, &ctx);
fs_reclaim_acquire(GFP_KERNEL);
+   __dma_fence_might_wait();
fs_reclaim_release(GFP_KERNEL);
ww_mutex_unlock(&obj.lock);
ww_acquire_fini(&ctx);
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 3f288f7db2ef..09e23adb351d 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -360,6 +360,7 @@ dma_fence_get_rcu_safe(struct dma_fence __rcu **fencep)
 #ifdef CONFIG_LOCKDEP
 bool dma_fence_begin_signalling(void);
 void dma_fence_end_signalling(bool cookie);
+void __dma_fence_might_wait(void);
 #else
 static inline bool dma_fence_begin_signalling(void)
 {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC 17/17] drm/i915: Annotate dma_fence_work

2020-05-12 Thread Daniel Vetter
i915 does tons of allocations from this worker, which lockdep catches.

Also generic infrastructure like this with big potential for how
dma_fence or other cross driver contracts work, really should be
reviewed on dri-devel. Implementing custom wheels for everything
within the driver is a classic case of "platform problem" [1]. Which in
upstream we really shouldn't have.

Since there's no quick way to solve these splats (dma_fence_work is
used a bunch in basic buffer management and command submission) like
for amdgpu, I'm giving up at this point here. Annotating i915
scheduler and gpu reset could would be interesting, but since lockdep
is one-shot we can't see what surprises would lurk there.

1: https://lwn.net/Articles/443531/
Cc: linux-me...@vger.kernel.org
Cc: linaro-mm-...@lists.linaro.org
Cc: linux-r...@vger.kernel.org
Cc: amd-...@lists.freedesktop.org
Cc: intel-...@lists.freedesktop.org
Cc: Chris Wilson 
Cc: Maarten Lankhorst 
Cc: Christian König 
Signed-off-by: Daniel Vetter 
---
 drivers/gpu/drm/i915/i915_sw_fence_work.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_sw_fence_work.c 
b/drivers/gpu/drm/i915/i915_sw_fence_work.c
index a3a81bb8f2c3..5b74acadaef5 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence_work.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence_work.c
@@ -17,12 +17,15 @@ static void fence_work(struct work_struct *work)
 {
struct dma_fence_work *f = container_of(work, typeof(*f), work);
int err;
+   bool fence_cookie;
 
+   fence_cookie = dma_fence_begin_signalling();
err = f->ops->work(f);
if (err)
dma_fence_set_error(&f->dma, err);
 
fence_complete(f);
+   dma_fence_end_signalling(fence_cookie);
dma_fence_put(&f->dma);
 }
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 01/38] dma-mapping: add generic helpers for mapping sgtable objects

2020-05-12 Thread Marek Szyprowski
struct sg_table is a common structure used for describing a memory
buffer. It consists of a scatterlist with memory pages and DMA addresses
(sgl entry), as well as the number of scatterlist entries: CPU pages
(orig_nents entry) and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg
function.

To avoid such issues, lets introduce a common wrappers operating directly
on the struct sg_table objects, which take care of the proper use of
the nents and orig_nents entries.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 include/linux/dma-mapping.h | 79 +
 1 file changed, 79 insertions(+)

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index b43116a..88f01cc 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -609,6 +609,85 @@ static inline void dma_sync_single_range_for_device(struct 
device *dev,
return dma_sync_single_for_device(dev, addr + offset, size, dir);
 }
 
+/**
+ * dma_map_sgtable - Map the given buffer for the DMA operations
+ * @dev:   The device to perform a DMA operation
+ * @sgt:   The sg_table object describing the buffer
+ * @dir:   DMA direction
+ * @attrs: Optional DMA attributes for the map operation
+ *
+ * Maps a buffer described by a scatterlist stored in the given sg_table
+ * object for the @dir DMA operation by the @dev device. After success
+ * the ownership for the buffer is transferred to the DMA domain. One has
+ * to call dma_sync_sgtable_for_cpu() or dma_unmap_sgtable() to move the
+ * ownership of the buffer back to the CPU domain before touching the
+ * buffer by the CPU.
+ * Returns 0 on success or -EINVAL on error during mapping the buffer.
+ */
+static inline int dma_map_sgtable(struct device *dev, struct sg_table *sgt,
+   enum dma_data_direction dir, unsigned long attrs)
+{
+   int n = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents, dir, attrs);
+
+   if (n > 0) {
+   sgt->nents = n;
+   return 0;
+   }
+   return -EINVAL;
+}
+
+/**
+ * dma_unmap_sgtable - Unmap the given buffer for the DMA operations
+ * @dev:   The device to perform a DMA operation
+ * @sgt:   The sg_table object describing the buffer
+ * @dir:   DMA direction
+ * @attrs: Optional DMA attributes for the map operation
+ *
+ * Unmaps a buffer described by a scatterlist stored in the given sg_table
+ * object for the @dir DMA operation by the @dev device. After this function
+ * the ownership of the buffer is transferred back to the CPU domain.
+ */
+static inline void dma_unmap_sgtable(struct device *dev, struct sg_table *sgt,
+   enum dma_data_direction dir, unsigned long attrs)
+{
+   dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents, dir, attrs);
+}
+
+/**
+ * dma_sync_sgtable_for_cpu - Synchronize the given buffer for the CPU access
+ * @dev:   The device to perform a DMA operation
+ * @sgt:   The sg_table object describing the buffer
+ * @dir:   DMA direction
+ *
+ * Performs the needed cache synchronization and moves the ownership of the
+ * buffer back to the CPU domain, so it is safe to perform any access to it
+ * by the CPU. Before doing any further DMA operations, one has to transfer
+ * the ownership of the buffer back to the DMA domain by calling the
+ * dma_sync_sgtable_for_device().
+ */
+static inline void dma_sync_sgtable_for_cpu(struct device *dev,
+   struct sg_table *sgt, enum dma_data_direction dir)
+{
+   dma_sync_sg_for_cpu(dev, sgt->sgl, sgt->orig_nents, dir);
+}
+
+/**
+ * dma_sync_sgtable_for_device - Synchronize the given buffer for the DMA
+ * @dev:   The device to perform a DMA operation
+ * @sgt:   The sg_table object describing the buffer
+ * @dir:   DMA direction
+ *
+ * Performs the needed cache synchronization and moves the ownership of the
+ * buffer back to the DMA domain, so it is safe to perform the DMA operation.
+ * Once finished, one has to call dma_sync_sgtable_for_cpu() or
+ * dma_unmap_sgtable().
+ */
+static inline void dma_sync_sgtable_for_device(struct device *dev,
+   struct sg_table *sgt, enum dma_data_direction dir)
+{
+   dma_sync_sg_for_device(dev, sgt->sgl, sgt->orig_nents, dir);
+}
+
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
 #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedeskto

[PATCH v4 24/38] drm: v3d: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/v3d/v3d_mmu.c | 17 +++--
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c
index 3b81ea2..175c257 100644
--- a/drivers/gpu/drm/v3d/v3d_mmu.c
+++ b/drivers/gpu/drm/v3d/v3d_mmu.c
@@ -90,19 +90,16 @@ void v3d_mmu_insert_ptes(struct v3d_bo *bo)
struct v3d_dev *v3d = to_v3d_dev(shmem_obj->base.dev);
u32 page = bo->node.start;
u32 page_prot = V3D_PTE_WRITEABLE | V3D_PTE_VALID;
-   unsigned int count;
-   struct scatterlist *sgl;
+   struct sg_dma_page_iter dma_iter;
 
-   for_each_sg(shmem_obj->sgt->sgl, sgl, shmem_obj->sgt->nents, count) {
-   u32 page_address = sg_dma_address(sgl) >> V3D_MMU_PAGE_SHIFT;
+   for_each_sgtable_dma_page(shmem_obj->sgt, &dma_iter, 0) {
+   dma_addr_t dma_addr = sg_page_iter_dma_address(&dma_iter);
+   u32 page_address = dma_addr >> V3D_MMU_PAGE_SHIFT;
u32 pte = page_prot | page_address;
-   u32 i;
 
-   BUG_ON(page_address + (sg_dma_len(sgl) >> V3D_MMU_PAGE_SHIFT) >=
-  BIT(24));
-
-   for (i = 0; i < sg_dma_len(sgl) >> V3D_MMU_PAGE_SHIFT; i++)
-   v3d->pt[page++] = pte + i;
+   BUILD_BUG_ON(V3D_MMU_PAGE_SHIFT != PAGE_SIZE);
+   BUG_ON(page_address + 1 >= BIT(24));
+   v3d->pt[page++] = pte;
}
 
WARN_ON_ONCE(page - bo->node.start !=
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 02/38] scatterlist: add generic wrappers for iterating over sgtable objects

2020-05-12 Thread Marek Szyprowski
struct sg_table is a common structure used for describing a memory
buffer. It consists of a scatterlist with memory pages and DMA addresses
(sgl entry), as well as the number of scatterlist entries: CPU pages
(orig_nents entry) and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling the scatterlist iterating functions with a wrong number
of the entries.

To avoid such issues, lets introduce a common wrappers operating directly
on the struct sg_table objects, which take care of the proper use of
the nents and orig_nents entries.

While touching this, lets clarify some ambiguities in the comments for
the existing for_each helpers.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 include/linux/scatterlist.h | 50 ++---
 1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 6eec50f..4f922af 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -151,6 +151,20 @@ static inline void sg_set_buf(struct scatterlist *sg, 
const void *buf,
 #define for_each_sg(sglist, sg, nr, __i)   \
for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
 
+/*
+ * Loop over each sg element in the given sg_table object.
+ */
+#define for_each_sgtable_sg(sgt, sg, i)\
+   for_each_sg(sgt->sgl, sg, sgt->orig_nents, i)
+
+/*
+ * Loop over each sg element in the given *DMA mapped* sg_table object.
+ * Please use sg_dma_address(sg) and sg_dma_len(sg) to extract DMA addresses
+ * of the each element.
+ */
+#define for_each_sgtable_dma_sg(sgt, sg, i)\
+   for_each_sg(sgt->sgl, sg, sgt->nents, i)
+
 /**
  * sg_chain - Chain two sglists together
  * @prv:   First scatterlist
@@ -401,9 +415,10 @@ static inline struct page *sg_page_iter_page(struct 
sg_page_iter *piter)
  * @sglist:sglist to iterate over
  * @piter: page iterator to hold current page, sg, sg_pgoffset
  * @nents: maximum number of sg entries to iterate over
- * @pgoffset:  starting page offset
+ * @pgoffset:  starting page offset (in pages)
  *
  * Callers may use sg_page_iter_page() to get each page pointer.
+ * In each loop it operates on PAGE_SIZE unit.
  */
 #define for_each_sg_page(sglist, piter, nents, pgoffset)  \
for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \
@@ -412,18 +427,47 @@ static inline struct page *sg_page_iter_page(struct 
sg_page_iter *piter)
 /**
  * for_each_sg_dma_page - iterate over the pages of the given sg list
  * @sglist:sglist to iterate over
- * @dma_iter:  page iterator to hold current page
+ * @dma_iter:  DMA page iterator to hold current page
  * @dma_nents: maximum number of sg entries to iterate over, this is the value
  *  returned from dma_map_sg
- * @pgoffset:  starting page offset
+ * @pgoffset:  starting page offset (in pages)
  *
  * Callers may use sg_page_iter_dma_address() to get each page's DMA address.
+ * In each loop it operates on PAGE_SIZE unit.
  */
 #define for_each_sg_dma_page(sglist, dma_iter, dma_nents, pgoffset)
\
for (__sg_page_iter_start(&(dma_iter)->base, sglist, dma_nents,\
  pgoffset);   \
 __sg_page_iter_dma_next(dma_iter);)
 
+/**
+ * for_each_sgtable_page - iterate over all pages in the sg_table object
+ * @sgt:   sg_table object to iterate over
+ * @piter: page iterator to hold current page
+ * @pgoffset:  starting page offset (in pages)
+ *
+ * Iterates over the all memory pages in the buffer described by
+ * a scatterlist stored in the given sg_table object.
+ * See also for_each_sg_page(). In each loop it operates on PAGE_SIZE unit.
+ */
+#define for_each_sgtable_page(sgt, piter, pgoffset)\
+   for_each_sg_page(sgt->sgl, piter, sgt->orig_nents, pgoffset)
+
+/**
+ * for_each_sgtable_dma_page - iterate over the DMA mapped sg_table object
+ * @sgt:   sg_table object to iterate over
+ * @dma_iter:  DMA page iterator to hold current page
+ * @pgoffset:  starting page offset (in pages)
+ *
+ * Iterates over the all DMA mapped pages in the buffer described by
+ * a scatterlist stored in the given sg_table object.
+ * See also for_each_sg_dma_page(). In each loop it operates on PAGE_SIZE
+ * unit.
+ */
+#define for_each_sgtable_dma_page(sgt, dma_iter, pgoffset) \
+   for_each_sg_dma_page(sgt->sgl, dma_iter, sgt->nents, pgoffset)
+
+
 /*
  * Mapping sg iterator
  *
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 13/38] drm: lima: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/lima/lima_gem.c | 11 ---
 drivers/gpu/drm/lima/lima_vm.c  |  5 ++---
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
index 5404e0d..cda43f6 100644
--- a/drivers/gpu/drm/lima/lima_gem.c
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -69,8 +69,7 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
return ret;
 
if (bo->base.sgt) {
-   dma_unmap_sg(dev, bo->base.sgt->sgl,
-bo->base.sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0);
sg_free_table(bo->base.sgt);
} else {
bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL);
@@ -80,7 +79,13 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
}
}
 
-   dma_map_sg(dev, sgt.sgl, sgt.nents, DMA_BIDIRECTIONAL);
+   ret = dma_map_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0);
+   if (ret) {
+   sg_free_table(&sgt);
+   kfree(bo->base.sgt);
+   bo->base.sgt = NULL;
+   return ret;
+   }
 
*bo->base.sgt = sgt;
 
diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c
index 5b92fb8..2b2739a 100644
--- a/drivers/gpu/drm/lima/lima_vm.c
+++ b/drivers/gpu/drm/lima/lima_vm.c
@@ -124,7 +124,7 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, 
bool create)
if (err)
goto err_out1;
 
-   for_each_sg_dma_page(bo->base.sgt->sgl, &sg_iter, bo->base.sgt->nents, 
0) {
+   for_each_sgtable_dma_page(bo->base.sgt, &sg_iter, 0) {
err = lima_vm_map_page(vm, sg_page_iter_dma_address(&sg_iter),
   bo_va->node.start + offset);
if (err)
@@ -298,8 +298,7 @@ int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, 
int pageoff)
mutex_lock(&vm->lock);
 
base = bo_va->node.start + (pageoff << PAGE_SHIFT);
-   for_each_sg_dma_page(bo->base.sgt->sgl, &sg_iter,
-bo->base.sgt->nents, pageoff) {
+   for_each_sgtable_dma_page(bo->base.sgt, &sg_iter, pageoff) {
err = lima_vm_map_page(vm, sg_page_iter_dma_address(&sg_iter),
   base + offset);
if (err)
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 06/38] drm: core: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/drm_cache.c|  2 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c | 14 +-
 drivers/gpu/drm/drm_prime.c| 11 ++-
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 03e01b0..0fe3c49 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -127,7 +127,7 @@ static void drm_cache_flush_clflush(struct page *pages[],
struct sg_page_iter sg_iter;
 
mb(); /*CLFLUSH is ordered only by using memory barriers*/
-   for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
+   for_each_sgtable_page(st, &sg_iter, 0)
drm_clflush_page(sg_page_iter_page(&sg_iter));
mb(); /*Make sure that all cache line entry is flushed*/
 
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c 
b/drivers/gpu/drm/drm_gem_shmem_helper.c
index df31e57..00a43e8 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -117,8 +117,8 @@ void drm_gem_shmem_free_object(struct drm_gem_object *obj)
kvfree(shmem->pages);
} else {
if (shmem->sgt) {
-   dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl,
-shmem->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(obj->dev->dev, shmem->sgt,
+ DMA_BIDIRECTIONAL, 0);
sg_free_table(shmem->sgt);
kfree(shmem->sgt);
}
@@ -395,8 +395,7 @@ void drm_gem_shmem_purge_locked(struct drm_gem_object *obj)
 
WARN_ON(!drm_gem_shmem_is_purgeable(shmem));
 
-   dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl,
-shmem->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(obj->dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);
sg_free_table(shmem->sgt);
kfree(shmem->sgt);
shmem->sgt = NULL;
@@ -623,12 +622,17 @@ struct sg_table *drm_gem_shmem_get_pages_sgt(struct 
drm_gem_object *obj)
goto err_put_pages;
}
/* Map the pages for use by the h/w. */
-   dma_map_sg(obj->dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+   ret = dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
+   if (ret)
+   goto err_free_sgt;
 
shmem->sgt = sgt;
 
return sgt;
 
+err_free_sgt:
+   sg_free_table(sgt);
+   kfree(sgt);
 err_put_pages:
drm_gem_shmem_put_pages(shmem);
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index dfdf4d4..5ed22dd 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -617,6 +617,7 @@ struct sg_table *drm_gem_map_dma_buf(struct 
dma_buf_attachment *attach,
 {
struct drm_gem_object *obj = attach->dmabuf->priv;
struct sg_table *sgt;
+   int ret;
 
if (WARN_ON(dir == DMA_NONE))
return ERR_PTR(-EINVAL);
@@ -626,11 +627,12 @@ struct sg_table *drm_gem_map_dma_buf(struct 
dma_buf_attachment *attach,
else
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
 
-   if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
- DMA_ATTR_SKIP_CPU_SYNC)) {
+   ret = dma_map_sgtable(attach->dev, sgt, dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+   if (ret) {
sg_free_table(sgt);
kfree(sgt);
-   sgt 

[PATCH v4 05/38] drm: prime: use sgtable iterators in drm_prime_sg_to_page_addr_arrays()

2020-05-12 Thread Marek Szyprowski
Replace the current hand-crafted code for extracting pages and DMA
addresses from the given scatterlist by the much more robust
code based on the generic scatterlist iterators and recently
introduced sg_table-based wrappers. The resulting code is simple and
easy to understand, so the comment describing the old code is no
longer needed.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/drm_prime.c | 47 ++---
 1 file changed, 14 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 1d2e5fe..dfdf4d4 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -985,45 +985,26 @@ struct drm_gem_object *drm_gem_prime_import(struct 
drm_device *dev,
 int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
 dma_addr_t *addrs, int max_entries)
 {
-   unsigned count;
-   struct scatterlist *sg;
-   struct page *page;
-   u32 page_len, page_index;
-   dma_addr_t addr;
-   u32 dma_len, dma_index;
+   struct sg_dma_page_iter dma_iter;
+   struct sg_page_iter page_iter;
+   struct page **p = pages;
+   dma_addr_t *a = addrs;
 
-   /*
-* Scatterlist elements contains both pages and DMA addresses, but
-* one shoud not assume 1:1 relation between them. The sg->length is
-* the size of the physical memory chunk described by the sg->page,
-* while sg_dma_len(sg) is the size of the DMA (IO virtual) chunk
-* described by the sg_dma_address(sg).
-*/
-   page_index = 0;
-   dma_index = 0;
-   for_each_sg(sgt->sgl, sg, sgt->nents, count) {
-   page_len = sg->length;
-   page = sg_page(sg);
-   dma_len = sg_dma_len(sg);
-   addr = sg_dma_address(sg);
-
-   while (pages && page_len > 0) {
-   if (WARN_ON(page_index >= max_entries))
+   if (pages) {
+   for_each_sgtable_page(sgt, &page_iter, 0) {
+   if (p - pages >= max_entries)
return -1;
-   pages[page_index] = page;
-   page++;
-   page_len -= PAGE_SIZE;
-   page_index++;
+   *p++ = sg_page_iter_page(&page_iter);
}
-   while (addrs && dma_len > 0) {
-   if (WARN_ON(dma_index >= max_entries))
+   }
+   if (addrs) {
+   for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
+   if (a - addrs >= max_entries)
return -1;
-   addrs[dma_index] = addr;
-   addr += PAGE_SIZE;
-   dma_len -= PAGE_SIZE;
-   dma_index++;
+   *a++ = sg_page_iter_dma_address(&dma_iter);
}
}
+
return 0;
 }
 EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 15/38] drm: mediatek: use common helper for extracting pages array

2020-05-12 Thread Marek Szyprowski
Use common helper for converting a sg_table object into struct
page pointer array.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/mediatek/mtk_drm_gem.c | 9 ++---
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index 6c34c06..14fcd48 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -233,9 +233,7 @@ void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)
 {
struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
struct sg_table *sgt;
-   struct sg_page_iter iter;
unsigned int npages;
-   unsigned int i = 0;
 
if (mtk_gem->kvaddr)
return mtk_gem->kvaddr;
@@ -249,11 +247,8 @@ void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)
if (!mtk_gem->pages)
goto out;
 
-   for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) {
-   mtk_gem->pages[i++] = sg_page_iter_page(&iter);
-   if (i > npages)
-   break;
-   }
+   drm_prime_sg_to_page_addr_arrays(sgt, mtk_gem->pages, NULL, npages);
+
mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
   pgprot_writecombine(PAGE_KERNEL));
 
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 03/38] iommu: add generic helper for mapping sgtable objects

2020-05-12 Thread Marek Szyprowski
struct sg_table is a common structure used for describing a memory
buffer. It consists of a scatterlist with memory pages and DMA addresses
(sgl entry), as well as the number of scatterlist entries: CPU pages
(orig_nents entry) and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling mapping functions with a wrong number of entries.

To avoid such issues, lets introduce a common wrapper operating directly
on the struct sg_table objects, which take care of the proper use of
the nents and orig_nents entries.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 include/linux/iommu.h | 16 
 1 file changed, 16 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 7cfd2dd..ba662ba 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -478,6 +478,22 @@ extern size_t iommu_map_sg_atomic(struct iommu_domain 
*domain,
 extern void iommu_set_fault_handler(struct iommu_domain *domain,
iommu_fault_handler_t handler, void *token);
 
+/**
+ * iommu_map_sgtable - Map the given buffer to the IOMMU domain
+ * @domain:The IOMMU domain to perfor
+ * @iova:  The start addrees to map the buffer
+ * @sgt:   The sg_table object describing the buffer
+ * @prot:  IOMMU protection bits
+ *
+ * Create a mapping at @iova for the buffer described by a scatterlist
+ * stored in the given sg_table object in the provided IOMMU domain.
+ */
+static inline size_t iommu_map_sgtable(struct iommu_domain *domain,
+   unsigned long iova, struct sg_table *sgt, int prot)
+{
+   return iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, prot);
+}
+
 extern void iommu_get_resv_regions(struct device *dev, struct list_head *list);
 extern void iommu_put_resv_regions(struct device *dev, struct list_head *list);
 extern void generic_iommu_put_resv_regions(struct device *dev,
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 10/38] drm: exynos: use common helper for a scatterlist contiguity check

2020-05-12 Thread Marek Szyprowski
Use common helper for checking the contiguity of the imported dma-buf.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 23 +++
 1 file changed, 3 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c 
b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 0df57ee..a49a8ea 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -431,27 +431,10 @@ struct drm_gem_object *
 {
struct exynos_drm_gem *exynos_gem;
 
-   if (sgt->nents < 1)
+   /* check if the entries in the sg_table are contiguous */
+   if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size) {
+   DRM_ERROR("buffer chunks must be mapped contiguously");
return ERR_PTR(-EINVAL);
-
-   /*
-* Check if the provided buffer has been mapped as contiguous
-* into DMA address space.
-*/
-   if (sgt->nents > 1) {
-   dma_addr_t next_addr = sg_dma_address(sgt->sgl);
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt->sgl, s, sgt->nents, i) {
-   if (!sg_dma_len(s))
-   break;
-   if (sg_dma_address(s) != next_addr) {
-   DRM_ERROR("buffer chunks must be mapped 
contiguously");
-   return ERR_PTR(-EINVAL);
-   }
-   next_addr = sg_dma_address(s) + sg_dma_len(s);
-   }
}
 
exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size);
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 21/38] drm: rockchip: use common helper for a scatterlist contiguity check

2020-05-12 Thread Marek Szyprowski
Use common helper for checking the contiguity of the imported dma-buf.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 19 +--
 1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 0d18846..21f8cb2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -460,23 +460,6 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct 
drm_gem_object *obj)
return sgt;
 }
 
-static unsigned long rockchip_sg_get_contiguous_size(struct sg_table *sgt,
-int count)
-{
-   struct scatterlist *s;
-   dma_addr_t expected = sg_dma_address(sgt->sgl);
-   unsigned int i;
-   unsigned long size = 0;
-
-   for_each_sg(sgt->sgl, s, count, i) {
-   if (sg_dma_address(s) != expected)
-   break;
-   expected = sg_dma_address(s) + sg_dma_len(s);
-   size += sg_dma_len(s);
-   }
-   return size;
-}
-
 static int
 rockchip_gem_iommu_map_sg(struct drm_device *drm,
  struct dma_buf_attachment *attach,
@@ -498,7 +481,7 @@ static unsigned long rockchip_sg_get_contiguous_size(struct 
sg_table *sgt,
if (!count)
return -EINVAL;
 
-   if (rockchip_sg_get_contiguous_size(sg, count) < attach->dmabuf->size) {
+   if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
DRM_ERROR("failed to map sg_table to contiguous linear 
address.\n");
dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
 DMA_BIDIRECTIONAL);
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 09/38] drm: etnaviv: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 12 +---
 drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 13 +++--
 2 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index dc9ef30..cc50c7b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -27,7 +27,7 @@ static void etnaviv_gem_scatter_map(struct etnaviv_gem_object 
*etnaviv_obj)
 * because display controller, GPU, etc. are not coherent.
 */
if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
-   dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+   dma_map_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
 }
 
 static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object 
*etnaviv_obj)
@@ -51,7 +51,7 @@ static void etnaviv_gem_scatterlist_unmap(struct 
etnaviv_gem_object *etnaviv_obj
 * discard those writes.
 */
if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
-   dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
 }
 
 /* called with etnaviv_obj->lock held */
@@ -404,9 +404,8 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
}
 
if (etnaviv_obj->flags & ETNA_BO_CACHED) {
-   dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
-   etnaviv_obj->sgt->nents,
-   etnaviv_op_to_dma_dir(op));
+   dma_sync_sgtable_for_cpu(dev->dev, etnaviv_obj->sgt,
+etnaviv_op_to_dma_dir(op));
etnaviv_obj->last_cpu_prep_op = op;
}
 
@@ -421,8 +420,7 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
if (etnaviv_obj->flags & ETNA_BO_CACHED) {
/* fini without a prep is almost certainly a userspace error */
WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
-   dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
-   etnaviv_obj->sgt->nents,
+   dma_sync_sgtable_for_device(dev->dev, etnaviv_obj->sgt,
etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
etnaviv_obj->last_cpu_prep_op = 0;
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 3607d34..13b1005 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -79,7 +79,7 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context 
*context, u32 iova,
if (!context || !sgt)
return -EINVAL;
 
-   for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+   for_each_sgtable_dma_sg(sgt, sg, i) {
u32 pa = sg_dma_address(sg) - sg->offset;
size_t bytes = sg_dma_len(sg) + sg->offset;
 
@@ -95,14 +95,7 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context 
*context, u32 iova,
return 0;
 
 fail:
-   da = iova;
-
-   for_each_sg(sgt->sgl, sg, i, j) {
-   size_t bytes = sg_dma_len(sg) + sg->offset;
-
-   etnaviv_context_unmap(context, da, bytes);
-   da += bytes;
-   }
+   etnaviv_context_unmap(context, iova, da - iova);
return ret;
 }
 
@@ -113,7 +106,7 @@ static void etnaviv_iommu_unmap(struct 
etnaviv_iommu_context *context, u32 iova,
unsigned int da = iova;
int i;
 
-   for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+   

[PATCH v4 26/38] drm: vmwgfx: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
Acked-by: Roland Scheidegger 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c | 17 -
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index bf0bc46..49ed6ad 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -362,8 +362,7 @@ static void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt 
*vmw_tt)
 {
struct device *dev = vmw_tt->dev_priv->dev->dev;
 
-   dma_unmap_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.nents,
-   DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(dev, vmw_tt->sgt, DMA_BIDIRECTIONAL, 0);
vmw_tt->sgt.nents = vmw_tt->sgt.orig_nents;
 }
 
@@ -383,16 +382,8 @@ static void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt 
*vmw_tt)
 static int vmw_ttm_map_for_dma(struct vmw_ttm_tt *vmw_tt)
 {
struct device *dev = vmw_tt->dev_priv->dev->dev;
-   int ret;
-
-   ret = dma_map_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.orig_nents,
-DMA_BIDIRECTIONAL);
-   if (unlikely(ret == 0))
-   return -ENOMEM;
 
-   vmw_tt->sgt.nents = ret;
-
-   return 0;
+   return dma_map_sgtable(dev, vmw_tt->sgt, DMA_BIDIRECTIONAL, 0);
 }
 
 /**
@@ -449,10 +440,10 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
if (unlikely(ret != 0))
goto out_sg_alloc_fail;
 
-   if (vsgt->num_pages > vmw_tt->sgt.nents) {
+   if (vsgt->num_pages > vmw_tt->sgt.orig_nents) {
uint64_t over_alloc =
sgl_size * (vsgt->num_pages -
-   vmw_tt->sgt.nents);
+   vmw_tt->sgt.orig_nents);
 
ttm_mem_global_free(glob, over_alloc);
vmw_tt->sg_alloc_size -= over_alloc;
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 12/38] drm: i915: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

This driver creatively uses sg_table->orig_nents to store the size of the
allocated scatterlist and ignores the number of the entries returned by
dma_map_sg function. The sg_table->orig_nents is (mis)used to properly
free the (over)allocated scatterlist.

This patch only introduces the common DMA-mapping wrappers operating
directly on the struct sg_table objects to the dmabuf related functions,
so the other drivers, which might share buffers with i915 could rely on
the properly set nents and orig_nents values.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c   | 11 +++
 drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c |  7 +++
 2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c 
b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
index 7db5a79..6c67810 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -48,12 +48,9 @@ static struct sg_table *i915_gem_map_dma_buf(struct 
dma_buf_attachment *attachme
src = sg_next(src);
}
 
-   if (!dma_map_sg_attrs(attachment->dev,
- st->sgl, st->nents, dir,
- DMA_ATTR_SKIP_CPU_SYNC)) {
-   ret = -ENOMEM;
+   ret = dma_map_sgtable(attachment->dev, st, dir, DMA_ATTR_SKIP_CPU_SYNC);
+   if (ret)
goto err_free_sg;
-   }
 
return st;
 
@@ -73,9 +70,7 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment 
*attachment,
 {
struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf);
 
-   dma_unmap_sg_attrs(attachment->dev,
-  sg->sgl, sg->nents, dir,
-  DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(attachment->dev, sg, dir, DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sg);
kfree(sg);
 
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c 
b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
index debaf7b..be30b27 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
@@ -28,10 +28,9 @@ static struct sg_table *mock_map_dma_buf(struct 
dma_buf_attachment *attachment,
sg = sg_next(sg);
}
 
-   if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
-   err = -ENOMEM;
+   err = dma_map_sgtable(attachment->dev, st, dir, 0);
+   if (err)
goto err_st;
-   }
 
return st;
 
@@ -46,7 +45,7 @@ static void mock_unmap_dma_buf(struct dma_buf_attachment 
*attachment,
   struct sg_table *st,
   enum dma_data_direction dir)
 {
-   dma_unmap_sg(attachment->dev, st->sgl, st->nents, dir);
+   dma_unmap_sgtable(attachment->dev, st, dir, 0);
sg_free_table(st);
kfree(st);
 }
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 25/38] drm: virtio: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/virtio/virtgpu_object.c | 36 +++--
 drivers/gpu/drm/virtio/virtgpu_vq.c | 12 +--
 2 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c 
b/drivers/gpu/drm/virtio/virtgpu_object.c
index 6ccbd01..399556f 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -72,9 +72,8 @@ void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo)
 
if (shmem->pages) {
if (shmem->mapped) {
-   dma_unmap_sg(vgdev->vdev->dev.parent,
-shmem->pages->sgl, shmem->mapped,
-DMA_TO_DEVICE);
+   dma_unmap_sgtable(vgdev->vdev->dev.parent,
+shmem->pages, DMA_TO_DEVICE, 0);
shmem->mapped = 0;
}
 
@@ -157,13 +156,13 @@ static int virtio_gpu_object_shmem_init(struct 
virtio_gpu_device *vgdev,
}
 
if (use_dma_api) {
-   shmem->mapped = dma_map_sg(vgdev->vdev->dev.parent,
-  shmem->pages->sgl,
-  shmem->pages->nents,
-  DMA_TO_DEVICE);
-   *nents = shmem->mapped;
+   ret = dma_map_sgtable(vgdev->vdev->dev.parent,
+ shmem->pages, DMA_TO_DEVICE, 0);
+   if (ret)
+   return ret;
+   *nents = shmem->mapped = shmem->pages->nents;
} else {
-   *nents = shmem->pages->nents;
+   *nents = shmem->pages->orig_nents;
}
 
*ents = kmalloc_array(*nents, sizeof(struct virtio_gpu_mem_entry),
@@ -173,13 +172,20 @@ static int virtio_gpu_object_shmem_init(struct 
virtio_gpu_device *vgdev,
return -ENOMEM;
}
 
-   for_each_sg(shmem->pages->sgl, sg, *nents, si) {
-   (*ents)[si].addr = cpu_to_le64(use_dma_api
-  ? sg_dma_address(sg)
-  : sg_phys(sg));
-   (*ents)[si].length = cpu_to_le32(sg->length);
-   (*ents)[si].padding = 0;
+   if (use_dma_api) {
+   for_each_sgtable_dma_sg(shmem->pages, sg, si) {
+   (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg));
+   (*ents)[si].length = cpu_to_le32(sg_dma_len(sg));
+   (*ents)[si].padding = 0;
+   }
+   } else {
+   for_each_sgtable_sg(shmem->pages, sg, si) {
+   (*ents)[si].addr = cpu_to_le64(sg_phys(sg));
+   (*ents)[si].length = cpu_to_le32(sg->length);
+   (*ents)[si].padding = 0;
+   }
}
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c 
b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 9e663a5..e5765db 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -302,7 +302,7 @@ static struct sg_table *vmalloc_to_sgt(char *data, uint32_t 
size, int *sg_ents)
return NULL;
}
 
-   for_each_sg(sgt->sgl, sg, *sg_ents, i) {
+   for_each_sgtable_sg(sgt, sg, i) {
pg = vmalloc_to_page(data);
if (!pg) {
sg_free_table(sgt);
@@ -603,9 +603,8 @@ void virtio_gpu_c

[PATCH v4 04/38] drm: prime: add common helper to check scatterlist contiguity

2020-05-12 Thread Marek Szyprowski
It is a common operation done by DRM drivers to check the contiguity
of the DMA-mapped buffer described by a scatterlist in the
sg_table object. Let's add a common helper for this operation.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/drm_gem_cma_helper.c | 23 +++
 drivers/gpu/drm/drm_prime.c  | 26 ++
 include/drm/drm_prime.h  |  2 ++
 3 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c 
b/drivers/gpu/drm/drm_gem_cma_helper.c
index 12e98fb..9f2d13e 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -471,26 +471,9 @@ struct drm_gem_object *
 {
struct drm_gem_cma_object *cma_obj;
 
-   if (sgt->nents != 1) {
-   /* check if the entries in the sg_table are contiguous */
-   dma_addr_t next_addr = sg_dma_address(sgt->sgl);
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt->sgl, s, sgt->nents, i) {
-   /*
-* sg_dma_address(s) is only valid for entries
-* that have sg_dma_len(s) != 0
-*/
-   if (!sg_dma_len(s))
-   continue;
-
-   if (sg_dma_address(s) != next_addr)
-   return ERR_PTR(-EINVAL);
-
-   next_addr = sg_dma_address(s) + sg_dma_len(s);
-   }
-   }
+   /* check if the entries in the sg_table are contiguous */
+   if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size)
+   return ERR_PTR(-EINVAL);
 
/* Create a CMA GEM buffer. */
cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 282774e..1d2e5fe 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -826,6 +826,32 @@ struct sg_table *drm_prime_pages_to_sg(struct page 
**pages, unsigned int nr_page
 EXPORT_SYMBOL(drm_prime_pages_to_sg);
 
 /**
+ * drm_prime_get_contiguous_size - returns the contiguous size of the buffer
+ * @sgt: sg_table describing the buffer to check
+ *
+ * This helper calculates the contiguous size in the DMA address space
+ * of the the buffer described by the provided sg_table.
+ *
+ * This is useful for implementing
+ * &drm_gem_object_funcs.gem_prime_import_sg_table.
+ */
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt)
+{
+   dma_addr_t expected = sg_dma_address(sgt->sgl);
+   struct sg_dma_page_iter dma_iter;
+   unsigned long size = 0;
+
+   for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
+   if (sg_page_iter_dma_address(&dma_iter) != expected)
+   break;
+   expected += PAGE_SIZE;
+   size += PAGE_SIZE;
+   }
+   return size;
+}
+EXPORT_SYMBOL(drm_prime_get_contiguous_size);
+
+/**
  * drm_gem_prime_export - helper library implementation of the export callback
  * @obj: GEM object to export
  * @flags: flags like DRM_CLOEXEC and DRM_RDWR
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
index 9af7422..47ef116 100644
--- a/include/drm/drm_prime.h
+++ b/include/drm/drm_prime.h
@@ -92,6 +92,8 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
 struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj,
 int flags);
 
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt);
+
 /* helper functions for importing */
 struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
struct dma_buf *dma_buf,
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 07/38] drm: amdgpu: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
Reviewed-by: Christian König 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c  | 6 +++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c  | 9 +++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 8 
 3 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index 43d8ed7..519ce44 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -307,8 +307,8 @@ static struct sg_table *amdgpu_dma_buf_map(struct 
dma_buf_attachment *attach,
if (IS_ERR(sgt))
return sgt;
 
-   if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
- DMA_ATTR_SKIP_CPU_SYNC))
+   if (dma_map_sgtable(attach->dev, sgt, dir,
+   DMA_ATTR_SKIP_CPU_SYNC))
goto error_free;
break;
 
@@ -349,7 +349,7 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment 
*attach,
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
 
if (sgt->sgl->page_link) {
-   dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+   dma_unmap_sgtable(attach->dev, sgt, dir, 0);
sg_free_table(sgt);
kfree(sgt);
} else {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 9cbecd5..57a5d56 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1024,7 +1024,6 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 {
struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
struct amdgpu_ttm_tt *gtt = (void *)ttm;
-   unsigned nents;
int r;
 
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
@@ -1039,9 +1038,8 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
goto release_sg;
 
/* Map SG to device */
-   r = -ENOMEM;
-   nents = dma_map_sg(adev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
-   if (nents == 0)
+   r = dma_map_sgtable(adev->dev, ttm->sg, direction, 0);
+   if (r)
goto release_sg;
 
/* convert SG to linear array of pages and dma addresses */
@@ -1072,8 +1070,7 @@ static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt 
*ttm)
return;
 
/* unmap the pages mapped to the device */
-   dma_unmap_sg(adev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
-
+   dma_unmap_sgtable(adev->dev, ttm->sg, direction, 0);
sg_free_table(ttm->sg);
 
 #if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index d399e58..75495a7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -477,11 +477,11 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
if (r)
goto error_free;
 
-   for_each_sg((*sgt)->sgl, sg, num_entries, i)
+   for_each_sgtable_sg(*sgt, sg, i)
sg->length = 0;
 
node = mem->mm_node;
-   for_each_sg((*sgt)->sgl, sg, num_entries, i) {
+   for_each_sgtable_sg(*sgt, sg, i) {
phys_addr_t phys = (node->start << PAGE_SHIFT) +
adev->gmc.aper_base;
size_t size = node->size << PAGE_SHIFT;
@@ -501,7 +501,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_devi

[PATCH v4 11/38] drm: exynos: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index fcee33a..7014a8c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -395,8 +395,8 @@ static void g2d_userptr_put_dma_addr(struct g2d_data *g2d,
return;
 
 out:
-   dma_unmap_sg(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt->sgl,
-   g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt,
+ DMA_BIDIRECTIONAL, 0);
 
pages = frame_vector_pages(g2d_userptr->vec);
if (!IS_ERR(pages)) {
@@ -511,10 +511,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
g2d_data *g2d,
 
g2d_userptr->sgt = sgt;
 
-   if (!dma_map_sg(to_dma_dev(g2d->drm_dev), sgt->sgl, sgt->nents,
-   DMA_BIDIRECTIONAL)) {
+   ret = dma_map_sgtable(to_dma_dev(g2d->drm_dev), sgt,
+ DMA_BIDIRECTIONAL, 0);
+   if (ret) {
DRM_DEV_ERROR(g2d->dev, "failed to map sgt with dma region.\n");
-   ret = -ENOMEM;
goto err_sg_free_table;
}
 
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 16/38] drm: msm: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/msm/msm_gem.c| 13 +
 drivers/gpu/drm/msm/msm_gpummu.c | 14 ++
 drivers/gpu/drm/msm/msm_iommu.c  |  2 +-
 3 files changed, 12 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 5a6a79f..6318c20 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -53,11 +53,10 @@ static void sync_for_device(struct msm_gem_object *msm_obj)
struct device *dev = msm_obj->base.dev->dev;
 
if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {
-   dma_sync_sg_for_device(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_sync_sgtable_for_device(dev, msm_obj->sgt,
+   DMA_BIDIRECTIONAL);
} else {
-   dma_map_sg(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_map_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
}
 }
 
@@ -66,11 +65,9 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj)
struct device *dev = msm_obj->base.dev->dev;
 
if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {
-   dma_sync_sg_for_cpu(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_sync_sgtable_for_cpu(dev, msm_obj->sgt, DMA_BIDIRECTIONAL);
} else {
-   dma_unmap_sg(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
}
 }
 
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
index 34980d8..5d8da4d 100644
--- a/drivers/gpu/drm/msm/msm_gpummu.c
+++ b/drivers/gpu/drm/msm/msm_gpummu.c
@@ -35,21 +35,19 @@ static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t 
iova,
 {
struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE;
-   struct scatterlist *sg;
+   struct sg_dma_page_iter dma_iter;
unsigned prot_bits = 0;
-   unsigned i, j;
 
if (prot & IOMMU_WRITE)
prot_bits |= 1;
if (prot & IOMMU_READ)
prot_bits |= 2;
 
-   for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-   dma_addr_t addr = sg->dma_address;
-   for (j = 0; j < sg->length / GPUMMU_PAGE_SIZE; j++, idx++) {
-   gpummu->table[idx] = addr | prot_bits;
-   addr += GPUMMU_PAGE_SIZE;
-   }
+   for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
+   dma_addr_t addr = sg_page_iter_dma_address(&dma_iter);
+
+   BUILD_BUG_ON(GPUMMU_PAGE_SIZE != PAGE_SIZE);
+   gpummu->table[idx++] = addr | prot_bits;
}
 
/* we can improve by deferring flush for multiple map() */
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index ad58cfe..d322b39 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -43,7 +43,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
struct msm_iommu *iommu = to_msm_iommu(mmu);
size_t ret;
 
-   ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot);
+   ret = iommu_map_sgtable(iommu->domain, iova, sgt, prot);
WARN_ON(!ret);
 
return (ret == len) ? 0 : -EINVAL;
-- 
1.9.1

___
dri-devel mailing list
dri-

[PATCH v4 32/38] staging: ion: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/staging/android/ion/ion.c | 25 +++
 drivers/staging/android/ion/ion_heap.c| 44 ---
 drivers/staging/android/ion/ion_system_heap.c |  2 +-
 3 files changed, 25 insertions(+), 46 deletions(-)

diff --git a/drivers/staging/android/ion/ion.c 
b/drivers/staging/android/ion/ion.c
index 38b51ea..2db041d 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -147,14 +147,14 @@ static struct sg_table *dup_sg_table(struct sg_table 
*table)
if (!new_table)
return ERR_PTR(-ENOMEM);
 
-   ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
+   ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL);
if (ret) {
kfree(new_table);
return ERR_PTR(-ENOMEM);
}
 
new_sg = new_table->sgl;
-   for_each_sg(table->sgl, sg, table->nents, i) {
+   for_each_sgtable_sg(table, sg, i) {
memcpy(new_sg, sg, sizeof(*sg));
new_sg->dma_address = 0;
new_sg = sg_next(new_sg);
@@ -224,12 +224,13 @@ static struct sg_table *ion_map_dma_buf(struct 
dma_buf_attachment *attachment,
 {
struct ion_dma_buf_attachment *a = attachment->priv;
struct sg_table *table;
+   int ret;
 
table = a->table;
 
-   if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
-   direction))
-   return ERR_PTR(-ENOMEM);
+   ret = dma_map_sgtable(attachment->dev, table, direction);
+   if (ret)
+   return ERR_PTR(ret);
 
return table;
 }
@@ -238,7 +239,7 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment 
*attachment,
  struct sg_table *table,
  enum dma_data_direction direction)
 {
-   dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
+   dma_unmap_sgtable(attachment->dev, table, direction);
 }
 
 static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
@@ -296,10 +297,8 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf 
*dmabuf,
}
 
mutex_lock(&buffer->lock);
-   list_for_each_entry(a, &buffer->attachments, list) {
-   dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
-   direction);
-   }
+   list_for_each_entry(a, &buffer->attachments, list)
+   dma_sync_sgtable_for_cpu(a->dev, a->table, direction);
 
 unlock:
mutex_unlock(&buffer->lock);
@@ -319,10 +318,8 @@ static int ion_dma_buf_end_cpu_access(struct dma_buf 
*dmabuf,
}
 
mutex_lock(&buffer->lock);
-   list_for_each_entry(a, &buffer->attachments, list) {
-   dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
-  direction);
-   }
+   list_for_each_entry(a, &buffer->attachments, list)
+   dma_sync_sgtable_for_device(a->dev, a->table, direction);
mutex_unlock(&buffer->lock);
 
return 0;
diff --git a/drivers/staging/android/ion/ion_heap.c 
b/drivers/staging/android/ion/ion_heap.c
index 9c23b23..79f2794 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -20,8 +20,7 @@
 void *ion_heap_map_kernel(struct ion_heap *heap,
  struct ion_buffer *buffer)
 {
-   struct scatterlist *sg;
-   int i, j;
+   struct sg_page_iter piter;
void *vaddr;
pgprot_t pgprot;
struct sg_table *table 

[PATCH v4 20/38] drm: radeon: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
Reviewed-by: Christian König 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/radeon/radeon_ttm.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c 
b/drivers/gpu/drm/radeon/radeon_ttm.c
index 5d50c9e..0e3eb0d 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -481,7 +481,7 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 {
struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
struct radeon_ttm_tt *gtt = (void *)ttm;
-   unsigned pinned = 0, nents;
+   unsigned pinned = 0;
int r;
 
int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
@@ -521,9 +521,8 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
if (r)
goto release_sg;
 
-   r = -ENOMEM;
-   nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
-   if (nents == 0)
+   r = dma_map_sgtable(rdev->dev, ttm->sg, direction, 0);
+   if (r)
goto release_sg;
 
drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
@@ -554,9 +553,9 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
return;
 
/* free the sg table and pages again */
-   dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
+   dma_unmap_sgtable(rdev->dev, ttm->sg, direction, 0);
 
-   for_each_sg_page(ttm->sg->sgl, &sg_iter, ttm->sg->nents, 0) {
+   for_each_sgtable_page(ttm->sg, &sg_iter, 0) {
struct page *page = sg_page_iter_page(&sg_iter);
if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY))
set_page_dirty(page);
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 27/38] xen: gntdev: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/xen/gntdev-dmabuf.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/xen/gntdev-dmabuf.c b/drivers/xen/gntdev-dmabuf.c
index 75d3bb9..ba6cad8 100644
--- a/drivers/xen/gntdev-dmabuf.c
+++ b/drivers/xen/gntdev-dmabuf.c
@@ -247,10 +247,9 @@ static void dmabuf_exp_ops_detach(struct dma_buf *dma_buf,
 
if (sgt) {
if (gntdev_dmabuf_attach->dir != DMA_NONE)
-   dma_unmap_sg_attrs(attach->dev, sgt->sgl,
-  sgt->nents,
-  gntdev_dmabuf_attach->dir,
-  DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(attach->dev, sgt,
+ gntdev_dmabuf_attach->dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
}
 
@@ -288,8 +287,8 @@ static void dmabuf_exp_ops_detach(struct dma_buf *dma_buf,
sgt = dmabuf_pages_to_sgt(gntdev_dmabuf->pages,
  gntdev_dmabuf->nr_pages);
if (!IS_ERR(sgt)) {
-   if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
- DMA_ATTR_SKIP_CPU_SYNC)) {
+   if (dma_map_sgtable(attach->dev, sgt, dir,
+   DMA_ATTR_SKIP_CPU_SYNC)) {
sg_free_table(sgt);
kfree(sgt);
sgt = ERR_PTR(-ENOMEM);
@@ -625,7 +624,7 @@ static struct gntdev_dmabuf *dmabuf_imp_alloc_storage(int 
count)
 
/* Now convert sgt to array of pages and check for page validity. */
i = 0;
-   for_each_sg_page(sgt->sgl, &sg_iter, sgt->nents, 0) {
+   for_each_sgtable_page(sgt, &sg_iter, 0) {
struct page *page = sg_page_iter_page(&sg_iter);
/*
 * Check if page is valid: this can happen if we are given
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 22/38] drm: rockchip: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 23 ++-
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 21f8cb2..566557b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -36,8 +36,8 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object 
*rk_obj)
 
rk_obj->dma_addr = rk_obj->mm.start;
 
-   ret = iommu_map_sg(private->domain, rk_obj->dma_addr, rk_obj->sgt->sgl,
-  rk_obj->sgt->nents, prot);
+   ret = iommu_map_sgtable(private->domain, rk_obj->dma_addr, rk_obj->sgt,
+   prot);
if (ret < rk_obj->base.size) {
DRM_ERROR("failed to map buffer: size=%zd request_size=%zd\n",
  ret, rk_obj->base.size);
@@ -98,11 +98,10 @@ static int rockchip_gem_get_pages(struct 
rockchip_gem_object *rk_obj)
 * TODO: Replace this by drm_clflush_sg() once it can be implemented
 * without relying on symbols that are not exported.
 */
-   for_each_sg(rk_obj->sgt->sgl, s, rk_obj->sgt->nents, i)
+   for_each_sgtable_sg(rk_obj->sgt, s, i)
sg_dma_address(s) = sg_phys(s);
 
-   dma_sync_sg_for_device(drm->dev, rk_obj->sgt->sgl, rk_obj->sgt->nents,
-  DMA_TO_DEVICE);
+   dma_sync_sgtable_for_device(drm->dev, rk_obj->sgt, DMA_TO_DEVICE);
 
return 0;
 
@@ -350,8 +349,8 @@ void rockchip_gem_free_object(struct drm_gem_object *obj)
if (private->domain) {
rockchip_gem_iommu_unmap(rk_obj);
} else {
-   dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
-rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(drm->dev, rk_obj->sgt,
+ DMA_BIDIRECTIONAL, 0);
}
drm_prime_gem_destroy(obj, rk_obj->sgt);
} else {
@@ -476,15 +475,13 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct 
drm_gem_object *obj)
struct sg_table *sg,
struct rockchip_gem_object *rk_obj)
 {
-   int count = dma_map_sg(drm->dev, sg->sgl, sg->nents,
-  DMA_BIDIRECTIONAL);
-   if (!count)
-   return -EINVAL;
+   int err = dma_map_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
+   if (err)
+   return err;
 
if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
DRM_ERROR("failed to map sg_table to contiguous linear 
address.\n");
-   dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
-DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
return -EINVAL;
}
 
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 17/38] drm: omapdrm: use common helper for extracting pages array

2020-05-12 Thread Marek Szyprowski
Use common helper for converting a sg_table object into struct
page pointer array.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/omapdrm/omap_gem.c | 14 --
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c 
b/drivers/gpu/drm/omapdrm/omap_gem.c
index d08ae95..c259411 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -1297,10 +1297,9 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct 
drm_device *dev, size_t size,
omap_obj->dma_addr = sg_dma_address(sgt->sgl);
} else {
/* Create pages list from sgt */
-   struct sg_page_iter iter;
struct page **pages;
unsigned int npages;
-   unsigned int i = 0;
+   unsigned int ret;
 
npages = DIV_ROUND_UP(size, PAGE_SIZE);
pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL);
@@ -1311,14 +1310,9 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct 
drm_device *dev, size_t size,
}
 
omap_obj->pages = pages;
-
-   for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) {
-   pages[i++] = sg_page_iter_page(&iter);
-   if (i > npages)
-   break;
-   }
-
-   if (WARN_ON(i != npages)) {
+   ret = drm_prime_sg_to_page_addr_arrays(sgt, pages, NULL,
+  npages);
+   if (WARN_ON(ret)) {
omap_gem_free_object(obj);
obj = ERR_PTR(-ENOMEM);
goto done;
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 29/38] drm: rcar-du: fix common struct sg_table related issues

2020-05-12 Thread Marek Szyprowski
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

dma_map_sgtable() function returns zero or an error code, so adjust the
return value check for the vsp1_du_map_sg() function.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c  | 3 +--
 drivers/media/platform/vsp1/vsp1_drm.c | 8 
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c 
b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 5e4faf2..2fc1816 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -197,9 +197,8 @@ int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct 
drm_framebuffer *fb,
goto fail;
 
ret = vsp1_du_map_sg(vsp->vsp, sgt);
-   if (!ret) {
+   if (ret) {
sg_free_table(sgt);
-   ret = -ENOMEM;
goto fail;
}
}
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index a4a45d6..86d5e3f 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -912,8 +912,8 @@ int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
 * skip cache sync. This will need to be revisited when support for
 * non-coherent buffers will be added to the DU driver.
 */
-   return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
-   DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+   return dma_map_sgtable(vsp1->bus_master, sgt, DMA_TO_DEVICE,
+  DMA_ATTR_SKIP_CPU_SYNC);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
 
@@ -921,8 +921,8 @@ void vsp1_du_unmap_sg(struct device *dev, struct sg_table 
*sgt)
 {
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 
-   dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
-  DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(vsp1->bus_master, sgt, DMA_TO_DEVICE,
+ DMA_ATTR_SKIP_CPU_SYNC);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
 
-- 
1.9.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 38/38] videobuf2: use sgtable-based scatterlist wrappers

2020-05-12 Thread Marek Szyprowski
Use recently introduced common wrappers operating directly on the struct
sg_table objects and scatterlist page iterators to make the code a bit
more compact, robust, easier to follow and copy/paste safe.

No functional change, because the code already properly did all the
scaterlist related calls.

Signed-off-by: Marek Szyprowski 
---
For more information, see '[PATCH v4 00/38] DRM: fix struct sg_table nents
vs. orig_nents misuse' thread:
https://lore.kernel.org/dri-devel/20200512085710.14688-1-m.szyprow...@samsung.com/T/
---
 .../media/common/videobuf2/videobuf2-dma-contig.c  | 41 ++
 drivers/media/common/videobuf2/videobuf2-dma-sg.c  | 32 +++--
 drivers/media/common/videobuf2/videobuf2-vmalloc.c | 12 +++
 3 files changed, 34 insertions(+), 51 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c 
b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
index d3a3ee5..bf31a9d 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -48,16 +48,15 @@ struct vb2_dc_buf {
 
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
-   struct scatterlist *s;
dma_addr_t expected = sg_dma_address(sgt->sgl);
-   unsigned int i;
+   struct sg_dma_page_iter dma_iter;
unsigned long size = 0;
 
-   for_each_sg(sgt->sgl, s, sgt->nents, i) {
-   if (sg_dma_address(s) != expected)
+   for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
+   if (sg_page_iter_dma_address(&dma_iter) != expected)
break;
-   expected = sg_dma_address(s) + sg_dma_len(s);
-   size += sg_dma_len(s);
+   expected += PAGE_SIZE;
+   size += PAGE_SIZE;
}
return size;
 }
@@ -99,8 +98,7 @@ static void vb2_dc_prepare(void *buf_priv)
if (!sgt || buf->db_attach)
return;
 
-   dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,
-  buf->dma_dir);
+   dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir);
 }
 
 static void vb2_dc_finish(void *buf_priv)
@@ -112,7 +110,7 @@ static void vb2_dc_finish(void *buf_priv)
if (!sgt || buf->db_attach)
return;
 
-   dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+   dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir);
 }
 
 /*/
@@ -273,8 +271,8 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf,
 * memory locations do not require any explicit cache
 * maintenance prior or after being used by the device.
 */
-   dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
-  attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
@@ -299,8 +297,8 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
 
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
-   dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
-  attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
attach->dma_dir = DMA_NONE;
}
 
@@ -308,9 +306,8 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
 * mapping to the client with new direction, no cache sync
 * required see comment in vb2_dc_dmabuf_ops_detach()
 */
-   sgt->nents = dma_map_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
- dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
-   if (!sgt->nents) {
+   if (dma_map_sgtable(db_attach->dev, sgt, dma_dir,
+   DMA_ATTR_SKIP_CPU_SYNC)) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return ERR_PTR(-EIO);
@@ -423,8 +420,8 @@ static void vb2_dc_put_userptr(void *buf_priv)
 * No need to sync to CPU, it's already synced to the CPU
 * since the finish() memop will have been called before this.
 */
-   dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-  buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
pages = frame_vector_pages(buf->vec);
/* sgt should exist only if vector contains pages... */
BUG_ON(IS_ERR(pages));
@@ -521,9 +518,8 @@ static void *vb2_dc_get_userptr(struct device *dev, 

  1   2   >