1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-02-12 19:31:52 +00:00

Update RPI, should fix memory and USB problem

This commit is contained in:
Ycarus (Yannick Chabanois) 2019-08-15 19:10:14 +02:00
parent e632bdc531
commit 91d60c33e0
88 changed files with 9140 additions and 0 deletions

View file

@ -61,6 +61,7 @@ CONFIG_ARM_TIMER_SP804=y
CONFIG_ARM_UNWIND=y
CONFIG_ARM_VIRT_EXT=y
CONFIG_AUTO_ZRELADDR=y
# CONFIG_AX88796B_PHY is not set
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BCM2708_VCMEM=y
@ -472,6 +473,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_GPIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
# CONFIG_RPIVID_MEM is not set
CONFIG_RPS=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y

View file

@ -113,6 +113,7 @@ CONFIG_ARM_PSCI_FW=y
# CONFIG_ARM_SCMI_PROTOCOL is not set
# CONFIG_ARM_SP805_WATCHDOG is not set
CONFIG_ARM_TIMER_SP804=y
# CONFIG_AX88796B_PHY is not set
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@ -462,6 +463,7 @@ CONFIG_REGMAP_MMIO=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_RFS_ACCEL=y
# CONFIG_RPIVID_MEM is not set
CONFIG_RPS=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y

View file

@ -123,6 +123,7 @@ CONFIG_ARM_MODULE_PLTS=y
# CONFIG_ARM_SCMI_PROTOCOL is not set
# CONFIG_ARM_SP805_WATCHDOG is not set
CONFIG_ARM_TIMER_SP804=y
# CONFIG_AX88796B_PHY is not set
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@ -561,6 +562,7 @@ CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
# CONFIG_RPIVID_MEM is not set
CONFIG_RPS=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y

View file

@ -0,0 +1,38 @@
From 5d1250c4a623fba8f10e3578f10cbde75c0f41ff Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 31 Jul 2019 17:36:34 +0100
Subject: [PATCH 734/826] drm/vc4: A present but empty dmas disables audio
Overlays are unable to remove properties in the base DTB, but they
can overwrite them. Allow a present but empty 'dmas' property
to also disable the HDMI audio interface.
See: https://github.com/raspberrypi/linux/issues/2489
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 2f276222e30f..be80769d7b5b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1087,10 +1087,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
struct device *dev = &hdmi->pdev->dev;
const __be32 *addr;
int ret;
+ int len;
- if (!of_find_property(dev->of_node, "dmas", NULL)) {
+ if (!of_find_property(dev->of_node, "dmas", &len) ||
+ len == 0) {
dev_warn(dev,
- "'dmas' DT property is missing, no HDMI audio\n");
+ "'dmas' DT property is missing or empty, no HDMI audio\n");
return 0;
}
--
2.22.0

View file

@ -0,0 +1,56 @@
From e8e84b725b2d9048f34c57c85893e4c35d94ea9e Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 31 Jul 2019 17:39:37 +0100
Subject: [PATCH 735/826] overlays: Add audio parameter to vc4-kms-v3d
The audio parameter to the vc4-kms-v3d overlay allows audio support
to be disabled (it defaults to on) by adding "audio=off" to the
dtoverlay parameters.
See: https://github.com/raspberrypi/linux/issues/2489
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/boot/dts/overlays/README | 1 +
arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 8 ++++++++
2 files changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README
index 203041654d84..6131ac3d967c 100644
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -2480,6 +2480,7 @@ Params: cma-256 CMA is 256MB (needs 1GB)
cma-128 CMA is 128MB
cma-96 CMA is 96MB
cma-64 CMA is 64MB
+ audio Enable or disable audio over HDMI (default "on")
Name: vga666
diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
index 19e1d2548e7b..c5f687e8bcb9 100644
--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
@@ -134,11 +134,19 @@
};
};
+ fragment@17 {
+ target = <&hdmi>;
+ __dormant__ {
+ dmas;
+ };
+ };
+
__overrides__ {
cma-256 = <0>,"+0-1-2-3-4";
cma-192 = <0>,"-0+1-2-3-4";
cma-128 = <0>,"-0-1+2-3-4";
cma-96 = <0>,"-0-1-2+3-4";
cma-64 = <0>,"-0-1-2-3+4";
+ audio = <0>,"!17";
};
};
--
2.22.0

View file

@ -0,0 +1,33 @@
From 3560542c15a3b71ecd58e347f7fcfc3b6e7770a2 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 31 Jul 2019 17:41:47 +0100
Subject: [PATCH 736/826] overlays: Update the upstream overlay
The recent vc4-kms-v3d commit has changed the content of the
upstream overlay (even though the extra fragment is disabled).
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/boot/dts/overlays/upstream-overlay.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/overlays/upstream-overlay.dts b/arch/arm/boot/dts/overlays/upstream-overlay.dts
index 48e0ef61952c..6112640837fc 100644
--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
@@ -110,6 +110,12 @@
};
};
fragment@17 {
+ target = <&hdmi>;
+ __dormant__ {
+ dmas;
+ };
+ };
+ fragment@18 {
target = <&usb>;
#address-cells = <1>;
#size-cells = <1>;
--
2.22.0

View file

@ -0,0 +1,52 @@
From 9543c9ffe07dcfd7b7a93e9009bd004c3c1cfdec Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 1 Aug 2019 08:58:48 +0100
Subject: [PATCH 737/826] can: mcp251x: Allow more time after a reset
Some boards take longer than 5ms to power up after a reset, so allow
a few retry attempts before giving up.
See: https://github.com/raspberrypi/linux/issues/2767
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/can/spi/mcp251x.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index cae0f5b633d0..c5c2ac423fc9 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -628,6 +628,7 @@ static int mcp251x_hw_reset(struct spi_device *spi)
struct mcp251x_priv *priv = spi_get_drvdata(spi);
u8 reg;
int ret;
+ int retries = 10;
/* Wait for oscillator startup timer after power up */
mdelay(MCP251X_OST_DELAY_MS);
@@ -637,10 +638,18 @@ static int mcp251x_hw_reset(struct spi_device *spi)
if (ret)
return ret;
- /* Wait for oscillator startup timer after reset */
- mdelay(MCP251X_OST_DELAY_MS);
+ /*
+ * Wait for oscillator startup timer after reset
+ *
+ * Some devices can take longer than the expected 5ms to wake
+ * up, so allow a few retries.
+ */
+
+ do {
+ mdelay(MCP251X_OST_DELAY_MS);
+ reg = mcp251x_read_reg(spi, CANSTAT);
+ } while (!reg && retries--);
- reg = mcp251x_read_reg(spi, CANSTAT);
if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
return -ENODEV;
--
2.22.0

View file

@ -0,0 +1,44 @@
From e27970cd68f7b52523ce0992446f43b7ed2fb211 Mon Sep 17 00:00:00 2001
From: James Hughes <james.hughes@raspberrypi.org>
Date: Mon, 29 Jul 2019 12:02:59 +0100
Subject: [PATCH 738/826] Fixup FKMS interrupt handing for non-existent display
If an errant interrupt flag was received from a non-existent display,
a NULL pointer access was made. Protect against this by checking if a
second display is present prior to checking the interrupt flags.
---
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
index 8f3fe6f9246e..bcbd2f709c7f 100644
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -1056,14 +1056,17 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
vc4_crtc_handle_page_flip(crtc_list[0]);
}
- /* Check for the secondary display too */
- chan = readl(crtc_list[0]->regs + SMIDSW1);
+ if (crtc_list[1]) {
+ /* Check for the secondary display too */
+ chan = readl(crtc_list[0]->regs + SMIDSW1);
- if (chan & 1) {
- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
- if (crtc_list[1]->vblank_enabled)
- drm_crtc_handle_vblank(&crtc_list[1]->base);
- vc4_crtc_handle_page_flip(crtc_list[1]);
+ if (chan & 1) {
+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
+
+ if (crtc_list[1]->vblank_enabled)
+ drm_crtc_handle_vblank(&crtc_list[1]->base);
+ vc4_crtc_handle_page_flip(crtc_list[1]);
+ }
}
}
--
2.22.0

View file

@ -0,0 +1,422 @@
From f8838a2ac019050145abb3931dfb9270b8208e2d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Sun, 28 Jul 2019 22:22:36 +0100
Subject: [PATCH 739/826] drivers: char: Use correct name for the Raspberry Pi
video decoder
Replace the old code name with a more appropriate name - RPiVid.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/boot/dts/bcm2838.dtsi | 10 +-
arch/arm/configs/bcm2711_defconfig | 2 +-
drivers/char/broadcom/Kconfig | 8 +-
drivers/char/broadcom/Makefile | 2 +-
.../broadcom/{argon-mem.c => rpivid-mem.c} | 105 +++++++++---------
drivers/mfd/bcm2835-pm.c | 12 +-
drivers/soc/bcm/bcm2835-power.c | 6 +-
include/linux/mfd/bcm2835-pm.h | 2 +-
8 files changed, 71 insertions(+), 76 deletions(-)
rename drivers/char/broadcom/{argon-mem.c => rpivid-mem.c} (69%)
diff --git a/arch/arm/boot/dts/bcm2838.dtsi b/arch/arm/boot/dts/bcm2838.dtsi
index 9d349b3fa652..1d321ad6640a 100644
--- a/arch/arm/boot/dts/bcm2838.dtsi
+++ b/arch/arm/boot/dts/bcm2838.dtsi
@@ -409,26 +409,26 @@
};
hevc-decoder@7eb00000 {
- compatible = "raspberrypi,argon-hevc-decoder";
+ compatible = "raspberrypi,rpivid-hevc-decoder";
reg = <0x0 0x7eb00000 0x10000>;
status = "okay";
};
- argon-local-intc@7eb10000 {
- compatible = "raspberrypi,argon-local-intc";
+ rpivid-local-intc@7eb10000 {
+ compatible = "raspberrypi,rpivid-local-intc";
reg = <0x0 0x7eb10000 0x1000>;
status = "okay";
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
};
h264-decoder@7eb20000 {
- compatible = "raspberrypi,argon-h264-decoder";
+ compatible = "raspberrypi,rpivid-h264-decoder";
reg = <0x0 0x7eb20000 0x10000>;
status = "okay";
};
vp9-decoder@7eb30000 {
- compatible = "raspberrypi,argon-vp9-decoder";
+ compatible = "raspberrypi,rpivid-vp9-decoder";
reg = <0x0 0x7eb30000 0x10000>;
status = "okay";
};
diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig
index 159169797d57..2ff5dd6f5175 100644
--- a/arch/arm/configs/bcm2711_defconfig
+++ b/arch/arm/configs/bcm2711_defconfig
@@ -650,7 +650,7 @@ CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_BCM_VCIO=y
CONFIG_BCM_VC_SM=y
CONFIG_BCM2835_DEVGPIOMEM=y
-CONFIG_ARGON_MEM=m
+CONFIG_RPIVID_MEM=m
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig
index 4ba3fb4049eb..6f9b37bf6b8a 100644
--- a/drivers/char/broadcom/Kconfig
+++ b/drivers/char/broadcom/Kconfig
@@ -50,10 +50,10 @@ config BCM2835_SMI_DEV
Broadcom's Secondary Memory interface. The low-level functionality is provided
by the SMI driver itself.
-config ARGON_MEM
- tristate "Character device driver for the Argon decoder hardware"
+config RPIVID_MEM
+ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware"
default n
help
This driver provides a character device interface for memory-map operations
- so userspace tools can access the control and status registers of the Argon
- video decoder hardware.
+ so userspace tools can access the control and status registers of the
+ Raspberry Pi RPiVid video decoder hardware.
diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile
index 50767fc1b569..e06026539719 100644
--- a/drivers/char/broadcom/Makefile
+++ b/drivers/char/broadcom/Makefile
@@ -4,4 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm/
obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
-obj-$(CONFIG_ARGON_MEM) += argon-mem.o
+obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o
diff --git a/drivers/char/broadcom/argon-mem.c b/drivers/char/broadcom/rpivid-mem.c
similarity index 69%
rename from drivers/char/broadcom/argon-mem.c
rename to drivers/char/broadcom/rpivid-mem.c
index 01c36db7754a..fae84c7d3cf4 100644
--- a/drivers/char/broadcom/argon-mem.c
+++ b/drivers/char/broadcom/rpivid-mem.c
@@ -1,5 +1,5 @@
/**
- * argon-mem.c - character device access to the Argon decoder registers
+ * rpivid-mem.c - character device access to the RPiVid decoder registers
*
* Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
* register blocks such that ffmpeg plugins can access the hardware.
@@ -48,36 +48,36 @@
#include <linux/pagemap.h>
#include <linux/io.h>
-#define DRIVER_NAME "argon-mem"
+#define DRIVER_NAME "rpivid-mem"
#define DEVICE_MINOR 0
-struct argon_mem_priv {
+struct rpivid_mem_priv {
dev_t devid;
struct class *class;
- struct cdev argon_mem_cdev;
+ struct cdev rpivid_mem_cdev;
unsigned long regs_phys;
unsigned long mem_window_len;
struct device *dev;
const char *name;
};
-static int argon_mem_open(struct inode *inode, struct file *file)
+static int rpivid_mem_open(struct inode *inode, struct file *file)
{
int dev = iminor(inode);
int ret = 0;
- struct argon_mem_priv *priv;
+ struct rpivid_mem_priv *priv;
if (dev != DEVICE_MINOR)
ret = -ENXIO;
- priv = container_of(inode->i_cdev, struct argon_mem_priv,
- argon_mem_cdev);
+ priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
+ rpivid_mem_cdev);
if (!priv)
return -EINVAL;
file->private_data = priv;
return ret;
}
-static int argon_mem_release(struct inode *inode, struct file *file)
+static int rpivid_mem_release(struct inode *inode, struct file *file)
{
int dev = iminor(inode);
int ret = 0;
@@ -88,15 +88,15 @@ static int argon_mem_release(struct inode *inode, struct file *file)
return ret;
}
-static const struct vm_operations_struct argon_mem_vm_ops = {
+static const struct vm_operations_struct rpivid_mem_vm_ops = {
#ifdef CONFIG_HAVE_IOREMAP_PROT
.access = generic_access_phys
#endif
};
-static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
+static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct argon_mem_priv *priv;
+ struct rpivid_mem_priv *priv;
unsigned long pages;
priv = file->private_data;
@@ -108,7 +108,7 @@ static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_page_prot = phys_mem_access_prot(file, pages,
priv->mem_window_len,
vma->vm_page_prot);
- vma->vm_ops = &argon_mem_vm_ops;
+ vma->vm_ops = &rpivid_mem_vm_ops;
if (remap_pfn_range(vma, vma->vm_start,
pages,
priv->mem_window_len,
@@ -119,28 +119,28 @@ static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
}
static const struct file_operations
-argon_mem_fops = {
+rpivid_mem_fops = {
.owner = THIS_MODULE,
- .open = argon_mem_open,
- .release = argon_mem_release,
- .mmap = argon_mem_mmap,
+ .open = rpivid_mem_open,
+ .release = rpivid_mem_release,
+ .mmap = rpivid_mem_mmap,
};
-static const struct of_device_id argon_mem_of_match[];
-static int argon_mem_probe(struct platform_device *pdev)
+static const struct of_device_id rpivid_mem_of_match[];
+static int rpivid_mem_probe(struct platform_device *pdev)
{
int err;
void *ptr_err;
const struct of_device_id *id;
struct device *dev = &pdev->dev;
- struct device *argon_mem_dev;
+ struct device *rpivid_mem_dev;
struct resource *ioresource;
- struct argon_mem_priv *priv;
+ struct rpivid_mem_priv *priv;
/* Allocate buffers and instance data */
- priv = kzalloc(sizeof(struct argon_mem_priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
if (!priv) {
err = -ENOMEM;
@@ -149,7 +149,7 @@ static int argon_mem_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
priv->dev = dev;
- id = of_match_device(argon_mem_of_match, dev);
+ id = of_match_device(rpivid_mem_of_match, dev);
if (!id)
return -EINVAL;
priv->name = id->data;
@@ -172,9 +172,9 @@ static int argon_mem_probe(struct platform_device *pdev)
dev_err(priv->dev, "unable to allocate device number");
goto failed_alloc_chrdev;
}
- cdev_init(&priv->argon_mem_cdev, &argon_mem_fops);
- priv->argon_mem_cdev.owner = THIS_MODULE;
- err = cdev_add(&priv->argon_mem_cdev, priv->devid, 1);
+ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
+ priv->rpivid_mem_cdev.owner = THIS_MODULE;
+ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 1);
if (err != 0) {
dev_err(priv->dev, "unable to register device");
goto failed_cdev_add;
@@ -187,10 +187,10 @@ static int argon_mem_probe(struct platform_device *pdev)
if (IS_ERR(ptr_err))
goto failed_class_create;
- argon_mem_dev = device_create(priv->class, NULL,
+ rpivid_mem_dev = device_create(priv->class, NULL,
priv->devid, NULL,
priv->name);
- ptr_err = argon_mem_dev;
+ ptr_err = rpivid_mem_dev;
if (IS_ERR(ptr_err))
goto failed_device_create;
@@ -202,7 +202,7 @@ static int argon_mem_probe(struct platform_device *pdev)
failed_device_create:
class_destroy(priv->class);
failed_class_create:
- cdev_del(&priv->argon_mem_cdev);
+ cdev_del(&priv->rpivid_mem_cdev);
err = PTR_ERR(ptr_err);
failed_cdev_add:
unregister_chrdev_region(priv->devid, 1);
@@ -210,18 +210,18 @@ static int argon_mem_probe(struct platform_device *pdev)
failed_get_resource:
kfree(priv);
failed_inst_alloc:
- dev_err(priv->dev, "could not load argon_mem");
+ dev_err(priv->dev, "could not load rpivid_mem");
return err;
}
-static int argon_mem_remove(struct platform_device *pdev)
+static int rpivid_mem_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct argon_mem_priv *priv = platform_get_drvdata(pdev);
+ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
device_destroy(priv->class, priv->devid);
class_destroy(priv->class);
- cdev_del(&priv->argon_mem_cdev);
+ cdev_del(&priv->rpivid_mem_cdev);
unregister_chrdev_region(priv->devid, 1);
kfree(priv);
@@ -229,49 +229,44 @@ static int argon_mem_remove(struct platform_device *pdev)
return 0;
}
-static const char argon_hevc_name[] = "argon-hevcmem";
-static const char argon_h264_name[] = "argon-h264mem";
-static const char argon_vp9_name[] = "argon-vp9mem";
-static const char argon_intc_name[] = "argon-intcmem";
-
-static const struct of_device_id argon_mem_of_match[] = {
+static const struct of_device_id rpivid_mem_of_match[] = {
{
- .compatible = "raspberrypi,argon-hevc-decoder",
- .data = &argon_hevc_name,
+ .compatible = "raspberrypi,rpivid-hevc-decoder",
+ .data = "rpivid-hevcmem",
},
{
- .compatible = "raspberrypi,argon-h264-decoder",
- .data = &argon_h264_name,
+ .compatible = "raspberrypi,rpivid-h264-decoder",
+ .data = "rpivid-h264mem",
},
{
- .compatible = "raspberrypi,argon-vp9-decoder",
- .data = &argon_vp9_name,
+ .compatible = "raspberrypi,rpivid-vp9-decoder",
+ .data = "rpivid-vp9mem",
},
/* The "intc" is included as this block of hardware contains the
* "frame done" status flags.
*/
{
- .compatible = "raspberrypi,argon-local-intc",
- .data = &argon_intc_name,
+ .compatible = "raspberrypi,rpivid-local-intc",
+ .data = "rpivid-intcmem",
},
{ /* sentinel */ },
};
-MODULE_DEVICE_TABLE(of, argon_mem_of_match);
+MODULE_DEVICE_TABLE(of, rpivid_mem_of_match);
-static struct platform_driver argon_mem_driver = {
- .probe = argon_mem_probe,
- .remove = argon_mem_remove,
+static struct platform_driver rpivid_mem_driver = {
+ .probe = rpivid_mem_probe,
+ .remove = rpivid_mem_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
- .of_match_table = argon_mem_of_match,
+ .of_match_table = rpivid_mem_of_match,
},
};
-module_platform_driver(argon_mem_driver);
+module_platform_driver(rpivid_mem_driver);
-MODULE_ALIAS("platform:argon-mem");
+MODULE_ALIAS("platform:rpivid-mem");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Driver for accessing Argon decoder registers from userspace");
+MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace");
MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.org>");
diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c
index ab1e9cbc50b1..f66f92fe28c3 100644
--- a/drivers/mfd/bcm2835-pm.c
+++ b/drivers/mfd/bcm2835-pm.c
@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
if (ret)
return ret;
- /* Map the ARGON ASB regs if present. */
+ /* Map the RPiVid ASB regs if present. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (res) {
- pm->arg_asb = devm_ioremap_resource(dev, res);
- if (IS_ERR(pm->arg_asb)) {
- dev_err(dev, "Failed to map ARGON ASB: %ld\n",
- PTR_ERR(pm->arg_asb));
- return PTR_ERR(pm->arg_asb);
+ pm->rpivid_asb = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pm->rpivid_asb)) {
+ dev_err(dev, "Failed to map RPiVid ASB: %ld\n",
+ PTR_ERR(pm->rpivid_asb));
+ return PTR_ERR(pm->rpivid_asb);
}
}
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
index 918cf54ab9ef..05d2293e8e58 100644
--- a/drivers/soc/bcm/bcm2835-power.c
+++ b/drivers/soc/bcm/bcm2835-power.c
@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct platform_device *pdev)
power->base = pm->base;
power->asb = pm->asb;
- /* 2711 hack: the new ARGON ASB took over V3D, which is our
+ /* 2711 hack: the new RPiVid ASB took over V3D, which is our
* only consumer of this driver so far. The old ASB seems to
* still be present with ISP and H264 bits but no V3D, but I
* don't know if that's real or not. The V3D is in the same
* place in the new ASB as the old one, so just poke the new
* one for now.
*/
- if (pm->arg_asb) {
- power->asb = pm->arg_asb;
+ if (pm->rpivid_asb) {
+ power->asb = pm->rpivid_asb;
power->is_2711 = true;
}
diff --git a/include/linux/mfd/bcm2835-pm.h b/include/linux/mfd/bcm2835-pm.h
index b2d157091e12..f70a810c55f7 100644
--- a/include/linux/mfd/bcm2835-pm.h
+++ b/include/linux/mfd/bcm2835-pm.h
@@ -9,7 +9,7 @@ struct bcm2835_pm {
struct device *dev;
void __iomem *base;
void __iomem *asb;
- void __iomem *arg_asb;
+ void __iomem *rpivid_asb;
};
#endif /* BCM2835_MFD_PM_H */
--
2.22.0

View file

@ -0,0 +1,76 @@
From 75f1d14cee8cfb1964cbda21a30cb030a632c3c2 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 29 Jul 2019 12:03:21 +0100
Subject: [PATCH 740/826] driver: char: rpivid - also support legacy name
Provide transitional support for the previous names of
the character devices.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/char/broadcom/rpivid-mem.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/char/broadcom/rpivid-mem.c b/drivers/char/broadcom/rpivid-mem.c
index fae84c7d3cf4..e4e5fb1fb820 100644
--- a/drivers/char/broadcom/rpivid-mem.c
+++ b/drivers/char/broadcom/rpivid-mem.c
@@ -66,7 +66,7 @@ static int rpivid_mem_open(struct inode *inode, struct file *file)
int dev = iminor(inode);
int ret = 0;
struct rpivid_mem_priv *priv;
- if (dev != DEVICE_MINOR)
+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
ret = -ENXIO;
priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
@@ -82,7 +82,7 @@ static int rpivid_mem_release(struct inode *inode, struct file *file)
int dev = iminor(inode);
int ret = 0;
- if (dev != DEVICE_MINOR)
+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
ret = -ENXIO;
return ret;
@@ -167,14 +167,14 @@ static int rpivid_mem_probe(struct platform_device *pdev)
/* Create character device entries */
err = alloc_chrdev_region(&priv->devid,
- DEVICE_MINOR, 1, priv->name);
+ DEVICE_MINOR, 2, priv->name);
if (err != 0) {
dev_err(priv->dev, "unable to allocate device number");
goto failed_alloc_chrdev;
}
cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
priv->rpivid_mem_cdev.owner = THIS_MODULE;
- err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 1);
+ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2);
if (err != 0) {
dev_err(priv->dev, "unable to register device");
goto failed_cdev_add;
@@ -194,6 +194,20 @@ static int rpivid_mem_probe(struct platform_device *pdev)
if (IS_ERR(ptr_err))
goto failed_device_create;
+ /* Legacy alias */
+ {
+ char *oldname = kstrdup(priv->name, GFP_KERNEL);
+
+ oldname[1] = 'a';
+ oldname[2] = 'r';
+ oldname[3] = 'g';
+ oldname[4] = 'o';
+ oldname[5] = 'n';
+ (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
+ oldname + 1);
+ kfree(oldname);
+ }
+
dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
priv->name, priv->regs_phys, priv->mem_window_len);
--
2.22.0

View file

@ -0,0 +1,70 @@
From dee43611031fb719b1472e14d9e90e176284d98c Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.org>
Date: Thu, 1 Aug 2019 16:41:20 +0100
Subject: [PATCH 741/826] hid: usb: Add device quirks for Freeway Airmouse T3
and MX3
These wireless mouse/keyboard combo remote control devices specify
multiple "wheel" events in their report descriptors. The wheel events
are incorrectly defined and apparently map to accelerometer data, leading
to spurious mouse scroll events being generated at an extreme rate when
the device is moved.
As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask
feeding the extra wheel events to the input subsystem.
See: https://github.com/raspberrypi/firmware/issues/1189
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
---
drivers/hid/hid-ids.h | 6 ++++++
drivers/hid/hid-quirks.c | 2 ++
2 files changed, 8 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index ab373a3942aa..4a643a60998f 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -222,6 +222,9 @@
#define USB_VENDOR_ID_BAANTO 0x2453
#define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
+#define USB_VENDOR_ID_BEKEN 0x25a7
+#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402
+
#define USB_VENDOR_ID_BELKIN 0x050d
#define USB_DEVICE_ID_FLIP_KVM 0x3201
@@ -1186,6 +1189,9 @@
#define USB_VENDOR_ID_XAT 0x2505
#define USB_DEVICE_ID_XAT_CSR 0x0220
+#define USB_VENDOR_ID_XENTA 0x1d57
+#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03
+
#define USB_VENDOR_ID_XIN_MO 0x16c0
#define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1
#define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 91e86af44a04..80b8c6ba8939 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -43,6 +43,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
@@ -171,6 +172,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ 0 }
};
--
2.22.0

View file

@ -0,0 +1,307 @@
From d7c5bc668cd07ccf3682e5a271375421bff915d0 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Fri, 14 Jun 2019 10:12:07 +0100
Subject: [PATCH 742/826] drm/vc4: Add "Broadcast RGB" connector property
Some HDMI monitors do not abide by the full or limited
(16-235) range RGB flags in the AVI infoframe. This can
result in images looking washed out (if given limited and
interpreting as full), or detail disappearing at the extremes
(given full and interpreting as limited).
Copy the Intel i915 driver's approach of adding an override
property ("Broadcast RGB") to force one mode or the other.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++--
1 file changed, 177 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
index bcbd2f709c7f..8e235e65d5a8 100644
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -285,6 +285,13 @@ to_vc4_fkms_encoder(struct drm_encoder *encoder)
return container_of(encoder, struct vc4_fkms_encoder, base);
}
+/* "Broadcast RGB" property.
+ * Allows overriding of HDMI full or limited range RGB
+ */
+#define VC4_BROADCAST_RGB_AUTO 0
+#define VC4_BROADCAST_RGB_FULL 1
+#define VC4_BROADCAST_RGB_LIMITED 2
+
/* VC4 FKMS connector KMS struct */
struct vc4_fkms_connector {
struct drm_connector base;
@@ -297,6 +304,8 @@ struct vc4_fkms_connector {
struct vc4_dev *vc4_dev;
u32 display_number;
u32 display_type;
+
+ struct drm_property *broadcast_rgb_property;
};
static inline struct vc4_fkms_connector *
@@ -305,6 +314,16 @@ to_vc4_fkms_connector(struct drm_connector *connector)
return container_of(connector, struct vc4_fkms_connector, base);
}
+/* VC4 FKMS connector state */
+struct vc4_fkms_connector_state {
+ struct drm_connector_state base;
+
+ int broadcast_rgb;
+};
+
+#define to_vc4_fkms_connector_state(x) \
+ container_of(x, struct vc4_fkms_connector_state, base)
+
static u32 vc4_get_display_type(u32 display_number)
{
const u32 display_types[] = {
@@ -832,8 +851,6 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
mode->picture_aspect_ratio, mode->flags);
mb.timings.display = vc4_crtc->display_number;
- mb.timings.video_id_code = frame.avi.video_code;
-
mb.timings.clock = mode->clock;
mb.timings.hdisplay = mode->hdisplay;
mb.timings.hsync_start = mode->hsync_start;
@@ -871,11 +888,30 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
break;
}
- if (!vc4_encoder->hdmi_monitor)
+ if (!vc4_encoder->hdmi_monitor) {
mb.timings.flags |= TIMINGS_FLAGS_DVI;
- else if (drm_default_rgb_quant_range(mode) ==
+ mb.timings.video_id_code = frame.avi.video_code;
+ } else {
+ struct vc4_fkms_connector_state *conn_state =
+ to_vc4_fkms_connector_state(vc4_crtc->connector->state);
+
+ /* Do not provide a VIC as the HDMI spec requires that we do not
+ * signal the opposite of the defined range in the AVI
+ * infoframe.
+ */
+ mb.timings.video_id_code = 0;
+
+ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
+ /* See CEA-861-E - 5.1 Default Encoding Parameters */
+ if (drm_default_rgb_quant_range(mode) ==
HDMI_QUANTIZATION_RANGE_LIMITED)
- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
+ } else {
+ if (conn_state->broadcast_rgb ==
+ VC4_BROADCAST_RGB_LIMITED)
+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
+ }
+ }
/*
FIXME: To implement
@@ -1340,13 +1376,95 @@ static void vc4_fkms_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
+/**
+ * vc4_connector_duplicate_state - duplicate connector state
+ * @connector: digital connector
+ *
+ * Allocates and returns a copy of the connector state (both common and
+ * digital connector specific) for the specified connector.
+ *
+ * Returns: The newly allocated connector state, or NULL on failure.
+ */
+struct drm_connector_state *
+vc4_connector_duplicate_state(struct drm_connector *connector)
+{
+ struct vc4_fkms_connector_state *state;
+
+ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
+ return &state->base;
+}
+
+/**
+ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
+ * @connector: Connector to get the property for.
+ * @state: Connector state to retrieve the property from.
+ * @property: Property to retrieve.
+ * @val: Return value for the property.
+ *
+ * Returns the atomic property value for a digital connector.
+ */
+int vc4_connector_atomic_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct vc4_fkms_connector *fkms_connector =
+ to_vc4_fkms_connector(connector);
+ struct vc4_fkms_connector_state *vc4_conn_state =
+ to_vc4_fkms_connector_state(state);
+
+ if (property == fkms_connector->broadcast_rgb_property) {
+ *val = vc4_conn_state->broadcast_rgb;
+ } else {
+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
+ property->base.id, property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
+ * @connector: Connector to set the property for.
+ * @state: Connector state to set the property on.
+ * @property: Property to set.
+ * @val: New value for the property.
+ *
+ * Sets the atomic property value for a digital connector.
+ */
+int vc4_connector_atomic_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct vc4_fkms_connector *fkms_connector =
+ to_vc4_fkms_connector(connector);
+ struct vc4_fkms_connector_state *vc4_conn_state =
+ to_vc4_fkms_connector_state(state);
+
+ if (property == fkms_connector->broadcast_rgb_property) {
+ vc4_conn_state->broadcast_rgb = val;
+ return 0;
+ }
+
+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
+ property->base.id, property->name);
+ return -EINVAL;
+}
+
static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
.detect = vc4_fkms_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = vc4_fkms_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_duplicate_state = vc4_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_get_property = vc4_connector_atomic_get_property,
+ .atomic_set_property = vc4_connector_atomic_set_property,
};
static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
@@ -1359,12 +1477,40 @@ static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs =
.best_encoder = vc4_fkms_connector_best_encoder,
};
+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
+ { VC4_BROADCAST_RGB_AUTO, "Automatic" },
+ { VC4_BROADCAST_RGB_FULL, "Full" },
+ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
+};
+
+static void
+vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
+{
+ struct drm_device *dev = fkms_connector->base.dev;
+ struct drm_property *prop;
+
+ prop = fkms_connector->broadcast_rgb_property;
+ if (!prop) {
+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
+ "Broadcast RGB",
+ broadcast_rgb_names,
+ ARRAY_SIZE(broadcast_rgb_names));
+ if (!prop)
+ return;
+
+ fkms_connector->broadcast_rgb_property = prop;
+ }
+
+ drm_object_attach_property(&fkms_connector->base.base, prop, 0);
+}
+
static struct drm_connector *
vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
u32 display_num)
{
struct drm_connector *connector = NULL;
struct vc4_fkms_connector *fkms_connector;
+ struct vc4_fkms_connector_state *conn_state = NULL;
struct vc4_dev *vc4_dev = to_vc4_dev(dev);
int ret = 0;
@@ -1373,9 +1519,18 @@ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
GFP_KERNEL);
if (!fkms_connector) {
- ret = -ENOMEM;
- goto fail;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * Allocate enough memory to hold vc4_fkms_connector_state,
+ */
+ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
+ if (!conn_state) {
+ kfree(fkms_connector);
+ return ERR_PTR(-ENOMEM);
}
+
connector = &fkms_connector->base;
fkms_connector->encoder = encoder;
@@ -1383,6 +1538,9 @@ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
fkms_connector->display_type = vc4_get_display_type(display_num);
fkms_connector->vc4_dev = vc4_dev;
+ __drm_atomic_helper_connector_reset(connector,
+ &conn_state->base);
+
if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
@@ -1403,10 +1561,14 @@ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
connector->interlace_allowed = 0;
}
- /* Create and attach TV margin props to this connector. */
- ret = drm_mode_create_tv_margin_properties(dev);
- if (ret)
- return ERR_PTR(ret);
+ /* Create and attach TV margin props to this connector.
+ * Already done for SDTV outputs.
+ */
+ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
+ ret = drm_mode_create_tv_margin_properties(dev);
+ if (ret)
+ goto fail;
+ }
drm_connector_attach_tv_margin_properties(connector);
@@ -1415,6 +1577,8 @@ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
connector->doublescan_allowed = 0;
+ vc4_attach_broadcast_rgb_property(fkms_connector);
+
drm_connector_attach_encoder(connector, encoder);
return connector;
--
2.22.0

View file

@ -0,0 +1,130 @@
From 1039d354cbdb917b4e532c45c65635ce7ae2a1c7 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:48 +0200
Subject: [PATCH 743/826] drm/connector: Add documentation for drm_cmdline_mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit 772cd52c5574b04b00a97d638b2cfe94c0c1a9b6 upstream.
The struct drm_cmdline_mode holds the result of the command line parsers.
However, it wasn't documented so far, so let's do that.
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/963c893c16c6a25fc469b53c726f493d99bdc578.1560783090.git-series.maxime.ripard@bootlin.com
---
include/drm/drm_connector.h | 86 ++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 2 deletions(-)
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 342a4db4b0c1..83ed80edb083 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -755,18 +755,100 @@ struct drm_connector_funcs {
const struct drm_connector_state *state);
};
-/* mode specified on the command line */
+/**
+ * struct drm_cmdline_mode - DRM Mode passed through the kernel command-line
+ *
+ * Each connector can have an initial mode with additional options
+ * passed through the kernel command line. This structure allows to
+ * express those parameters and will be filled by the command-line
+ * parser.
+ */
struct drm_cmdline_mode {
+ /**
+ * @specified:
+ *
+ * Has a mode been read from the command-line?
+ */
bool specified;
+
+ /**
+ * @refresh_specified:
+ *
+ * Did the mode have a preferred refresh rate?
+ */
bool refresh_specified;
+
+ /**
+ * @bpp_specified:
+ *
+ * Did the mode have a preferred BPP?
+ */
bool bpp_specified;
- int xres, yres;
+
+ /**
+ * @xres:
+ *
+ * Active resolution on the X axis, in pixels.
+ */
+ int xres;
+
+ /**
+ * @yres:
+ *
+ * Active resolution on the Y axis, in pixels.
+ */
+ int yres;
+
+ /**
+ * @bpp:
+ *
+ * Bits per pixels for the mode.
+ */
int bpp;
+
+ /**
+ * @refresh:
+ *
+ * Refresh rate, in Hertz.
+ */
int refresh;
+
+ /**
+ * @rb:
+ *
+ * Do we need to use reduced blanking?
+ */
bool rb;
+
+ /**
+ * @interlace:
+ *
+ * The mode is interlaced.
+ */
bool interlace;
+
+ /**
+ * @cvt:
+ *
+ * The timings will be calculated using the VESA Coordinated
+ * Video Timings instead of looking up the mode from a table.
+ */
bool cvt;
+
+ /**
+ * @margins:
+ *
+ * Add margins to the mode calculation (1.8% of xres rounded
+ * down to 8 pixels and 1.8% of yres).
+ */
bool margins;
+
+ /**
+ * @force:
+ *
+ * Ignore the hotplug state of the connector, and force its
+ * state to one of the DRM_FORCE_* values.
+ */
enum drm_connector_force force;
};
--
2.22.0

View file

@ -0,0 +1,396 @@
From 402f0b03a46f4dcaf83e89cfca8edfa9057831e1 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:49 +0200
Subject: [PATCH 744/826] drm/modes: Rewrite the command line parser
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit e08ab74bd4c7a5fe311bc05f32dbb4f1e7fa3428 upstream.
Rewrite the command line parser in order to get away from the state machine
parsing the video mode lines.
Hopefully, this will allow to extend it more easily to support named modes
and / or properties set directly on the command line.
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/e32cd4009153b184103554009135c7bf7c9975d7.1560783090.git-series.maxime.ripard@bootlin.com
---
drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++-------------
1 file changed, 210 insertions(+), 115 deletions(-)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index a3104d79b48f..faae19afa686 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -30,6 +30,7 @@
* authorization from the copyright holder(s) and author(s).
*/
+#include <linux/ctype.h>
#include <linux/list.h>
#include <linux/list_sort.h>
#include <linux/export.h>
@@ -1414,6 +1415,151 @@ void drm_connector_list_update(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_connector_list_update);
+static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
+ struct drm_cmdline_mode *mode)
+{
+ unsigned int bpp;
+
+ if (str[0] != '-')
+ return -EINVAL;
+
+ str++;
+ bpp = simple_strtol(str, end_ptr, 10);
+ if (*end_ptr == str)
+ return -EINVAL;
+
+ mode->bpp = bpp;
+ mode->bpp_specified = true;
+
+ return 0;
+}
+
+static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
+ struct drm_cmdline_mode *mode)
+{
+ unsigned int refresh;
+
+ if (str[0] != '@')
+ return -EINVAL;
+
+ str++;
+ refresh = simple_strtol(str, end_ptr, 10);
+ if (*end_ptr == str)
+ return -EINVAL;
+
+ mode->refresh = refresh;
+ mode->refresh_specified = true;
+
+ return 0;
+}
+
+static int drm_mode_parse_cmdline_extra(const char *str, int length,
+ struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ switch (str[i]) {
+ case 'i':
+ mode->interlace = true;
+ break;
+ case 'm':
+ mode->margins = true;
+ break;
+ case 'D':
+ if (mode->force != DRM_FORCE_UNSPECIFIED)
+ return -EINVAL;
+
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+ mode->force = DRM_FORCE_ON;
+ else
+ mode->force = DRM_FORCE_ON_DIGITAL;
+ break;
+ case 'd':
+ if (mode->force != DRM_FORCE_UNSPECIFIED)
+ return -EINVAL;
+
+ mode->force = DRM_FORCE_OFF;
+ break;
+ case 'e':
+ if (mode->force != DRM_FORCE_UNSPECIFIED)
+ return -EINVAL;
+
+ mode->force = DRM_FORCE_ON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
+ bool extras,
+ struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+{
+ const char *str_start = str;
+ bool rb = false, cvt = false;
+ int xres = 0, yres = 0;
+ int remaining, i;
+ char *end_ptr;
+
+ xres = simple_strtol(str, &end_ptr, 10);
+ if (end_ptr == str)
+ return -EINVAL;
+
+ if (end_ptr[0] != 'x')
+ return -EINVAL;
+ end_ptr++;
+
+ str = end_ptr;
+ yres = simple_strtol(str, &end_ptr, 10);
+ if (end_ptr == str)
+ return -EINVAL;
+
+ remaining = length - (end_ptr - str_start);
+ if (remaining < 0)
+ return -EINVAL;
+
+ for (i = 0; i < remaining; i++) {
+ switch (end_ptr[i]) {
+ case 'M':
+ cvt = true;
+ break;
+ case 'R':
+ rb = true;
+ break;
+ default:
+ /*
+ * Try to pass that to our extras parsing
+ * function to handle the case where the
+ * extras are directly after the resolution
+ */
+ if (extras) {
+ int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
+ 1,
+ connector,
+ mode);
+ if (ret)
+ return ret;
+ } else {
+ return -EINVAL;
+ }
+ }
+ }
+
+ mode->xres = xres;
+ mode->yres = yres;
+ mode->cvt = cvt;
+ mode->rb = rb;
+
+ return 0;
+}
+
/**
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector
* @mode_option: optional per connector mode option
@@ -1440,13 +1586,12 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
struct drm_cmdline_mode *mode)
{
const char *name;
- unsigned int namelen;
- bool res_specified = false, bpp_specified = false, refresh_specified = false;
- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
- bool yres_specified = false, cvt = false, rb = false;
- bool interlace = false, margins = false, was_digit = false;
- int i;
- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+ bool parse_extras = false;
+ unsigned int bpp_off = 0, refresh_off = 0;
+ unsigned int mode_end = 0;
+ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+ int ret;
#ifdef CONFIG_FB
if (!mode_option)
@@ -1459,127 +1604,77 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
}
name = mode_option;
- namelen = strlen(name);
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '@':
- if (!refresh_specified && !bpp_specified &&
- !yres_specified && !cvt && !rb && was_digit) {
- refresh = simple_strtol(&name[i+1], NULL, 10);
- refresh_specified = true;
- was_digit = false;
- } else
- goto done;
- break;
- case '-':
- if (!bpp_specified && !yres_specified && !cvt &&
- !rb && was_digit) {
- bpp = simple_strtol(&name[i+1], NULL, 10);
- bpp_specified = true;
- was_digit = false;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified && was_digit) {
- yres = simple_strtol(&name[i+1], NULL, 10);
- yres_specified = true;
- was_digit = false;
- } else
- goto done;
- break;
- case '0' ... '9':
- was_digit = true;
- break;
- case 'M':
- if (yres_specified || cvt || was_digit)
- goto done;
- cvt = true;
- break;
- case 'R':
- if (yres_specified || cvt || rb || was_digit)
- goto done;
- rb = true;
- break;
- case 'm':
- if (cvt || yres_specified || was_digit)
- goto done;
- margins = true;
- break;
- case 'i':
- if (cvt || yres_specified || was_digit)
- goto done;
- interlace = true;
- break;
- case 'e':
- if (yres_specified || bpp_specified || refresh_specified ||
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
- goto done;
- force = DRM_FORCE_ON;
- break;
- case 'D':
- if (yres_specified || bpp_specified || refresh_specified ||
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
- goto done;
+ if (!isdigit(name[0]))
+ return false;
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
- force = DRM_FORCE_ON;
- else
- force = DRM_FORCE_ON_DIGITAL;
- break;
- case 'd':
- if (yres_specified || bpp_specified || refresh_specified ||
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
- goto done;
+ /* Try to locate the bpp and refresh specifiers, if any */
+ bpp_ptr = strchr(name, '-');
+ if (bpp_ptr) {
+ bpp_off = bpp_ptr - name;
+ mode->bpp_specified = true;
+ }
- force = DRM_FORCE_OFF;
- break;
- default:
- goto done;
- }
+ refresh_ptr = strchr(name, '@');
+ if (refresh_ptr) {
+ refresh_off = refresh_ptr - name;
+ mode->refresh_specified = true;
}
- if (i < 0 && yres_specified) {
- char *ch;
- xres = simple_strtol(name, &ch, 10);
- if ((ch != NULL) && (*ch == 'x'))
- res_specified = true;
- else
- i = ch - name;
- } else if (!yres_specified && was_digit) {
- /* catch mode that begins with digits but has no 'x' */
- i = 0;
+ /* Locate the end of the name / resolution, and parse it */
+ if (bpp_ptr && refresh_ptr) {
+ mode_end = min(bpp_off, refresh_off);
+ } else if (bpp_ptr) {
+ mode_end = bpp_off;
+ } else if (refresh_ptr) {
+ mode_end = refresh_off;
+ } else {
+ mode_end = strlen(name);
+ parse_extras = true;
}
-done:
- if (i >= 0) {
- pr_warn("[drm] parse error at position %i in video mode '%s'\n",
- i, name);
- mode->specified = false;
+
+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+ parse_extras,
+ connector,
+ mode);
+ if (ret)
return false;
- }
+ mode->specified = true;
- if (res_specified) {
- mode->specified = true;
- mode->xres = xres;
- mode->yres = yres;
+ if (bpp_ptr) {
+ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
+ if (ret)
+ return false;
}
- if (refresh_specified) {
- mode->refresh_specified = true;
- mode->refresh = refresh;
+ if (refresh_ptr) {
+ ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
+ &refresh_end_ptr, mode);
+ if (ret)
+ return false;
}
- if (bpp_specified) {
- mode->bpp_specified = true;
- mode->bpp = bpp;
+ /*
+ * Locate the end of the bpp / refresh, and parse the extras
+ * if relevant
+ */
+ if (bpp_ptr && refresh_ptr)
+ extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
+ else if (bpp_ptr)
+ extra_ptr = bpp_end_ptr;
+ else if (refresh_ptr)
+ extra_ptr = refresh_end_ptr;
+
+ if (extra_ptr) {
+ int remaining = strlen(name) - (extra_ptr - name);
+
+ /*
+ * We still have characters to process, while
+ * we shouldn't have any
+ */
+ if (remaining > 0)
+ return false;
}
- mode->rb = rb;
- mode->cvt = cvt;
- mode->interlace = interlace;
- mode->margins = margins;
- mode->force = force;
return true;
}
--
2.22.0

View file

@ -0,0 +1,185 @@
From 5329799326fa5bab28d5cbc9c8bb045478f24ba2 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:50 +0200
Subject: [PATCH 745/826] drm/modes: Support modes names on the command line
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit 3aeeb13d899627fe2b86bdbdcd0927cf7192234f upstream.
Minor conflict resolution as upstream has moved functions
from drm_fb_helper.c to a new drm_client_modeset.c
The drm subsystem also uses the video= kernel parameter, and in the
documentation refers to the fbdev documentation for that parameter.
However, that documentation also says that instead of giving the mode using
its resolution we can also give a name. However, DRM doesn't handle that
case at the moment. Even though in most case it shouldn't make any
difference, it might be useful for analog modes, where different standards
might have the same resolution, but still have a few different parameters
that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/18443e0c3bdbbd16cea4ec63bc7f2079b820b43b.1560783090.git-series.maxime.ripard@bootlin.com
---
drivers/gpu/drm/drm_connector.c | 3 +-
drivers/gpu/drm/drm_fb_helper.c | 4 +++
drivers/gpu/drm/drm_modes.c | 62 ++++++++++++++++++++++++---------
include/drm/drm_connector.h | 7 ++++
4 files changed, 59 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index bbc3f3ed47a8..ff0996f49b21 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -135,8 +135,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
connector->force = mode->force;
}
- DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+ DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
connector->name,
+ mode->name ? mode->name : "",
mode->xres, mode->yres,
mode->refresh_specified ? mode->refresh : 60,
mode->rb ? " reduced blanking" : "",
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 8b546fde139d..c8a8e0d7212d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2099,6 +2099,10 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
prefer_non_interlace = !cmdline_mode->interlace;
again:
list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+ /* Check (optional) mode name first */
+ if (!strcmp(mode->name, cmdline_mode->name))
+ return mode;
+
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
mode->vdisplay != cmdline_mode->yres)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index faae19afa686..c6ce1d526b10 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1586,7 +1586,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
struct drm_cmdline_mode *mode)
{
const char *name;
- bool parse_extras = false;
+ bool named_mode = false, parse_extras = false;
unsigned int bpp_off = 0, refresh_off = 0;
unsigned int mode_end = 0;
char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
@@ -1605,8 +1605,22 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
name = mode_option;
- if (!isdigit(name[0]))
- return false;
+ /*
+ * This is a bit convoluted. To differentiate between the
+ * named modes and poorly formatted resolutions, we need a
+ * bunch of things:
+ * - We need to make sure that the first character (which
+ * would be our resolution in X) is a digit.
+ * - However, if the X resolution is missing, then we end up
+ * with something like x<yres>, with our first character
+ * being an alpha-numerical character, which would be
+ * considered a named mode.
+ *
+ * If this isn't enough, we should add more heuristics here,
+ * and matching unit-tests.
+ */
+ if (!isdigit(name[0]) && name[0] != 'x')
+ named_mode = true;
/* Try to locate the bpp and refresh specifiers, if any */
bpp_ptr = strchr(name, '-');
@@ -1617,6 +1631,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
refresh_ptr = strchr(name, '@');
if (refresh_ptr) {
+ if (named_mode)
+ return false;
+
refresh_off = refresh_ptr - name;
mode->refresh_specified = true;
}
@@ -1633,12 +1650,16 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
parse_extras = true;
}
- ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
- parse_extras,
- connector,
- mode);
- if (ret)
- return false;
+ if (named_mode) {
+ strncpy(mode->name, name, mode_end);
+ } else {
+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+ parse_extras,
+ connector,
+ mode);
+ if (ret)
+ return false;
+ }
mode->specified = true;
if (bpp_ptr) {
@@ -1666,14 +1687,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
extra_ptr = refresh_end_ptr;
if (extra_ptr) {
- int remaining = strlen(name) - (extra_ptr - name);
+ if (!named_mode) {
+ int len = strlen(name) - (extra_ptr - name);
- /*
- * We still have characters to process, while
- * we shouldn't have any
- */
- if (remaining > 0)
- return false;
+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+ connector, mode);
+ if (ret)
+ return false;
+ } else {
+ int remaining = strlen(name) - (extra_ptr - name);
+
+ /*
+ * We still have characters to process, while
+ * we shouldn't have any
+ */
+ if (remaining > 0)
+ return false;
+ }
}
return true;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 83ed80edb083..9ffd8e931ee0 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -764,6 +764,13 @@ struct drm_connector_funcs {
* parser.
*/
struct drm_cmdline_mode {
+ /**
+ * @name:
+ *
+ * Name of the mode.
+ */
+ char name[DRM_DISPLAY_MODE_LEN];
+
/**
* @specified:
*
--
2.22.0

View file

@ -0,0 +1,287 @@
From 119273663afb44806748f42af20333ce8b6cfa08 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:51 +0200
Subject: [PATCH 746/826] drm/modes: Allow to specify rotation and reflection
on the commandline
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit 1bf4e09227c345e246062285eba4b8fe660e512e upstream.
Minor conflict resolution as upstream has moved functions
from drm_fb_helper.c to a new drm_client_modeset.c
Rotations and reflections setup are needed in some scenarios to initialise
properly the initial framebuffer. Some drivers already had a bunch of
quirks to deal with this, such as either a private kernel command line
parameter (omapdss) or on the device tree (various panels).
In order to accomodate this, let's create a video mode parameter to deal
with the rotation and reflexion.
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/777da16e42db757c1f5b414b5ca34507097fed5c.1560783090.git-series.maxime.ripard@bootlin.com
---
Documentation/fb/modedb.txt | 12 ++++
drivers/gpu/drm/drm_fb_helper.c | 30 +++++++++
drivers/gpu/drm/drm_modes.c | 114 ++++++++++++++++++++++++++------
include/drm/drm_connector.h | 10 +++
4 files changed, 146 insertions(+), 20 deletions(-)
diff --git a/Documentation/fb/modedb.txt b/Documentation/fb/modedb.txt
index 16aa08453911..52418c6dbfc4 100644
--- a/Documentation/fb/modedb.txt
+++ b/Documentation/fb/modedb.txt
@@ -51,6 +51,18 @@ To force the VGA output to be enabled and drive a specific mode say:
Specifying the option multiple times for different ports is possible, e.g.:
video=LVDS-1:d video=HDMI-1:D
+Options can also be passed after the mode, using commas as separator.
+
+ Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
+
+Valid options are:
+
+ - reflect_x (boolean): Perform an axial symmetry on the X axis
+ - reflect_y (boolean): Perform an axial symmetry on the Y axis
+ - rotate (integer): Rotate the initial framebuffer by x
+ degrees. Valid values are 0, 90, 180 and 270.
+
+
***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
What is the VESA(TM) Coordinated Video Timings (CVT)?
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index c8a8e0d7212d..cfa272fab56a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2464,6 +2464,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
struct drm_connector *connector)
{
struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
+ struct drm_cmdline_mode *cmdline;
uint64_t valid_mask = 0;
int i, rotation;
@@ -2483,6 +2484,35 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
rotation = DRM_MODE_ROTATE_0;
}
+ /**
+ * The panel already defined the default rotation
+ * through its orientation. Whatever has been provided
+ * on the command line needs to be added to that.
+ *
+ * Unfortunately, the rotations are at different bit
+ * indices, so the math to add them up are not as
+ * trivial as they could.
+ *
+ * Reflections on the other hand are pretty trivial to deal with, a
+ * simple XOR between the two handle the addition nicely.
+ */
+ cmdline = &connector->cmdline_mode;
+ if (cmdline->specified) {
+ unsigned int cmdline_rest, panel_rest;
+ unsigned int cmdline_rot, panel_rot;
+ unsigned int sum_rot, sum_rest;
+
+ panel_rot = ilog2(rotation & DRM_MODE_ROTATE_MASK);
+ cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
+ sum_rot = (panel_rot + cmdline_rot) % 4;
+
+ panel_rest = rotation & ~DRM_MODE_ROTATE_MASK;
+ cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
+ sum_rest = panel_rest ^ cmdline_rest;
+
+ rotation = (1 << sum_rot) | sum_rest;
+ }
+
/*
* TODO: support 90 / 270 degree hardware rotation,
* depending on the hardware this may require the framebuffer
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index c6ce1d526b10..b5eed64d7349 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1560,6 +1560,71 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
return 0;
}
+static int drm_mode_parse_cmdline_options(char *str, size_t len,
+ struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+{
+ unsigned int rotation = 0;
+ char *sep = str;
+
+ while ((sep = strchr(sep, ','))) {
+ char *delim, *option;
+
+ option = sep + 1;
+ delim = strchr(option, '=');
+ if (!delim) {
+ delim = strchr(option, ',');
+
+ if (!delim)
+ delim = str + len;
+ }
+
+ if (!strncmp(option, "rotate", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int deg;
+
+ deg = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ switch (deg) {
+ case 0:
+ rotation |= DRM_MODE_ROTATE_0;
+ break;
+
+ case 90:
+ rotation |= DRM_MODE_ROTATE_90;
+ break;
+
+ case 180:
+ rotation |= DRM_MODE_ROTATE_180;
+ break;
+
+ case 270:
+ rotation |= DRM_MODE_ROTATE_270;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ } else if (!strncmp(option, "reflect_x", delim - option)) {
+ rotation |= DRM_MODE_REFLECT_X;
+ sep = delim;
+ } else if (!strncmp(option, "reflect_y", delim - option)) {
+ rotation |= DRM_MODE_REFLECT_Y;
+ sep = delim;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ mode->rotation_reflection = rotation;
+
+ return 0;
+}
+
/**
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector
* @mode_option: optional per connector mode option
@@ -1575,6 +1640,10 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
*
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
*
+ * Additionals options can be provided following the mode, using a comma to
+ * separate each option. Valid options can be found in
+ * Documentation/fb/modedb.txt.
+ *
* The intermediate drm_cmdline_mode structure is required to store additional
* options from the command line modline like the force-enable/disable flag.
*
@@ -1587,9 +1656,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
{
const char *name;
bool named_mode = false, parse_extras = false;
- unsigned int bpp_off = 0, refresh_off = 0;
+ unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
unsigned int mode_end = 0;
char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+ char *options_ptr = NULL;
char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
int ret;
@@ -1638,13 +1708,18 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
mode->refresh_specified = true;
}
+ /* Locate the start of named options */
+ options_ptr = strchr(name, ',');
+ if (options_ptr)
+ options_off = options_ptr - name;
+
/* Locate the end of the name / resolution, and parse it */
- if (bpp_ptr && refresh_ptr) {
- mode_end = min(bpp_off, refresh_off);
- } else if (bpp_ptr) {
+ if (bpp_ptr) {
mode_end = bpp_off;
} else if (refresh_ptr) {
mode_end = refresh_off;
+ } else if (options_ptr) {
+ mode_end = options_off;
} else {
mode_end = strlen(name);
parse_extras = true;
@@ -1686,24 +1761,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
else if (refresh_ptr)
extra_ptr = refresh_end_ptr;
- if (extra_ptr) {
- if (!named_mode) {
- int len = strlen(name) - (extra_ptr - name);
+ if (extra_ptr &&
+ extra_ptr != options_ptr) {
+ int len = strlen(name) - (extra_ptr - name);
- ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
- connector, mode);
- if (ret)
- return false;
- } else {
- int remaining = strlen(name) - (extra_ptr - name);
+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+ connector, mode);
+ if (ret)
+ return false;
+ }
- /*
- * We still have characters to process, while
- * we shouldn't have any
- */
- if (remaining > 0)
- return false;
- }
+ if (options_ptr) {
+ int len = strlen(name) - (options_ptr - name);
+
+ ret = drm_mode_parse_cmdline_options(options_ptr, len,
+ connector, mode);
+ if (ret)
+ return false;
}
return true;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 9ffd8e931ee0..37e9bae30224 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -857,6 +857,16 @@ struct drm_cmdline_mode {
* state to one of the DRM_FORCE_* values.
*/
enum drm_connector_force force;
+
+ /**
+ * @rotation_reflection:
+ *
+ * Initial rotation and reflection of the mode setup from the
+ * command line. See DRM_MODE_ROTATE_* and
+ * DRM_MODE_REFLECT_*. The only rotations supported are
+ * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
+ */
+ unsigned int rotation_reflection;
};
/**
--
2.22.0

View file

@ -0,0 +1,87 @@
From e5f25780cd3af08542c64fbdbe4d266b6e355b7d Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:51 +0200
Subject: [PATCH 747/826] drm/connector: Introduce a TV margins structure
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit 22045e8e52bd802f743f0471242782fc3b479707 upstream.
The TV margins has been defined as a structure inside the
drm_connector_state structure so far. However, we will need it in other
structures as well, so let's move that structure definition so that it can
be reused.
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/38b773b03f15ec7a135cdf8f7db669e5ada20cf2.1560783090.git-series.maxime.ripard@bootlin.com
---
include/drm/drm_connector.h | 41 +++++++++++++++++++++++++++----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 37e9bae30224..7789fbf785e9 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -343,14 +343,38 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
const u32 *formats,
unsigned int num_formats);
+/**
+ * struct drm_connector_tv_margins - TV connector related margins
+ *
+ * Describes the margins in pixels to put around the image on TV
+ * connectors to deal with overscan.
+ */
+struct drm_connector_tv_margins {
+ /**
+ * @bottom: Bottom margin in pixels.
+ */
+ unsigned int bottom;
+
+ /**
+ * @left: Left margin in pixels.
+ */
+ unsigned int left;
+
+ /**
+ * @right: Right margin in pixels.
+ */
+ unsigned int right;
+
+ /**
+ * @top: Top margin in pixels.
+ */
+ unsigned int top;
+};
+
/**
* struct drm_tv_connector_state - TV connector related states
* @subconnector: selected subconnector
- * @margins: margins (all margins are expressed in pixels)
- * @margins.left: left margin
- * @margins.right: right margin
- * @margins.top: top margin
- * @margins.bottom: bottom margin
+ * @margins: TV margins
* @mode: TV mode
* @brightness: brightness in percent
* @contrast: contrast in percent
@@ -361,12 +385,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
*/
struct drm_tv_connector_state {
enum drm_mode_subconnector subconnector;
- struct {
- unsigned int left;
- unsigned int right;
- unsigned int top;
- unsigned int bottom;
- } margins;
+ struct drm_connector_tv_margins margins;
unsigned int mode;
unsigned int brightness;
unsigned int contrast;
--
2.22.0

View file

@ -0,0 +1,111 @@
From 43e6a2a4ce7bf5fc75a4dcad706cca33db8d7e7e Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:51 +0200
Subject: [PATCH 748/826] drm/modes: Parse overscan properties
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit 3d46a3007cd8f73bae502bf5c171977b91d7aacc upstream.
Properly configuring the overscan properties might be needed for the
initial setup of the framebuffer for display that still have overscan.
Let's allow for more properties on the kernel command line to setup each
margin.
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/e481f1628e3768ca49226ec2115cfa4dfcbd5e4c.1560783090.git-series.maxime.ripard@bootlin.com
---
Documentation/fb/modedb.txt | 2 ++
drivers/gpu/drm/drm_modes.c | 44 +++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 5 +++++
3 files changed, 51 insertions(+)
diff --git a/Documentation/fb/modedb.txt b/Documentation/fb/modedb.txt
index 52418c6dbfc4..1dd5a52f9390 100644
--- a/Documentation/fb/modedb.txt
+++ b/Documentation/fb/modedb.txt
@@ -57,6 +57,8 @@ Options can also be passed after the mode, using commas as separator.
Valid options are:
+ - margin_top, margin_bottom, margin_left, margin_right (integer):
+ Number of pixels in the margins, typically to deal with overscan on TVs
- reflect_x (boolean): Perform an axial symmetry on the X axis
- reflect_y (boolean): Perform an axial symmetry on the Y axis
- rotate (integer): Rotate the initial framebuffer by x
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index b5eed64d7349..243de91ee9ee 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1615,6 +1615,50 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
} else if (!strncmp(option, "reflect_y", delim - option)) {
rotation |= DRM_MODE_REFLECT_Y;
sep = delim;
+ } else if (!strncmp(option, "margin_right", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->tv_margins.right = margin;
+ } else if (!strncmp(option, "margin_left", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->tv_margins.left = margin;
+ } else if (!strncmp(option, "margin_top", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->tv_margins.top = margin;
+ } else if (!strncmp(option, "margin_bottom", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->tv_margins.bottom = margin;
} else {
return -EINVAL;
}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 7789fbf785e9..6712a934c051 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -886,6 +886,11 @@ struct drm_cmdline_mode {
* DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
*/
unsigned int rotation_reflection;
+
+ /**
+ * @tv_margins: TV margins to apply to the mode.
+ */
+ struct drm_connector_tv_margins tv_margins;
};
/**
--
2.22.0

View file

@ -0,0 +1,70 @@
From c26132f177c3417531b80d1c3984c10a48e513e6 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:52 +0200
Subject: [PATCH 749/826] drm/atomic: Add a function to reset connector TV
properties
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit 731514b446fe6748d5a55a3dff202efb45c7d8df upstream.
Reworked as functions have been moved from drm_atomic_helper.[c|h]
to drm_atomic_state_helper.[c|h].
During the connector reset, if that connector has a TV property, it needs
to be reset to the value provided on the command line.
Provide a helper to do that.
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/84a7b657f09303a2850e1cc79e68f623547f3fdd.1560783090.git-series.maxime.ripard@bootlin.com
---
drivers/gpu/drm/drm_atomic_helper.c | 18 ++++++++++++++++++
include/drm/drm_atomic_helper.h | 1 +
2 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index c22062cc9992..2f416b283ef8 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3736,6 +3736,24 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
+/**
+ * drm_atomic_helper_connector_tv_reset - Resets TV connector properties
+ * @connector: DRM connector
+ *
+ * Resets the TV-related properties attached to a connector.
+ */
+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
+{
+ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+ struct drm_connector_state *state = connector->state;
+
+ state->tv.margins.left = cmdline->tv_margins.left;
+ state->tv.margins.right = cmdline->tv_margins.right;
+ state->tv.margins.top = cmdline->tv_margins.top;
+ state->tv.margins.bottom = cmdline->tv_margins.bottom;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
+
/**
* __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
* @connector: connector object
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 99e2a5297c69..f88752489d0c 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -168,6 +168,7 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state);
void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
void
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
struct drm_connector_state *state);
--
2.22.0

View file

@ -0,0 +1,46 @@
From d217f5cdcef652124a39e318cde98bfdfa677a74 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@bootlin.com>
Date: Wed, 19 Jun 2019 12:17:53 +0200
Subject: [PATCH 750/826] drm/vc4: hdmi: Set default state margin at reset
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Now that the TV margins are properly parsed and filled into
drm_cmdline_mode, we just need to initialise the first state at reset to
get those values and start using them.
Acked-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/44e24172e300be6a41578517021ef6a6e90ed682.1560783090.git-series.maxime.ripard@bootlin.com
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index be80769d7b5b..9dc0fc6b8a2a 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -292,11 +292,17 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
return ret;
}
+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
+{
+ drm_atomic_helper_connector_reset(connector);
+ drm_atomic_helper_connector_tv_reset(connector);
+}
+
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
.detect = vc4_hdmi_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = vc4_hdmi_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
+ .reset = vc4_hdmi_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
--
2.22.0

View file

@ -0,0 +1,39 @@
From 884c11bacd3baf9da45f540ec4ad17ea49accfb1 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Tue, 23 Jul 2019 11:09:26 +0100
Subject: [PATCH 751/826] drm/vc4: fkms: Set default state margin at reset
Now that the TV margins are properly parsed and filled into
drm_cmdline_mode, we just need to initialise the first state at reset to
get those values and start using them.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
index 8e235e65d5a8..066f6d17db97 100644
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -1457,10 +1457,17 @@ int vc4_connector_atomic_set_property(struct drm_connector *connector,
return -EINVAL;
}
+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
+{
+ drm_atomic_helper_connector_reset(connector);
+ drm_atomic_helper_connector_tv_reset(connector);
+}
+
static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
.detect = vc4_fkms_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = vc4_fkms_connector_destroy,
+ .reset = vc4_hdmi_connector_reset,
.atomic_duplicate_state = vc4_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_get_property = vc4_connector_atomic_get_property,
--
2.22.0

View file

@ -0,0 +1,39 @@
From bb0b99b86606be0ef3f7426ed3eb7d09deba3514 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Tue, 23 Jul 2019 14:10:31 +0100
Subject: [PATCH 752/826] drm/modes: Don't apply cmdline's rotation if it
wasn't specified
Taken from the dri-devel mailing list (11/7/2019) to fixup the cmdline
parsing, but requires changes as things have moved between 4.19 and 5.2.
From: Dmitry Osipenko <digetx@gmail.com>
The rotation mode from cmdline shouldn't be taken into account if it
wasn't specified in the cmdline. This fixes ignored default display
orientation when display mode is given using cmdline without the
rotation being specified.
Fixes: 1bf4e09227c3 ("drm/modes: Allow to specify rotation and reflection on the commandline")
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/gpu/drm/drm_fb_helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index cfa272fab56a..a0b217f93a0d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2497,7 +2497,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
* simple XOR between the two handle the addition nicely.
*/
cmdline = &connector->cmdline_mode;
- if (cmdline->specified) {
+ if (cmdline->specified && cmdline->rotation_reflection) {
unsigned int cmdline_rest, panel_rest;
unsigned int cmdline_rot, panel_rot;
unsigned int sum_rot, sum_rest;
--
2.22.0

View file

@ -0,0 +1,355 @@
From 5e484a3e2a1118e66ec39a007ac5a9f83fe20114 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@csie.org>
Date: Thu, 18 Jul 2019 17:07:05 +0800
Subject: [PATCH 754/826] staging: bcm2835-codec: switch to multi-planar API
There are two APIs for mem2mem devices, the older single-planar API and
the newer multi-planar one. Without making things overly complex, the
driver can only support one or the other. However the userspace libv4l2
library has a plugin that allows multi-planar API devices to service
single-planar consumers.
Chromium supports the multi-planar API exclusively, though this is
currently limited to ChromiumOS. It would be possible to add support
for generic Linux.
Switching to the multi-planar API would allow usage of both APIs from
userspace.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
.../bcm2835-codec/bcm2835-v4l2-codec.c | 145 +++++++++---------
1 file changed, 76 insertions(+), 69 deletions(-)
diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
index 708f76b7aa92..43b903cd5391 100644
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
for (k = 0; k < fmts->num_entries; k++) {
fmt = &fmts->list[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
break;
}
if (k == fmts->num_entries)
@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx,
enum v4l2_buf_type type)
{
switch (type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return &ctx->q_data[V4L2_M2M_SRC];
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return &ctx->q_data[V4L2_M2M_DST];
default:
v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx,
return NULL;
switch (type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return &ctx->component->input[0];
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return &ctx->component->output[0];
default:
v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
format->es.video.crop.width, format->es.video.crop.height,
format->es.video.color_space);
- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
q_data->crop_width = format->es.video.crop.width;
q_data->crop_height = format->es.video.crop.height;
q_data->bytesperline = format->es.video.crop.width;
@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *file, void *priv,
strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
MEM2MEM_NAME);
- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
q_data = get_q_data(ctx, f->type);
- f->fmt.pix.width = q_data->crop_width;
- f->fmt.pix.height = q_data->height;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.pixelformat = q_data->fmt->fourcc;
- f->fmt.pix.bytesperline = q_data->bytesperline;
- f->fmt.pix.sizeimage = q_data->sizeimage;
- f->fmt.pix.colorspace = ctx->colorspace;
- f->fmt.pix.xfer_func = ctx->xfer_func;
- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
- f->fmt.pix.quantization = ctx->quant;
+ f->fmt.pix_mp.width = q_data->crop_width;
+ f->fmt.pix_mp.height = q_data->height;
+ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.colorspace = ctx->colorspace;
+ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
+ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
+ f->fmt.pix_mp.num_planes = 1;
+ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
+ f->fmt.pix_mp.quantization = ctx->quant;
+ f->fmt.pix_mp.xfer_func = ctx->xfer_func;
+
+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
return 0;
}
@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
* The V4L2 specification requires the driver to correct the format
* struct if any of the dimensions is unsupported
*/
- if (f->fmt.pix.width > MAX_W)
- f->fmt.pix.width = MAX_W;
- if (f->fmt.pix.height > MAX_H)
- f->fmt.pix.height = MAX_H;
+ if (f->fmt.pix_mp.width > MAX_W)
+ f->fmt.pix_mp.width = MAX_W;
+ if (f->fmt.pix_mp.height > MAX_H)
+ f->fmt.pix_mp.height = MAX_H;
if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
/* Only clip min w/h on capture. Treat 0x0 as unknown. */
- if (f->fmt.pix.width < MIN_W)
- f->fmt.pix.width = MIN_W;
- if (f->fmt.pix.height < MIN_H)
- f->fmt.pix.height = MIN_H;
+ if (f->fmt.pix_mp.width < MIN_W)
+ f->fmt.pix_mp.width = MIN_W;
+ if (f->fmt.pix_mp.height < MIN_H)
+ f->fmt.pix_mp.height = MIN_H;
/*
* For codecs the buffer must have a vertical alignment of 16
@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
* some of the pixels are active.
*/
if (ctx->dev->role != ISP)
- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
+ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
}
- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
- fmt);
- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
- f->fmt.pix.width,
- f->fmt.pix.height,
- fmt);
+ f->fmt.pix_mp.num_planes = 1;
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ get_bytesperline(f->fmt.pix_mp.width, fmt);
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
+ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
- f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
return 0;
}
@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
fmt = find_format(f, ctx->dev, true);
if (!fmt) {
- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
- true)->fourcc;
+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
+ true)->fourcc;
fmt = find_format(f, ctx->dev, true);
}
@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
fmt = find_format(f, ctx->dev, false);
if (!fmt) {
- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
- false)->fourcc;
+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
+ false)->fourcc;
fmt = find_format(f, ctx->dev, false);
}
- if (!f->fmt.pix.colorspace)
- f->fmt.pix.colorspace = ctx->colorspace;
+ if (!f->fmt.pix_mp.colorspace)
+ f->fmt.pix_mp.colorspace = ctx->colorspace;
return vidioc_try_fmt(ctx, f, fmt);
}
@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
bool update_capture_port = false;
int ret;
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
- f->type, f->fmt.pix.width, f->fmt.pix.height,
- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
+ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
}
q_data->fmt = find_format(f, ctx->dev,
- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
- q_data->crop_width = f->fmt.pix.width;
- q_data->height = f->fmt.pix.height;
+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ q_data->crop_width = f->fmt.pix_mp.width;
+ q_data->height = f->fmt.pix_mp.height;
if (!q_data->selection_set)
q_data->crop_height = requested_height;
@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
* Copying the behaviour of vicodec which retains a single set of
* colorspace parameters for both input and output.
*/
- ctx->colorspace = f->fmt.pix.colorspace;
- ctx->xfer_func = f->fmt.pix.xfer_func;
- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
- ctx->quant = f->fmt.pix.quantization;
+ ctx->colorspace = f->fmt.pix_mp.colorspace;
+ ctx->xfer_func = f->fmt.pix_mp.xfer_func;
+ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+ ctx->quant = f->fmt.pix_mp.quantization;
/* All parameters should have been set correctly by try_fmt */
- q_data->bytesperline = f->fmt.pix.bytesperline;
- q_data->sizeimage = f->fmt.pix.sizeimage;
+ q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline;
+ q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage;
v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
q_data->bytesperline, q_data->sizeimage);
if (ctx->dev->role == DECODE &&
q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
- f->fmt.pix.width && f->fmt.pix.height) {
+ q_data->crop_width && q_data->height) {
/*
* On the decoder, if provided with a resolution on the input
* side, then replicate that to the output side.
@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
q_data_dst->height = ALIGN(q_data->crop_height, 16);
q_data_dst->bytesperline =
- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
+ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
q_data_dst->crop_width,
q_data_dst->height,
@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- unsigned int height = f->fmt.pix.height;
+ unsigned int height = f->fmt.pix_mp.height;
int ret;
ret = vidioc_try_fmt_vid_cap(file, priv, f);
@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
- unsigned int height = f->fmt.pix.height;
+ unsigned int height = f->fmt.pix_mp.height;
int ret;
ret = vidioc_try_fmt_vid_out(file, priv, f);
@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct file *file, void *priv,
{
struct bcm2835_codec_ctx *ctx = file2ctx(file);
struct bcm2835_codec_q_data *q_data;
- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
true : false;
if ((ctx->dev->role == DECODE && !capture_queue) ||
@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
{
struct bcm2835_codec_ctx *ctx = file2ctx(file);
struct bcm2835_codec_q_data *q_data = NULL;
- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
true : false;
v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *file, void *priv,
{
struct bcm2835_codec_ctx *ctx = file2ctx(file);
- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return -EINVAL;
ctx->framerate_num =
@@ -1738,15 +1745,15 @@ static int vidioc_encoder_cmd(struct file *file, void *priv,
static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming(struct vb2_queue *q,
ctx->component_enabled = true;
}
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/*
* Create the EOS buffer.
* We only need the MMAL part, and want to NOT attach a memory
@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
struct bcm2835_codec_ctx *ctx = priv;
int ret;
- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
if (ret)
return ret;
- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
--
2.22.0

View file

@ -0,0 +1,51 @@
From 962099a5bee23abfbf17815b21d94b3563ee18fe Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@csie.org>
Date: Mon, 22 Jul 2019 22:13:30 +0800
Subject: [PATCH 755/826] staging: bcm2835-codec: implement
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
The stateful decoder specification shows an optional step for retrieving
the miminum number of capture buffers required for the decoder to
proceed. While not a required parameter, having it makes some
applications happy.
bcm2835-codec is a little different from other decoder implementations
in that there is an intermediate format conversion between the hardware
and V4L2 buffers. The number of capture buffers required is therefore
independent of the stream and DPB etc.
There are plans to remove the conversion, but it requires a fair amount
of rework within the firmware. Until that is done, simply return a value
of 1.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
.../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
index 43b903cd5391..a6a6e9d56d80 100644
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct file *file)
}
ctx->fh.ctrl_handler = hdl;
v4l2_ctrl_handler_setup(hdl);
+ } else if (dev->role == DECODE) {
+ v4l2_ctrl_handler_init(hdl, 1);
+
+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+ 1, 1, 1, 1);
+ if (hdl->error) {
+ rc = hdl->error;
+ goto free_ctrl_handler;
+ }
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
}
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
--
2.22.0

View file

@ -0,0 +1,45 @@
From 8c54e77880234ee3937d0db7318c3e0dacfecb88 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@csie.org>
Date: Mon, 22 Jul 2019 22:20:55 +0800
Subject: [PATCH 756/826] staging: bcm2835-codec: set device_caps in struct
video_device
Instead of filling in the struct v4l2_capability device_caps
field, fill in the struct video_device device_caps field.
That way the V4L2 core knows what the capabilities of the
video device are.
This is similar to a cleanup series by Hans Verkuil [1].
[1] https://www.spinics.net/lists/linux-media/msg153313.html
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
.../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
index a6a6e9d56d80..2902e49a7c77 100644
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
MEM2MEM_NAME);
- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct platform_device *pdev,
vfd = &dev->vfd;
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
switch (role) {
case DECODE:
--
2.22.0

View file

@ -0,0 +1,92 @@
From 41c722d8f45e1da8b8ffc8767162ac6483cbd18e Mon Sep 17 00:00:00 2001
From: James Hughes <james.hughes@raspberrypi.org>
Date: Tue, 16 Jul 2019 12:18:21 +0100
Subject: [PATCH 757/826] Add HDMI1 facility to the driver.
For generic ALSA, all you need is the bcm2835.h change, but
have also added structures for IEC958 HDMI. Not sure how to
test those.
---
.../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++---
.../vc04_services/bcm2835-audio/bcm2835.h | 4 ++-
2 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
index 86b921030db7..4d5b99d8ae9d 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip,
if (err)
return err;
- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
+ if (err)
+ return err;
+
+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
if (err)
return err;
@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm2835_audio_alsa = {
.newctl = snd_bcm2835_new_ctl,
};
-static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
+static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
.driver = {
.name = "bcm2835_hdmi",
.owner = THIS_MODULE,
@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
.minchannels = 1,
.newpcm = bcm2835_audio_simple_newpcm,
.newctl = snd_bcm2835_new_hdmi_ctl,
- .route = AUDIO_DEST_HDMI
+ .route = AUDIO_DEST_HDMI0
+};
+
+static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
+ .driver = {
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+ },
+ .shortname = "bcm2835 HDMI 1",
+ .longname = "bcm2835 HDMI 1",
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+ .route = AUDIO_DEST_HDMI1
};
static struct bcm2835_audio_driver bcm2835_audio_headphones = {
@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers children_devices[] = {
.is_enabled = &enable_compat_alsa,
},
{
- .audio_driver = &bcm2835_audio_hdmi,
+ .audio_driver = &bcm2835_audio_hdmi0,
+ .is_enabled = &enable_hdmi,
+ },
+ {
+ .audio_driver = &bcm2835_audio_hdmi1,
.is_enabled = &enable_hdmi,
},
{
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
index 595ad584243f..67beb9f17dc5 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
@@ -33,7 +33,9 @@ enum {
enum snd_bcm2835_route {
AUDIO_DEST_AUTO = 0,
AUDIO_DEST_HEADPHONES = 1,
- AUDIO_DEST_HDMI = 2,
+ AUDIO_DEST_HDMI = 2, // for backwards compatibility.
+ AUDIO_DEST_HDMI0 = 2,
+ AUDIO_DEST_HDMI1 = 3,
AUDIO_DEST_MAX,
};
--
2.22.0

View file

@ -0,0 +1,207 @@
From a08305b0a8318f07b1fe06825985373373f0fa65 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 5 Aug 2019 14:17:14 +0100
Subject: [PATCH 758/826] overlays: Add baudrate parameter to i2c3-i2c6
The overlays for enabling the new BCM2711 I2C interfaces were lacking
the means to configure the baud/clock rate.
Also explictly set the default pins, rather than relying on the values
in the base DTB.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/boot/dts/overlays/README | 8 ++++++++
arch/arm/boot/dts/overlays/i2c3-overlay.dts | 15 ++++++++++++---
arch/arm/boot/dts/overlays/i2c4-overlay.dts | 15 ++++++++++++---
arch/arm/boot/dts/overlays/i2c5-overlay.dts | 15 ++++++++++++---
arch/arm/boot/dts/overlays/i2c6-overlay.dts | 15 ++++++++++++---
5 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README
index 6131ac3d967c..a034d07be96a 100644
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -1221,6 +1221,8 @@ Info: Enable the i2c3 bus
Load: dtoverlay=i2c3,<param>
Params: pins_2_3 Use GPIOs 2 and 3
pins_4_5 Use GPIOs 4 and 5 (default)
+ baudrate Set the baudrate for the interface (default
+ "100000")
Name: i2c4
@@ -1228,6 +1230,8 @@ Info: Enable the i2c4 bus
Load: dtoverlay=i2c4,<param>
Params: pins_6_7 Use GPIOs 6 and 7
pins_8_9 Use GPIOs 8 and 9 (default)
+ baudrate Set the baudrate for the interface (default
+ "100000")
Name: i2c5
@@ -1235,6 +1239,8 @@ Info: Enable the i2c5 bus
Load: dtoverlay=i2c5,<param>
Params: pins_10_11 Use GPIOs 10 and 11
pins_12_13 Use GPIOs 12 and 13 (default)
+ baudrate Set the baudrate for the interface (default
+ "100000")
Name: i2c6
@@ -1242,6 +1248,8 @@ Info: Enable the i2c6 bus
Load: dtoverlay=i2c6,<param>
Params: pins_0_1 Use GPIOs 0 and 1
pins_22_23 Use GPIOs 22 and 23 (default)
+ baudrate Set the baudrate for the interface (default
+ "100000")
Name: i2s-gpio28-31
diff --git a/arch/arm/boot/dts/overlays/i2c3-overlay.dts b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
index 79d0da0ca6f2..f651f3541d25 100644
--- a/arch/arm/boot/dts/overlays/i2c3-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
@@ -6,10 +6,11 @@
fragment@0 {
target = <&i2c3>;
- __overlay__ {
+ frag0: __overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c3_pins>;
+ clock-frequency = <100000>;
};
};
@@ -20,8 +21,16 @@
};
};
+ fragment@2 {
+ target = <&i2c3_pins>;
+ __overlay__ {
+ brcm,pins = <4 5>;
+ };
+ };
+
__overrides__ {
- pins_2_3 = <0>,"=1";
- pins_4_5 = <0>,"!1";
+ pins_2_3 = <0>,"=1!2";
+ pins_4_5 = <0>,"!1=2";
+ baudrate = <&frag0>, "clock-frequency:0";
};
};
diff --git a/arch/arm/boot/dts/overlays/i2c4-overlay.dts b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
index ffad91763f07..3cfd87913918 100644
--- a/arch/arm/boot/dts/overlays/i2c4-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
@@ -6,10 +6,11 @@
fragment@0 {
target = <&i2c4>;
- __overlay__ {
+ frag0: __overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c4_pins>;
+ clock-frequency = <100000>;
};
};
@@ -20,8 +21,16 @@
};
};
+ fragment@2 {
+ target = <&i2c4_pins>;
+ __overlay__ {
+ brcm,pins = <8 9>;
+ };
+ };
+
__overrides__ {
- pins_6_7 = <0>,"=1";
- pins_8_9 = <0>,"!1";
+ pins_6_7 = <0>,"=1!2";
+ pins_8_9 = <0>,"!1=2";
+ baudrate = <&frag0>, "clock-frequency:0";
};
};
diff --git a/arch/arm/boot/dts/overlays/i2c5-overlay.dts b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
index 551ce154f877..c71f511d90cf 100644
--- a/arch/arm/boot/dts/overlays/i2c5-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
@@ -6,10 +6,11 @@
fragment@0 {
target = <&i2c5>;
- __overlay__ {
+ frag0: __overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c5_pins>;
+ clock-frequency = <100000>;
};
};
@@ -20,8 +21,16 @@
};
};
+ fragment@2 {
+ target = <&i2c5_pins>;
+ __overlay__ {
+ brcm,pins = <12 13>;
+ };
+ };
+
__overrides__ {
- pins_10_11 = <0>,"=1";
- pins_12_13 = <0>,"!1";
+ pins_10_11 = <0>,"=1!2";
+ pins_12_13 = <0>,"!1=2";
+ baudrate = <&frag0>, "clock-frequency:0";
};
};
diff --git a/arch/arm/boot/dts/overlays/i2c6-overlay.dts b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
index 0a67f7da6ac0..17861ef00c5b 100644
--- a/arch/arm/boot/dts/overlays/i2c6-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
@@ -6,10 +6,11 @@
fragment@0 {
target = <&i2c6>;
- __overlay__ {
+ frag0: __overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c6_pins>;
+ clock-frequency = <100000>;
};
};
@@ -20,8 +21,16 @@
};
};
+ fragment@2 {
+ target = <&i2c6_pins>;
+ __overlay__ {
+ brcm,pins = <22 23>;
+ };
+ };
+
__overrides__ {
- pins_0_1 = <0>,"=1";
- pins_22_23 = <0>,"!1";
+ pins_0_1 = <0>,"=1!2";
+ pins_22_23 = <0>,"!1=2";
+ baudrate = <&frag0>, "clock-frequency:0";
};
};
--
2.22.0

View file

@ -0,0 +1,105 @@
From a5b534bb890687b7fc08787ad47421e8f6d72422 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 25 Jul 2019 17:27:44 +0100
Subject: [PATCH 760/826] drm/vc4: Resolve the vblank warnings on mode
switching
The details over when and how a driver is to service the
vblank events are sketchy, and the fkms driver was triggering
a kernel warning every time the crtc was enabled or disabled.
Copy the event handling as used by the vc4-kms driver slightly
more closely, and we avoid the warnings.
https://github.com/raspberrypi/linux/issues/3020
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++--------
1 file changed, 33 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
index 066f6d17db97..425625b24e29 100644
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -933,6 +933,7 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
{
+ struct drm_device *dev = crtc->dev;
struct drm_plane *plane;
DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
@@ -948,6 +949,35 @@ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_s
drm_atomic_crtc_for_each_plane(plane, crtc)
vc4_plane_atomic_disable(plane, plane->state);
+
+ /*
+ * Make sure we issue a vblank event after disabling the CRTC if
+ * someone was waiting it.
+ */
+ if (crtc->state->event) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+}
+
+static void vc4_crtc_consume_event(struct drm_crtc *crtc)
+{
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ unsigned long flags;
+
+ crtc->state->event->pipe = drm_crtc_index(crtc);
+
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ vc4_crtc->event = crtc->state->event;
+ crtc->state->event = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
}
static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
@@ -957,6 +987,7 @@ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_st
DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
crtc->base.id);
drm_crtc_vblank_on(crtc);
+ vc4_crtc_consume_event(crtc);
/* Unblank the planes (if they're supposed to be displayed). */
drm_atomic_crtc_for_each_plane(plane, crtc)
@@ -1028,23 +1059,10 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- struct drm_device *dev = crtc->dev;
-
DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
crtc->base.id);
- if (crtc->state->event) {
- unsigned long flags;
-
- crtc->state->event->pipe = drm_crtc_index(crtc);
-
- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-
- spin_lock_irqsave(&dev->event_lock, flags);
- vc4_crtc->event = crtc->state->event;
- crtc->state->event = NULL;
- spin_unlock_irqrestore(&dev->event_lock, flags);
- }
+ if (crtc->state->active && old_state->active && crtc->state->event)
+ vc4_crtc_consume_event(crtc);
}
static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
--
2.22.0

View file

@ -0,0 +1,32 @@
From c76cadf3388c4fb96cd57139dae6f4581ee13f77 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 25 Jul 2019 17:34:29 +0100
Subject: [PATCH 761/826] drm/vc4: Remove unused mode variable
"89d1376 drm/vc4: Add support for margins to fkms" removed
the requirement for having the mode structure from vc4_plane_to_mb,
but didn't remove it as a local to the function, causing a
compiler warning.
Remove the unused variable.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
index 425625b24e29..357b497f19ae 100644
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -523,7 +523,6 @@ static int vc4_plane_to_mb(struct drm_plane *plane,
const struct vc_image_format *vc_fmt =
vc4_get_vc_image_fmt(drm_fmt->format);
int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
unsigned int rotation = SUPPORTED_ROTATIONS;
mb->plane.vc_image_type = vc_fmt->vc_image;
--
2.22.0

View file

@ -0,0 +1,47 @@
From a86716fb9f7668aea882d1f890ff30b75eff4bfc Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 11 Jul 2019 14:57:09 +0100
Subject: [PATCH 763/826] staging:bcm2835-codec: Expand logging on format
setting
Adds some more useful logging during format changed events and
s_fmt.
Reported by: zillevdr <zillevdr@gmx.de>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
.../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
index 2902e49a7c77..a6ef88958b60 100644
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
format->es.video.color_space);
q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n",
+ __func__, q_data->bytesperline, q_data->height,
+ q_data->crop_width, q_data->crop_height);
+
q_data->crop_width = format->es.video.crop.width;
q_data->crop_height = format->es.video.crop.height;
q_data->bytesperline = format->es.video.crop.width;
@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
bool update_capture_port = false;
int ret;
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n",
f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
-
+ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat),
+ f->fmt.pix_mp.plane_fmt[0].sizeimage);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
--
2.22.0

View file

@ -0,0 +1,35 @@
From 6da0550a342143e11ca1d558b5307aac6c284514 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 11 Jul 2019 14:58:35 +0100
Subject: [PATCH 764/826] staging: bcm2835-codec: Correct bytesperline on
format changed
The handling of format changed events incorrectly set bytesperline
to the cropped width, which ignored padding and formats with
more than 8bpp.
Fix these.
Reported by: zillevdr <zillevdr@gmx.de>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
.../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
index a6ef88958b60..66edec1197ea 100644
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
q_data->crop_width = format->es.video.crop.width;
q_data->crop_height = format->es.video.crop.height;
- q_data->bytesperline = format->es.video.crop.width;
+ q_data->bytesperline = get_bytesperline(format->es.video.width,
+ q_data->fmt);
+
q_data->height = format->es.video.height;
q_data->sizeimage = format->buffer_size_min;
if (format->es.video.color_space)
--
2.22.0

View file

@ -0,0 +1,33 @@
From 76b2727efaca513fe81b4ba56658ea2b9f9d0907 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 7 Aug 2019 11:31:08 +0100
Subject: [PATCH 765/826] drm/vc4: Add missing NULL check to
vc4_crtc_consume_event
vc4_crtc_consume_event wasn't checking crtc->state->event was
set before dereferencing it, leading to an OOPS.
Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching"
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
index 357b497f19ae..89ad71cff2bd 100644
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
@@ -969,6 +969,9 @@ static void vc4_crtc_consume_event(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
unsigned long flags;
+ if (!crtc->state->event)
+ return;
+
crtc->state->event->pipe = drm_crtc_index(crtc);
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
--
2.22.0

View file

@ -0,0 +1,57 @@
From 02f18a908b8de64ffb2f18cc8acfd8892bc8b038 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 9 Aug 2019 08:51:43 +0100
Subject: [PATCH 767/826] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail
Some combinations of Pi 4Bs and Ethernet switches don't reliably get a
DCHP-assigned IP address, leaving the unit with a self=assigned 169.254
address. In the failure case, the Pi is left able to receive packets
but not send them, suggesting that the MAC<->PHY link is getting into
a bad state.
It has been found empirically that skipping a reset step by the genet
driver prevents the failures. No downsides have been discovered yet,
and unlike the forced renegotiation it doesn't increase the time to
get an IP address, so the workaround is enabled by default; add
genet.skip_umac_reset=n
to the command line to disable it.
See: https://github.com/raspberrypi/linux/issues/3108
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index b02f33a2ff08..251166dfb8a8 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -72,6 +72,10 @@
#define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
TOTAL_DESC * DMA_DESC_SIZE)
+static bool skip_umac_reset = true;
+module_param(skip_umac_reset, bool, 0444);
+MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
+
static inline void bcmgenet_writel(u32 value, void __iomem *offset)
{
/* MIPS chips strapped for BE will automagically configure the
@@ -1993,6 +1997,11 @@ static void reset_umac(struct bcmgenet_priv *priv)
bcmgenet_rbuf_ctrl_set(priv, 0);
udelay(10);
+ if (skip_umac_reset) {
+ pr_warn("Skipping UMAC reset\n");
+ return;
+ }
+
/* disable MAC while updating its registers */
bcmgenet_umac_writel(priv, 0, UMAC_CMD);
--
2.22.0

View file

@ -0,0 +1,228 @@
From 93d6f0841eef6304c13803a84588f00476b06a14 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Wed, 24 Jul 2019 11:00:55 +0200
Subject: [PATCH 768/826] scsi: fcoe: Embed fc_rport_priv in fcoe_rport
structure
commit 023358b136d490ca91735ac6490db3741af5a8bd upstream.
Gcc-9 complains for a memset across pointer boundaries, which happens as
the code tries to allocate a flexible array on the stack. Turns out we
cannot do this without relying on gcc-isms, so with this patch we'll embed
the fc_rport_priv structure into fcoe_rport, can use the normal
'container_of' outcast, and will only have to do a memset over one
structure.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/scsi/fcoe/fcoe_ctlr.c | 51 ++++++++++++++---------------------
drivers/scsi/libfc/fc_rport.c | 5 +++-
include/scsi/libfcoe.h | 1 +
3 files changed, 25 insertions(+), 32 deletions(-)
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 7dc4ffa24430..24cbd0a2cc69 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -2017,7 +2017,7 @@ EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
*/
static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
{
- return (struct fcoe_rport *)(rdata + 1);
+ return container_of(rdata, struct fcoe_rport, rdata);
}
/**
@@ -2281,7 +2281,7 @@ static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip)
*/
static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
struct sk_buff *skb,
- struct fc_rport_priv *rdata)
+ struct fcoe_rport *frport)
{
struct fip_header *fiph;
struct fip_desc *desc = NULL;
@@ -2289,16 +2289,12 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
struct fip_wwn_desc *wwn = NULL;
struct fip_vn_desc *vn = NULL;
struct fip_size_desc *size = NULL;
- struct fcoe_rport *frport;
size_t rlen;
size_t dlen;
u32 desc_mask = 0;
u32 dtype;
u8 sub;
- memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
- frport = fcoe_ctlr_rport(rdata);
-
fiph = (struct fip_header *)skb->data;
frport->flags = ntohs(fiph->fip_flags);
@@ -2361,15 +2357,17 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
if (dlen != sizeof(struct fip_wwn_desc))
goto len_err;
wwn = (struct fip_wwn_desc *)desc;
- rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+ frport->rdata.ids.node_name =
+ get_unaligned_be64(&wwn->fd_wwn);
break;
case FIP_DT_VN_ID:
if (dlen != sizeof(struct fip_vn_desc))
goto len_err;
vn = (struct fip_vn_desc *)desc;
memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
- rdata->ids.port_id = ntoh24(vn->fd_fc_id);
- rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
+ frport->rdata.ids.port_id = ntoh24(vn->fd_fc_id);
+ frport->rdata.ids.port_name =
+ get_unaligned_be64(&vn->fd_wwpn);
break;
case FIP_DT_FC4F:
if (dlen != sizeof(struct fip_fc4_feat))
@@ -2750,10 +2748,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
struct fip_header *fiph;
enum fip_vn2vn_subcode sub;
- struct {
- struct fc_rport_priv rdata;
- struct fcoe_rport frport;
- } buf;
+ struct fcoe_rport frport = { };
int rc, vlan_id = 0;
fiph = (struct fip_header *)skb->data;
@@ -2769,7 +2764,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
goto drop;
}
- rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
+ rc = fcoe_ctlr_vn_parse(fip, skb, &frport);
if (rc) {
LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
goto drop;
@@ -2778,19 +2773,19 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
mutex_lock(&fip->ctlr_mutex);
switch (sub) {
case FIP_SC_VN_PROBE_REQ:
- fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
+ fcoe_ctlr_vn_probe_req(fip, &frport.rdata);
break;
case FIP_SC_VN_PROBE_REP:
- fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
+ fcoe_ctlr_vn_probe_reply(fip, &frport.rdata);
break;
case FIP_SC_VN_CLAIM_NOTIFY:
- fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
+ fcoe_ctlr_vn_claim_notify(fip, &frport.rdata);
break;
case FIP_SC_VN_CLAIM_REP:
- fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
+ fcoe_ctlr_vn_claim_resp(fip, &frport.rdata);
break;
case FIP_SC_VN_BEACON:
- fcoe_ctlr_vn_beacon(fip, &buf.rdata);
+ fcoe_ctlr_vn_beacon(fip, &frport.rdata);
break;
default:
LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
@@ -2814,22 +2809,18 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
*/
static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip,
struct sk_buff *skb,
- struct fc_rport_priv *rdata)
+ struct fcoe_rport *frport)
{
struct fip_header *fiph;
struct fip_desc *desc = NULL;
struct fip_mac_desc *macd = NULL;
struct fip_wwn_desc *wwn = NULL;
- struct fcoe_rport *frport;
size_t rlen;
size_t dlen;
u32 desc_mask = 0;
u32 dtype;
u8 sub;
- memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
- frport = fcoe_ctlr_rport(rdata);
-
fiph = (struct fip_header *)skb->data;
frport->flags = ntohs(fiph->fip_flags);
@@ -2883,7 +2874,8 @@ static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip,
if (dlen != sizeof(struct fip_wwn_desc))
goto len_err;
wwn = (struct fip_wwn_desc *)desc;
- rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+ frport->rdata.ids.node_name =
+ get_unaligned_be64(&wwn->fd_wwn);
break;
default:
LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
@@ -2994,22 +2986,19 @@ static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
struct fip_header *fiph;
enum fip_vlan_subcode sub;
- struct {
- struct fc_rport_priv rdata;
- struct fcoe_rport frport;
- } buf;
+ struct fcoe_rport frport = { };
int rc;
fiph = (struct fip_header *)skb->data;
sub = fiph->fip_subcode;
- rc = fcoe_ctlr_vlan_parse(fip, skb, &buf.rdata);
+ rc = fcoe_ctlr_vlan_parse(fip, skb, &frport);
if (rc) {
LIBFCOE_FIP_DBG(fip, "vlan_recv vlan_parse error %d\n", rc);
goto drop;
}
mutex_lock(&fip->ctlr_mutex);
if (sub == FIP_SC_VL_REQ)
- fcoe_ctlr_vlan_disc_reply(fip, &buf.rdata);
+ fcoe_ctlr_vlan_disc_reply(fip, &frport.rdata);
mutex_unlock(&fip->ctlr_mutex);
drop:
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 3d51a936f6d5..90a748551ede 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -140,6 +140,7 @@ EXPORT_SYMBOL(fc_rport_lookup);
struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id)
{
struct fc_rport_priv *rdata;
+ size_t rport_priv_size = sizeof(*rdata);
lockdep_assert_held(&lport->disc.disc_mutex);
@@ -147,7 +148,9 @@ struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id)
if (rdata)
return rdata;
- rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
+ if (lport->rport_priv_size > 0)
+ rport_priv_size = lport->rport_priv_size;
+ rdata = kzalloc(rport_priv_size, GFP_KERNEL);
if (!rdata)
return NULL;
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index bb8092fa1e36..58507c7783cf 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -241,6 +241,7 @@ struct fcoe_fcf {
* @vn_mac: VN_Node assigned MAC address for data
*/
struct fcoe_rport {
+ struct fc_rport_priv rdata;
unsigned long time;
u16 fcoe_len;
u16 flags;
--
2.22.0

View file

@ -0,0 +1,36 @@
From a152a7b411a54b73707f37ab753cd907c3edfc56 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Wed, 1 May 2019 11:07:40 -0700
Subject: [PATCH 769/826] gcc-9: don't warn about uninitialized variable
commit cf676908846a06443fa5e6724ca3f5dd7460eca1 upstream.
I'm not sure what made gcc warn about this code now. The 'ret' variable
does end up initialized in all cases, but it's definitely not obvious,
so the compiler is quite reasonable to warn about this.
So just add initialization to make it all much more obvious both to
compilers and to humans.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/i2c/i2c-core-base.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 5b0e1d9e5adc..1de10e5c70d7 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -185,7 +185,7 @@ static int i2c_generic_bus_free(struct i2c_adapter *adap)
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
- int i = 0, scl = 1, ret;
+ int i = 0, scl = 1, ret = 0;
if (bri->prepare_recovery)
bri->prepare_recovery(adap);
--
2.22.0

View file

@ -0,0 +1,138 @@
From 7c43f84efd6d01fc646feb67d2b2b500435b191a Mon Sep 17 00:00:00 2001
From: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Date: Mon, 5 Aug 2019 18:31:45 -0700
Subject: [PATCH 770/826] driver core: Establish order of operations for
device_add and device_del via bitflag
commit 3451a495ef244a88ed6317a035299d835554d579 upstream.
Add an additional bit flag to the device_private struct named "dead".
This additional flag provides a guarantee that when a device_del is
executed on a given interface an async worker will not attempt to attach
the driver following the earlier device_del call. Previously this
guarantee was not present and could result in the device_del call
attempting to remove a driver from an interface only to have the async
worker attempt to probe the driver later when it finally completes the
asynchronous probe call.
One additional change added was that I pulled the check for dev->driver
out of the __device_attach_driver call and instead placed it in the
__device_attach_async_helper call. This was motivated by the fact that the
only other caller of this, __device_attach, had already taken the
device_lock() and checked for dev->driver. Instead of testing for this
twice in this path it makes more sense to just consolidate the dev->dead
and dev->driver checks together into one set of checks.
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/base.h | 4 ++++
drivers/base/core.c | 11 +++++++++++
drivers/base/dd.c | 22 +++++++++++-----------
3 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 7a419a7a6235..559b047de9f7 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -66,6 +66,9 @@ struct driver_private {
* probed first.
* @device - pointer back to the struct device that this structure is
* associated with.
+ * @dead - This device is currently either in the process of or has been
+ * removed from the system. Any asynchronous events scheduled for this
+ * device should exit without taking any action.
*
* Nothing outside of the driver core should ever touch these fields.
*/
@@ -76,6 +79,7 @@ struct device_private {
struct klist_node knode_bus;
struct list_head deferred_probe;
struct device *device;
+ u8 dead:1;
};
#define to_device_private_parent(obj) \
container_of(obj, struct device_private, knode_parent)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 92e2c32c2227..37a90d72f373 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2050,6 +2050,17 @@ void device_del(struct device *dev)
struct kobject *glue_dir = NULL;
struct class_interface *class_intf;
+ /*
+ * Hold the device lock and set the "dead" flag to guarantee that
+ * the update behavior is consistent with the other bitfields near
+ * it and that we cannot have an asynchronous probe routine trying
+ * to run while we are tearing out the bus/class/sysfs from
+ * underneath the device.
+ */
+ device_lock(dev);
+ dev->p->dead = true;
+ device_unlock(dev);
+
/* Notify clients of device removal. This call must come
* before dpm_sysfs_remove().
*/
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index d48b310c4760..11d24a552ee4 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -725,15 +725,6 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
bool async_allowed;
int ret;
- /*
- * Check if device has already been claimed. This may
- * happen with driver loading, device discovery/registration,
- * and deferred probe processing happens all at once with
- * multiple threads.
- */
- if (dev->driver)
- return -EBUSY;
-
ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
@@ -768,6 +759,15 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
device_lock(dev);
+ /*
+ * Check if device has already been removed or claimed. This may
+ * happen with driver loading, device discovery/registration,
+ * and deferred probe processing happens all at once with
+ * multiple threads.
+ */
+ if (dev->p->dead || dev->driver)
+ goto out_unlock;
+
if (dev->parent)
pm_runtime_get_sync(dev->parent);
@@ -778,7 +778,7 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
if (dev->parent)
pm_runtime_put(dev->parent);
-
+out_unlock:
device_unlock(dev);
put_device(dev);
@@ -891,7 +891,7 @@ static int __driver_attach(struct device *dev, void *data)
if (dev->parent && dev->bus->need_parent_lock)
device_lock(dev->parent);
device_lock(dev);
- if (!dev->driver)
+ if (!dev->p->dead && !dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent && dev->bus->need_parent_lock)
--
2.22.0

View file

@ -0,0 +1,102 @@
From c23106d4276d7d03f1b3e9dfca40fcf793a6ebab Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Mon, 5 Aug 2019 18:31:51 -0700
Subject: [PATCH 771/826] drivers/base: Introduce kill_device()
commit 00289cd87676e14913d2d8492d1ce05c4baafdae upstream.
The libnvdimm subsystem arranges for devices to be destroyed as a result
of a sysfs operation. Since device_unregister() cannot be called from
an actively running sysfs attribute of the same device libnvdimm
arranges for device_unregister() to be performed in an out-of-line async
context.
The driver core maintains a 'dead' state for coordinating its own racing
async registration / de-registration requests. Rather than add local
'dead' state tracking infrastructure to libnvdimm device objects, export
the existing state tracking via a new kill_device() helper.
The kill_device() helper simply marks the device as dead, i.e. that it
is on its way to device_del(), or returns that the device was already
dead. This can be used in advance of calling device_unregister() for
subsystems like libnvdimm that might need to handle multiple user
threads racing to delete a device.
This refactoring does not change any behavior, but it is a pre-requisite
for follow-on fixes and therefore marked for -stable.
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Fixes: 4d88a97aa9e8 ("libnvdimm, nvdimm: dimm driver and base libnvdimm device-driver...")
Cc: <stable@vger.kernel.org>
Tested-by: Jane Chu <jane.chu@oracle.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/156341207332.292348.14959761496009347574.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/core.c | 27 +++++++++++++++++++--------
include/linux/device.h | 1 +
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 37a90d72f373..e1a8d5c06f65 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2031,6 +2031,24 @@ void put_device(struct device *dev)
}
EXPORT_SYMBOL_GPL(put_device);
+bool kill_device(struct device *dev)
+{
+ /*
+ * Require the device lock and set the "dead" flag to guarantee that
+ * the update behavior is consistent with the other bitfields near
+ * it and that we cannot have an asynchronous probe routine trying
+ * to run while we are tearing out the bus/class/sysfs from
+ * underneath the device.
+ */
+ lockdep_assert_held(&dev->mutex);
+
+ if (dev->p->dead)
+ return false;
+ dev->p->dead = true;
+ return true;
+}
+EXPORT_SYMBOL_GPL(kill_device);
+
/**
* device_del - delete device from system.
* @dev: device.
@@ -2050,15 +2068,8 @@ void device_del(struct device *dev)
struct kobject *glue_dir = NULL;
struct class_interface *class_intf;
- /*
- * Hold the device lock and set the "dead" flag to guarantee that
- * the update behavior is consistent with the other bitfields near
- * it and that we cannot have an asynchronous probe routine trying
- * to run while we are tearing out the bus/class/sysfs from
- * underneath the device.
- */
device_lock(dev);
- dev->p->dead = true;
+ kill_device(dev);
device_unlock(dev);
/* Notify clients of device removal. This call must come
diff --git a/include/linux/device.h b/include/linux/device.h
index 3f1066a9e1c3..19dd8852602c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1332,6 +1332,7 @@ extern int (*platform_notify_remove)(struct device *dev);
*/
extern struct device *get_device(struct device *dev);
extern void put_device(struct device *dev);
+extern bool kill_device(struct device *dev);
#ifdef CONFIG_DEVTMPFS
extern int devtmpfs_create_node(struct device *dev);
--
2.22.0

View file

@ -0,0 +1,96 @@
From d16bbdbbcb5002c5366cbf6402561d0350afd5fe Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Mon, 5 Aug 2019 18:31:56 -0700
Subject: [PATCH 772/826] libnvdimm/bus: Prevent duplicate device_unregister()
calls
commit 8aac0e2338916e273ccbd438a2b7a1e8c61749f5 upstream.
A multithreaded namespace creation/destruction stress test currently
fails with signatures like the following:
sysfs group 'power' not found for kobject 'dax1.1'
RIP: 0010:sysfs_remove_group+0x76/0x80
Call Trace:
device_del+0x73/0x370
device_unregister+0x16/0x50
nd_async_device_unregister+0x1e/0x30 [libnvdimm]
async_run_entry_fn+0x39/0x160
process_one_work+0x23c/0x5e0
worker_thread+0x3c/0x390
BUG: kernel NULL pointer dereference, address: 0000000000000020
RIP: 0010:klist_put+0x1b/0x6c
Call Trace:
klist_del+0xe/0x10
device_del+0x8a/0x2c9
? __switch_to_asm+0x34/0x70
? __switch_to_asm+0x40/0x70
device_unregister+0x44/0x4f
nd_async_device_unregister+0x22/0x2d [libnvdimm]
async_run_entry_fn+0x47/0x15a
process_one_work+0x1a2/0x2eb
worker_thread+0x1b8/0x26e
Use the kill_device() helper to atomically resolve the race of multiple
threads issuing kill, device_unregister(), requests.
Reported-by: Jane Chu <jane.chu@oracle.com>
Reported-by: Erwin Tsaur <erwin.tsaur@oracle.com>
Fixes: 4d88a97aa9e8 ("libnvdimm, nvdimm: dimm driver and base libnvdimm device-driver...")
Cc: <stable@vger.kernel.org>
Link: https://github.com/pmem/ndctl/issues/96
Tested-by: Tested-by: Jane Chu <jane.chu@oracle.com>
Link: https://lore.kernel.org/r/156341207846.292348.10435719262819764054.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvdimm/bus.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index ee39e2c1644a..11cfd23e5aff 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -528,13 +528,38 @@ EXPORT_SYMBOL(nd_device_register);
void nd_device_unregister(struct device *dev, enum nd_async_mode mode)
{
+ bool killed;
+
switch (mode) {
case ND_ASYNC:
+ /*
+ * In the async case this is being triggered with the
+ * device lock held and the unregistration work needs to
+ * be moved out of line iff this is thread has won the
+ * race to schedule the deletion.
+ */
+ if (!kill_device(dev))
+ return;
+
get_device(dev);
async_schedule_domain(nd_async_device_unregister, dev,
&nd_async_domain);
break;
case ND_SYNC:
+ /*
+ * In the sync case the device is being unregistered due
+ * to a state change of the parent. Claim the kill state
+ * to synchronize against other unregistration requests,
+ * or otherwise let the async path handle it if the
+ * unregistration was already queued.
+ */
+ device_lock(dev);
+ killed = kill_device(dev);
+ device_unlock(dev);
+
+ if (!killed)
+ return;
+
nd_synchronize();
device_unregister(dev);
break;
--
2.22.0

View file

@ -0,0 +1,94 @@
From 3248536919c17855ef5f2bc736d9565d9580706a Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Mon, 5 Aug 2019 18:32:02 -0700
Subject: [PATCH 773/826] libnvdimm/region: Register badblocks before
namespaces
commit 700cd033a82d466ad8f9615f9985525e45f8960a upstream.
Namespace activation expects to be able to reference region badblocks.
The following warning sometimes triggers when asynchronous namespace
activation races in front of the completion of namespace probing. Move
all possible namespace probing after region badblocks initialization.
Otherwise, lockdep sometimes catches the uninitialized state of the
badblocks seqlock with stack trace signatures like:
INFO: trying to register non-static key.
pmem2: detected capacity change from 0 to 136365211648
the code is fine but needs lockdep annotation.
turning off the locking correctness validator.
CPU: 9 PID: 358 Comm: kworker/u80:5 Tainted: G OE 5.2.0-rc4+ #3382
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
Workqueue: events_unbound async_run_entry_fn
Call Trace:
dump_stack+0x85/0xc0
pmem1.12: detected capacity change from 0 to 8589934592
register_lock_class+0x56a/0x570
? check_object+0x140/0x270
__lock_acquire+0x80/0x1710
? __mutex_lock+0x39d/0x910
lock_acquire+0x9e/0x180
? nd_pfn_validate+0x28f/0x440 [libnvdimm]
badblocks_check+0x93/0x1f0
? nd_pfn_validate+0x28f/0x440 [libnvdimm]
nd_pfn_validate+0x28f/0x440 [libnvdimm]
? lockdep_hardirqs_on+0xf0/0x180
nd_dax_probe+0x9a/0x120 [libnvdimm]
nd_pmem_probe+0x6d/0x180 [nd_pmem]
nvdimm_bus_probe+0x90/0x2c0 [libnvdimm]
Fixes: 48af2f7e52f4 ("libnvdimm, pfn: during init, clear errors...")
Cc: <stable@vger.kernel.org>
Cc: Vishal Verma <vishal.l.verma@intel.com>
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/156341208365.292348.1547528796026249120.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvdimm/region.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index b9ca0033cc99..f9130cc157e8 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -42,17 +42,6 @@ static int nd_region_probe(struct device *dev)
if (rc)
return rc;
- rc = nd_region_register_namespaces(nd_region, &err);
- if (rc < 0)
- return rc;
-
- ndrd = dev_get_drvdata(dev);
- ndrd->ns_active = rc;
- ndrd->ns_count = rc + err;
-
- if (rc && err && rc == err)
- return -ENODEV;
-
if (is_nd_pmem(&nd_region->dev)) {
struct resource ndr_res;
@@ -68,6 +57,17 @@ static int nd_region_probe(struct device *dev)
nvdimm_badblocks_populate(nd_region, &nd_region->bb, &ndr_res);
}
+ rc = nd_region_register_namespaces(nd_region, &err);
+ if (rc < 0)
+ return rc;
+
+ ndrd = dev_get_drvdata(dev);
+ ndrd->ns_active = rc;
+ ndrd->ns_count = rc + err;
+
+ if (rc && err && rc == err)
+ return -ENODEV;
+
nd_region->btt_seed = nd_btt_create(nd_region);
nd_region->pfn_seed = nd_pfn_create(nd_region);
nd_region->dax_seed = nd_dax_create(nd_region);
--
2.22.0

View file

@ -0,0 +1,165 @@
From 7f000e7b44901519b41bbe6352a9fb0afc5b6d18 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Mon, 5 Aug 2019 18:32:07 -0700
Subject: [PATCH 774/826] libnvdimm/bus: Prepare the nd_ioctl() path to be
re-entrant
commit 6de5d06e657acdbcf9637dac37916a4a5309e0f4 upstream.
In preparation for not holding a lock over the execution of nd_ioctl(),
update the implementation to allow multiple threads to be attempting
ioctls at the same time. The bus lock still prevents multiple in-flight
->ndctl() invocations from corrupting each other's state, but static
global staging buffers are moved to the heap.
Reported-by: Vishal Verma <vishal.l.verma@intel.com>
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
Tested-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/156341208947.292348.10560140326807607481.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvdimm/bus.c | 59 +++++++++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 22 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 11cfd23e5aff..5abcdb4faa64 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -951,20 +951,19 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
int read_only, unsigned int ioctl_cmd, unsigned long arg)
{
struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
- static char out_env[ND_CMD_MAX_ENVELOPE];
- static char in_env[ND_CMD_MAX_ENVELOPE];
const struct nd_cmd_desc *desc = NULL;
unsigned int cmd = _IOC_NR(ioctl_cmd);
struct device *dev = &nvdimm_bus->dev;
void __user *p = (void __user *) arg;
+ char *out_env = NULL, *in_env = NULL;
const char *cmd_name, *dimm_name;
u32 in_len = 0, out_len = 0;
unsigned int func = cmd;
unsigned long cmd_mask;
struct nd_cmd_pkg pkg;
int rc, i, cmd_rc;
+ void *buf = NULL;
u64 buf_len = 0;
- void *buf;
if (nvdimm) {
desc = nd_cmd_dimm_desc(cmd);
@@ -1004,6 +1003,9 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
}
/* process an input envelope */
+ in_env = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL);
+ if (!in_env)
+ return -ENOMEM;
for (i = 0; i < desc->in_num; i++) {
u32 in_size, copy;
@@ -1011,14 +1013,17 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (in_size == UINT_MAX) {
dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n",
__func__, dimm_name, cmd_name, i);
- return -ENXIO;
+ rc = -ENXIO;
+ goto out;
}
- if (in_len < sizeof(in_env))
- copy = min_t(u32, sizeof(in_env) - in_len, in_size);
+ if (in_len < ND_CMD_MAX_ENVELOPE)
+ copy = min_t(u32, ND_CMD_MAX_ENVELOPE - in_len, in_size);
else
copy = 0;
- if (copy && copy_from_user(&in_env[in_len], p + in_len, copy))
- return -EFAULT;
+ if (copy && copy_from_user(&in_env[in_len], p + in_len, copy)) {
+ rc = -EFAULT;
+ goto out;
+ }
in_len += in_size;
}
@@ -1030,6 +1035,12 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
}
/* process an output envelope */
+ out_env = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL);
+ if (!out_env) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
for (i = 0; i < desc->out_num; i++) {
u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
(u32 *) in_env, (u32 *) out_env, 0);
@@ -1038,15 +1049,18 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (out_size == UINT_MAX) {
dev_dbg(dev, "%s unknown output size cmd: %s field: %d\n",
dimm_name, cmd_name, i);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out;
}
- if (out_len < sizeof(out_env))
- copy = min_t(u32, sizeof(out_env) - out_len, out_size);
+ if (out_len < ND_CMD_MAX_ENVELOPE)
+ copy = min_t(u32, ND_CMD_MAX_ENVELOPE - out_len, out_size);
else
copy = 0;
if (copy && copy_from_user(&out_env[out_len],
- p + in_len + out_len, copy))
- return -EFAULT;
+ p + in_len + out_len, copy)) {
+ rc = -EFAULT;
+ goto out;
+ }
out_len += out_size;
}
@@ -1054,12 +1068,15 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (buf_len > ND_IOCTL_MAX_BUFLEN) {
dev_dbg(dev, "%s cmd: %s buf_len: %llu > %d\n", dimm_name,
cmd_name, buf_len, ND_IOCTL_MAX_BUFLEN);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
buf = vmalloc(buf_len);
- if (!buf)
- return -ENOMEM;
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
if (copy_from_user(buf, p, buf_len)) {
rc = -EFAULT;
@@ -1081,17 +1098,15 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
nvdimm_account_cleared_poison(nvdimm_bus, clear_err->address,
clear_err->cleared);
}
- nvdimm_bus_unlock(&nvdimm_bus->dev);
if (copy_to_user(p, buf, buf_len))
rc = -EFAULT;
- vfree(buf);
- return rc;
-
- out_unlock:
+out_unlock:
nvdimm_bus_unlock(&nvdimm_bus->dev);
- out:
+out:
+ kfree(in_env);
+ kfree(out_env);
vfree(buf);
return rc;
}
--
2.22.0

View file

@ -0,0 +1,153 @@
From 2364ed0d8ed11e30757563312587516911c88ae3 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Mon, 5 Aug 2019 18:32:13 -0700
Subject: [PATCH 775/826] libnvdimm/bus: Fix wait_nvdimm_bus_probe_idle() ABBA
deadlock
commit ca6bf264f6d856f959c4239cda1047b587745c67 upstream.
A multithreaded namespace creation/destruction stress test currently
deadlocks with the following lockup signature:
INFO: task ndctl:2924 blocked for more than 122 seconds.
Tainted: G OE 5.2.0-rc4+ #3382
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
ndctl D 0 2924 1176 0x00000000
Call Trace:
? __schedule+0x27e/0x780
schedule+0x30/0xb0
wait_nvdimm_bus_probe_idle+0x8a/0xd0 [libnvdimm]
? finish_wait+0x80/0x80
uuid_store+0xe6/0x2e0 [libnvdimm]
kernfs_fop_write+0xf0/0x1a0
vfs_write+0xb7/0x1b0
ksys_write+0x5c/0xd0
do_syscall_64+0x60/0x240
INFO: task ndctl:2923 blocked for more than 122 seconds.
Tainted: G OE 5.2.0-rc4+ #3382
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
ndctl D 0 2923 1175 0x00000000
Call Trace:
? __schedule+0x27e/0x780
? __mutex_lock+0x489/0x910
schedule+0x30/0xb0
schedule_preempt_disabled+0x11/0x20
__mutex_lock+0x48e/0x910
? nvdimm_namespace_common_probe+0x95/0x4d0 [libnvdimm]
? __lock_acquire+0x23f/0x1710
? nvdimm_namespace_common_probe+0x95/0x4d0 [libnvdimm]
nvdimm_namespace_common_probe+0x95/0x4d0 [libnvdimm]
__dax_pmem_probe+0x5e/0x210 [dax_pmem_core]
? nvdimm_bus_probe+0x1d0/0x2c0 [libnvdimm]
dax_pmem_probe+0xc/0x20 [dax_pmem]
nvdimm_bus_probe+0x90/0x2c0 [libnvdimm]
really_probe+0xef/0x390
driver_probe_device+0xb4/0x100
In this sequence an 'nd_dax' device is being probed and trying to take
the lock on its backing namespace to validate that the 'nd_dax' device
indeed has exclusive access to the backing namespace. Meanwhile, another
thread is trying to update the uuid property of that same backing
namespace. So one thread is in the probe path trying to acquire the
lock, and the other thread has acquired the lock and tries to flush the
probe path.
Fix this deadlock by not holding the namespace device_lock over the
wait_nvdimm_bus_probe_idle() synchronization step. In turn this requires
the device_lock to be held on entry to wait_nvdimm_bus_probe_idle() and
subsequently dropped internally to wait_nvdimm_bus_probe_idle().
Cc: <stable@vger.kernel.org>
Fixes: bf9bccc14c05 ("libnvdimm: pmem label sets and namespace instantiation")
Cc: Vishal Verma <vishal.l.verma@intel.com>
Tested-by: Jane Chu <jane.chu@oracle.com>
Link: https://lore.kernel.org/r/156341210094.292348.2384694131126767789.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvdimm/bus.c | 14 +++++++++-----
drivers/nvdimm/region_devs.c | 4 ++++
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 5abcdb4faa64..2ba22cd1331b 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -865,10 +865,12 @@ void wait_nvdimm_bus_probe_idle(struct device *dev)
do {
if (nvdimm_bus->probe_active == 0)
break;
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ nvdimm_bus_unlock(dev);
+ device_unlock(dev);
wait_event(nvdimm_bus->wait,
nvdimm_bus->probe_active == 0);
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ device_lock(dev);
+ nvdimm_bus_lock(dev);
} while (true);
}
@@ -994,7 +996,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
case ND_CMD_ARS_START:
case ND_CMD_CLEAR_ERROR:
case ND_CMD_CALL:
- dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
+ dev_dbg(dev, "'%s' command while read-only.\n",
nvdimm ? nvdimm_cmd_name(cmd)
: nvdimm_bus_cmd_name(cmd));
return -EPERM;
@@ -1083,7 +1085,8 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
goto out;
}
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ device_lock(dev);
+ nvdimm_bus_lock(dev);
rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, func, buf);
if (rc)
goto out_unlock;
@@ -1103,7 +1106,8 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
rc = -EFAULT;
out_unlock:
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ nvdimm_bus_unlock(dev);
+ device_unlock(dev);
out:
kfree(in_env);
kfree(out_env);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index e7377f1028ef..0303296e6d5b 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -425,10 +425,12 @@ static ssize_t available_size_show(struct device *dev,
* memory nvdimm_bus_lock() is dropped, but that's userspace's
* problem to not race itself.
*/
+ device_lock(dev);
nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev);
available = nd_region_available_dpa(nd_region);
nvdimm_bus_unlock(dev);
+ device_unlock(dev);
return sprintf(buf, "%llu\n", available);
}
@@ -440,10 +442,12 @@ static ssize_t max_available_extent_show(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev);
unsigned long long available = 0;
+ device_lock(dev);
nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev);
available = nd_region_allocatable_dpa(nd_region);
nvdimm_bus_unlock(dev);
+ device_unlock(dev);
return sprintf(buf, "%llu\n", available);
}
--
2.22.0

View file

@ -0,0 +1,52 @@
From e830c2c3c1748613cdcd0df85e6edcd8b59d9336 Mon Sep 17 00:00:00 2001
From: Aaron Armstrong Skomra <skomra@gmail.com>
Date: Tue, 23 Jul 2019 11:09:15 -0700
Subject: [PATCH 776/826] HID: wacom: fix bit shift for Cintiq Companion 2
commit 693c3dab4e50403f91bca4b52fc6d8562a3180f6 upstream.
The bit indicating BTN_6 on this device is overshifted
by 2 bits, resulting in the incorrect button being
reported.
Also fix copy-paste mistake in comments.
Signed-off-by: Aaron Armstrong Skomra <aaron.skomra@wacom.com>
Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
Link: https://github.com/linuxwacom/xf86-input-wacom/issues/71
Fixes: c7f0522a1ad1 ("HID: wacom: Slim down wacom_intuos_pad processing")
Cc: <stable@vger.kernel.org> # v4.5+
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/wacom_wac.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 0ae848369474..e56dc97fe4b6 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -537,14 +537,14 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
*/
buttons = (data[4] << 1) | (data[3] & 0x01);
} else if (features->type == CINTIQ_COMPANION_2) {
- /* d-pad right -> data[4] & 0x10
- * d-pad up -> data[4] & 0x20
- * d-pad left -> data[4] & 0x40
- * d-pad down -> data[4] & 0x80
- * d-pad center -> data[3] & 0x01
+ /* d-pad right -> data[2] & 0x10
+ * d-pad up -> data[2] & 0x20
+ * d-pad left -> data[2] & 0x40
+ * d-pad down -> data[2] & 0x80
+ * d-pad center -> data[1] & 0x01
*/
buttons = ((data[2] >> 4) << 7) |
- ((data[1] & 0x04) << 6) |
+ ((data[1] & 0x04) << 4) |
((data[2] & 0x0F) << 2) |
(data[1] & 0x03);
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
--
2.22.0

View file

@ -0,0 +1,50 @@
From 608cfdfa9eb712a54900859dabae5c5c19a2a93c Mon Sep 17 00:00:00 2001
From: Sebastian Parschauer <s.parschauer@gmx.de>
Date: Wed, 24 Jul 2019 20:40:03 +0200
Subject: [PATCH 777/826] HID: Add quirk for HP X1200 PIXART OEM mouse
commit 49869d2ea9eecc105a10724c1abf035151a3c4e2 upstream.
The PixArt OEM mice are known for disconnecting every minute in
runlevel 1 or 3 if they are not always polled. So add quirk
ALWAYS_POLL for this one as well.
Jonathan Teh (@jonathan-teh) reported and tested the quirk.
Reference: https://github.com/sriemer/fix-linux-mouse/issues/15
Signed-off-by: Sebastian Parschauer <s.parschauer@gmx.de>
CC: stable@vger.kernel.org
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-quirks.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 50b3c0d89c9c..2898bb061945 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -559,6 +559,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 91e86af44a04..d29c7c9cd185 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -94,6 +94,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
--
2.22.0

View file

@ -0,0 +1,49 @@
From 8440cdc77577e5177153e121229cff73c0ba4e6c Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Wed, 7 Aug 2019 18:44:12 +0200
Subject: [PATCH 778/826] IB: directly cast the sockaddr union to aockaddr
Like commit 641114d2af31 ("RDMA: Directly cast the sockaddr union to
sockaddr") we need to quiet gcc 9 from warning about this crazy union.
That commit did not fix all of the warnings in 4.19 and older kernels
because the logic in roce_resolve_route_from_path() was rewritten
between 4.19 and 5.2 when that change happened.
Cc: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/infiniband/core/sa_query.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 7b794a14d6e8..8be082edf986 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1232,7 +1232,6 @@ static int roce_resolve_route_from_path(struct sa_path_rec *rec,
{
struct rdma_dev_addr dev_addr = {};
union {
- struct sockaddr _sockaddr;
struct sockaddr_in _sockaddr_in;
struct sockaddr_in6 _sockaddr_in6;
} sgid_addr, dgid_addr;
@@ -1249,12 +1248,12 @@ static int roce_resolve_route_from_path(struct sa_path_rec *rec,
*/
dev_addr.net = &init_net;
- rdma_gid2ip(&sgid_addr._sockaddr, &rec->sgid);
- rdma_gid2ip(&dgid_addr._sockaddr, &rec->dgid);
+ rdma_gid2ip((struct sockaddr *)&sgid_addr, &rec->sgid);
+ rdma_gid2ip((struct sockaddr *)&dgid_addr, &rec->dgid);
/* validate the route */
- ret = rdma_resolve_ip_route(&sgid_addr._sockaddr,
- &dgid_addr._sockaddr, &dev_addr);
+ ret = rdma_resolve_ip_route((struct sockaddr *)&sgid_addr,
+ (struct sockaddr *)&dgid_addr, &dev_addr);
if (ret)
return ret;
--
2.22.0

View file

@ -0,0 +1,65 @@
From cb4626784f398ae9222ed5e70ab79a2c74d9c74c Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Tue, 30 Jul 2019 22:21:41 -0500
Subject: [PATCH 779/826] atm: iphase: Fix Spectre v1 vulnerability
[ Upstream commit ea443e5e98b5b74e317ef3d26bcaea54931ccdee ]
board is controlled by user-space, hence leading to a potential
exploitation of the Spectre variant 1 vulnerability.
This issue was detected with the help of Smatch:
drivers/atm/iphase.c:2765 ia_ioctl() warn: potential spectre issue 'ia_dev' [r] (local cap)
drivers/atm/iphase.c:2774 ia_ioctl() warn: possible spectre second half. 'iadev'
drivers/atm/iphase.c:2782 ia_ioctl() warn: possible spectre second half. 'iadev'
drivers/atm/iphase.c:2816 ia_ioctl() warn: possible spectre second half. 'iadev'
drivers/atm/iphase.c:2823 ia_ioctl() warn: possible spectre second half. 'iadev'
drivers/atm/iphase.c:2830 ia_ioctl() warn: potential spectre issue '_ia_dev' [r] (local cap)
drivers/atm/iphase.c:2845 ia_ioctl() warn: possible spectre second half. 'iadev'
drivers/atm/iphase.c:2856 ia_ioctl() warn: possible spectre second half. 'iadev'
Fix this by sanitizing board before using it to index ia_dev and _ia_dev
Notice that given that speculation windows are large, the policy is
to kill the speculation on the first load and not worry if it can be
completed with a dependent load/store [1].
[1] https://lore.kernel.org/lkml/20180423164740.GY17484@dhcp22.suse.cz/
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/atm/iphase.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 82532c299bb5..008905d4152a 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -63,6 +63,7 @@
#include <asm/byteorder.h>
#include <linux/vmalloc.h>
#include <linux/jiffies.h>
+#include <linux/nospec.h>
#include "iphase.h"
#include "suni.h"
#define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
@@ -2760,8 +2761,11 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
}
if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT;
board = ia_cmds.status;
- if ((board < 0) || (board > iadev_count))
- board = 0;
+
+ if ((board < 0) || (board > iadev_count))
+ board = 0;
+ board = array_index_nospec(board, iadev_count + 1);
+
iadev = ia_dev[board];
switch (ia_cmds.cmd) {
case MEMDUMP:
--
2.22.0

View file

@ -0,0 +1,39 @@
From 774358df88f7259dafebb5876de4196826ca75a7 Mon Sep 17 00:00:00 2001
From: Sudarsana Reddy Kalluru <skalluru@marvell.com>
Date: Tue, 23 Jul 2019 19:32:41 -0700
Subject: [PATCH 780/826] bnx2x: Disable multi-cos feature.
[ Upstream commit d1f0b5dce8fda09a7f5f04c1878f181d548e42f5 ]
Commit 3968d38917eb ("bnx2x: Fix Multi-Cos.") which enabled multi-cos
feature after prolonged time in driver added some regression causing
numerous issues (sudden reboots, tx timeout etc.) reported by customers.
We plan to backout this commit and submit proper fix once we have root
cause of issues reported with this feature enabled.
Fixes: 3968d38917eb ("bnx2x: Fix Multi-Cos.")
Signed-off-by: Sudarsana Reddy Kalluru <skalluru@marvell.com>
Signed-off-by: Manish Chopra <manishc@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 3edb81a4f075..33baa17fa9d5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1936,8 +1936,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* select a non-FCoE queue */
- return fallback(dev, skb, NULL) %
- (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos);
+ return fallback(dev, skb, NULL) % (BNX2X_NUM_ETH_QUEUES(bp));
}
void bnx2x_set_num_queues(struct bnx2x *bp)
--
2.22.0

View file

@ -0,0 +1,40 @@
From c4c8899376c2eb363c70b0b200434cc9abd3d34e Mon Sep 17 00:00:00 2001
From: Cong Wang <xiyou.wangcong@gmail.com>
Date: Mon, 22 Jul 2019 21:43:00 -0700
Subject: [PATCH 781/826] ife: error out when nla attributes are empty
[ Upstream commit c8ec4632c6ac9cda0e8c3d51aa41eeab66585bd5 ]
act_ife at least requires TCA_IFE_PARMS, so we have to bail out
when there is no attribute passed in.
Reported-by: syzbot+fbb5b288c9cb6a2eeac4@syzkaller.appspotmail.com
Fixes: ef6980b6becb ("introduce IFE action")
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/sched/act_ife.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 06a3d4801878..915b6e94da63 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -484,6 +484,11 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
int ret = 0;
int err;
+ if (!nla) {
+ NL_SET_ERR_MSG_MOD(extack, "IFE requires attributes to be passed");
+ return -EINVAL;
+ }
+
err = nla_parse_nested(tb, TCA_IFE_MAX, nla, ife_policy, NULL);
if (err < 0)
return err;
--
2.22.0

View file

@ -0,0 +1,43 @@
From fdcefa46c5c22fdff4960c6bdabf245af667ceaf Mon Sep 17 00:00:00 2001
From: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
Date: Wed, 24 Jul 2019 20:00:42 +0800
Subject: [PATCH 782/826] ip6_gre: reload ipv6h in prepare_ip6gre_xmit_ipv6
[ Upstream commit 3bc817d665ac6d9de89f59df522ad86f5b5dfc03 ]
Since ip6_tnl_parse_tlv_enc_lim() can call pskb_may_pull()
which may change skb->data, so we need to re-load ipv6h at
the right place.
Fixes: 898b29798e36 ("ip6_gre: Refactor ip6gre xmit codes")
Cc: William Tu <u9012063@gmail.com>
Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
Acked-by: William Tu <u9012063@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv6/ip6_gre.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 01ecd510014f..a53ef079a539 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -680,12 +680,13 @@ static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
struct flowi6 *fl6, __u8 *dsfield,
int *encap_limit)
{
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ struct ipv6hdr *ipv6h;
struct ip6_tnl *t = netdev_priv(dev);
__u16 offset;
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
/* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
+ ipv6h = ipv6_hdr(skb);
if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
--
2.22.0

View file

@ -0,0 +1,36 @@
From f186fb5ccf699487a38b5b924fa6068274ae7d4f Mon Sep 17 00:00:00 2001
From: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
Date: Thu, 25 Jul 2019 11:07:56 +0800
Subject: [PATCH 784/826] ipip: validate header length in ipip_tunnel_xmit
[ Upstream commit 47d858d0bdcd47cc1c6c9eeca91b091dd9e55637 ]
We need the same checks introduced by commit cb9f1b783850
("ip: validate header length on virtual device xmit") for
ipip tunnel.
Fixes: cb9f1b783850b ("ip: validate header length on virtual device xmit")
Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv4/ipip.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index c891235b4966..4368282eb6f8 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -281,6 +281,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
const struct iphdr *tiph = &tunnel->parms.iph;
u8 ipproto;
+ if (!pskb_inet_may_pull(skb))
+ goto tx_error;
+
switch (skb->protocol) {
case htons(ETH_P_IP):
ipproto = IPPROTO_IPIP;
--
2.22.0

View file

@ -0,0 +1,36 @@
From 3c46905fb182334eaa6737e8faa9f6067a45c027 Mon Sep 17 00:00:00 2001
From: Jiri Pirko <jiri@mellanox.com>
Date: Wed, 31 Jul 2019 09:33:14 +0300
Subject: [PATCH 785/826] mlxsw: spectrum: Fix error path in
mlxsw_sp_module_init()
[ Upstream commit 28fe79000e9b0a6f99959869947f1ca305f14599 ]
In case of sp2 pci driver registration fail, fix the error path to
start with sp1 pci driver unregister.
Fixes: c3ab435466d5 ("mlxsw: spectrum: Extend to support Spectrum-2 ASIC")
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 0cab06046e5d..ee126bcf7c35 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -5032,7 +5032,7 @@ static int __init mlxsw_sp_module_init(void)
return 0;
err_sp2_pci_driver_register:
- mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
+ mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
err_sp1_pci_driver_register:
mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
err_sp2_core_driver_register:
--
2.22.0

View file

@ -0,0 +1,115 @@
From ffab47bf69df0f340d56ded363bac09950ae2395 Mon Sep 17 00:00:00 2001
From: Matteo Croce <mcroce@redhat.com>
Date: Thu, 1 Aug 2019 14:13:30 +0200
Subject: [PATCH 786/826] mvpp2: fix panic on module removal
[ Upstream commit 944a83a2669ae8aa2c7664e79376ca7468eb0a2b ]
mvpp2 uses a delayed workqueue to gather traffic statistics.
On module removal the workqueue can be destroyed before calling
cancel_delayed_work_sync() on its works.
Fix it by moving the destroy_workqueue() call after mvpp2_port_remove().
Also remove an unneeded call to flush_workqueue()
# rmmod mvpp2
[ 2743.311722] mvpp2 f4000000.ethernet eth1: phy link down 10gbase-kr/10Gbps/Full
[ 2743.320063] mvpp2 f4000000.ethernet eth1: Link is Down
[ 2743.572263] mvpp2 f4000000.ethernet eth2: phy link down sgmii/1Gbps/Full
[ 2743.580076] mvpp2 f4000000.ethernet eth2: Link is Down
[ 2744.102169] mvpp2 f2000000.ethernet eth0: phy link down 10gbase-kr/10Gbps/Full
[ 2744.110441] mvpp2 f2000000.ethernet eth0: Link is Down
[ 2744.115614] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[ 2744.115615] Mem abort info:
[ 2744.115616] ESR = 0x96000005
[ 2744.115617] Exception class = DABT (current EL), IL = 32 bits
[ 2744.115618] SET = 0, FnV = 0
[ 2744.115619] EA = 0, S1PTW = 0
[ 2744.115620] Data abort info:
[ 2744.115621] ISV = 0, ISS = 0x00000005
[ 2744.115622] CM = 0, WnR = 0
[ 2744.115624] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000422681000
[ 2744.115626] [0000000000000000] pgd=0000000000000000, pud=0000000000000000
[ 2744.115630] Internal error: Oops: 96000005 [#1] SMP
[ 2744.115632] Modules linked in: mvpp2(-) algif_hash af_alg nls_iso8859_1 nls_cp437 vfat fat xhci_plat_hcd m25p80 spi_nor xhci_hcd mtd usbcore i2c_mv64xxx sfp usb_common marvell10g phy_generic spi_orion mdio_i2c i2c_core mvmdio phylink sbsa_gwdt ip_tables x_tables autofs4 [last unloaded: mvpp2]
[ 2744.115654] CPU: 3 PID: 8357 Comm: kworker/3:2 Not tainted 5.3.0-rc2 #1
[ 2744.115655] Hardware name: Marvell 8040 MACCHIATOBin Double-shot (DT)
[ 2744.115665] Workqueue: events_power_efficient phylink_resolve [phylink]
[ 2744.115669] pstate: a0000085 (NzCv daIf -PAN -UAO)
[ 2744.115675] pc : __queue_work+0x9c/0x4d8
[ 2744.115677] lr : __queue_work+0x170/0x4d8
[ 2744.115678] sp : ffffff801001bd50
[ 2744.115680] x29: ffffff801001bd50 x28: ffffffc422597600
[ 2744.115684] x27: ffffff80109ae6f0 x26: ffffff80108e4018
[ 2744.115688] x25: 0000000000000003 x24: 0000000000000004
[ 2744.115691] x23: ffffff80109ae6e0 x22: 0000000000000017
[ 2744.115694] x21: ffffffc42c030000 x20: ffffffc42209e8f8
[ 2744.115697] x19: 0000000000000000 x18: 0000000000000000
[ 2744.115699] x17: 0000000000000000 x16: 0000000000000000
[ 2744.115701] x15: 0000000000000010 x14: ffffffffffffffff
[ 2744.115702] x13: ffffff8090e2b95f x12: ffffff8010e2b967
[ 2744.115704] x11: ffffff8010906000 x10: 0000000000000040
[ 2744.115706] x9 : ffffff80109223b8 x8 : ffffff80109223b0
[ 2744.115707] x7 : ffffffc42bc00068 x6 : 0000000000000000
[ 2744.115709] x5 : ffffffc42bc00000 x4 : 0000000000000000
[ 2744.115710] x3 : 0000000000000000 x2 : 0000000000000000
[ 2744.115712] x1 : 0000000000000008 x0 : ffffffc42c030000
[ 2744.115714] Call trace:
[ 2744.115716] __queue_work+0x9c/0x4d8
[ 2744.115718] delayed_work_timer_fn+0x28/0x38
[ 2744.115722] call_timer_fn+0x3c/0x180
[ 2744.115723] expire_timers+0x60/0x168
[ 2744.115724] run_timer_softirq+0xbc/0x1e8
[ 2744.115727] __do_softirq+0x128/0x320
[ 2744.115731] irq_exit+0xa4/0xc0
[ 2744.115734] __handle_domain_irq+0x70/0xc0
[ 2744.115735] gic_handle_irq+0x58/0xa8
[ 2744.115737] el1_irq+0xb8/0x140
[ 2744.115738] console_unlock+0x3a0/0x568
[ 2744.115740] vprintk_emit+0x200/0x2a0
[ 2744.115744] dev_vprintk_emit+0x1c8/0x1e4
[ 2744.115747] dev_printk_emit+0x6c/0x7c
[ 2744.115751] __netdev_printk+0x104/0x1d8
[ 2744.115752] netdev_printk+0x60/0x70
[ 2744.115756] phylink_resolve+0x38c/0x3c8 [phylink]
[ 2744.115758] process_one_work+0x1f8/0x448
[ 2744.115760] worker_thread+0x54/0x500
[ 2744.115762] kthread+0x12c/0x130
[ 2744.115764] ret_from_fork+0x10/0x1c
[ 2744.115768] Code: aa1403e0 97fffbbe aa0003f5 b4000700 (f9400261)
Fixes: 118d6298f6f0 ("net: mvpp2: add ethtool GOP statistics")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Matteo Croce <mcroce@redhat.com>
Acked-by: Antoine Tenart <antoine.tenart@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index df5b74f289e1..c357aafee106 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -5358,9 +5358,6 @@ static int mvpp2_remove(struct platform_device *pdev)
mvpp2_dbgfs_cleanup(priv);
- flush_workqueue(priv->stats_queue);
- destroy_workqueue(priv->stats_queue);
-
fwnode_for_each_available_child_node(fwnode, port_fwnode) {
if (priv->port_list[i]) {
mutex_destroy(&priv->port_list[i]->gather_stats_lock);
@@ -5369,6 +5366,8 @@ static int mvpp2_remove(struct platform_device *pdev)
i++;
}
+ destroy_workqueue(priv->stats_queue);
+
for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i];
--
2.22.0

View file

@ -0,0 +1,88 @@
From b3645a487373e2182bd9899a4fe3a2cbf2010e6e Mon Sep 17 00:00:00 2001
From: Matteo Croce <mcroce@redhat.com>
Date: Sun, 28 Jul 2019 02:46:45 +0200
Subject: [PATCH 787/826] mvpp2: refactor MTU change code
[ Upstream commit 230bd958c2c846ee292aa38bc6b006296c24ca01 ]
The MTU change code can call napi_disable() with the device already down,
leading to a deadlock. Also, lot of code is duplicated unnecessarily.
Rework mvpp2_change_mtu() to avoid the deadlock and remove duplicated code.
Fixes: 3f518509dedc ("ethernet: Add new driver for Marvell Armada 375 network unit")
Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
.../net/ethernet/marvell/mvpp2/mvpp2_main.c | 41 ++++++-------------
1 file changed, 13 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index c357aafee106..6455511457ca 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3501,6 +3501,7 @@ static int mvpp2_set_mac_address(struct net_device *dev, void *p)
static int mvpp2_change_mtu(struct net_device *dev, int mtu)
{
struct mvpp2_port *port = netdev_priv(dev);
+ bool running = netif_running(dev);
int err;
if (!IS_ALIGNED(MVPP2_RX_PKT_SIZE(mtu), 8)) {
@@ -3509,40 +3510,24 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu)
mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8);
}
- if (!netif_running(dev)) {
- err = mvpp2_bm_update_mtu(dev, mtu);
- if (!err) {
- port->pkt_size = MVPP2_RX_PKT_SIZE(mtu);
- return 0;
- }
-
- /* Reconfigure BM to the original MTU */
- err = mvpp2_bm_update_mtu(dev, dev->mtu);
- if (err)
- goto log_error;
- }
-
- mvpp2_stop_dev(port);
+ if (running)
+ mvpp2_stop_dev(port);
err = mvpp2_bm_update_mtu(dev, mtu);
- if (!err) {
+ if (err) {
+ netdev_err(dev, "failed to change MTU\n");
+ /* Reconfigure BM to the original MTU */
+ mvpp2_bm_update_mtu(dev, dev->mtu);
+ } else {
port->pkt_size = MVPP2_RX_PKT_SIZE(mtu);
- goto out_start;
}
- /* Reconfigure BM to the original MTU */
- err = mvpp2_bm_update_mtu(dev, dev->mtu);
- if (err)
- goto log_error;
-
-out_start:
- mvpp2_start_dev(port);
- mvpp2_egress_enable(port);
- mvpp2_ingress_enable(port);
+ if (running) {
+ mvpp2_start_dev(port);
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+ }
- return 0;
-log_error:
- netdev_err(dev, "failed to change MTU\n");
return err;
}
--
2.22.0

View file

@ -0,0 +1,47 @@
From 639239be11ad95fab3266577e8d1efa1e8ec9672 Mon Sep 17 00:00:00 2001
From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Date: Mon, 29 Jul 2019 12:28:41 +0300
Subject: [PATCH 788/826] net: bridge: delete local fdb on device init failure
[ Upstream commit d7bae09fa008c6c9a489580db0a5a12063b97f97 ]
On initialization failure we have to delete the local fdb which was
inserted due to the default pvid creation. This problem has been present
since the inception of default_pvid. Note that currently there are 2 cases:
1) in br_dev_init() when br_multicast_init() fails
2) if register_netdevice() fails after calling ndo_init()
This patch takes care of both since br_vlan_flush() is called on both
occasions. Also the new fdb delete would be a no-op on normal bridge
device destruction since the local fdb would've been already flushed by
br_dev_delete(). This is not an issue for ports since nbp_vlan_init() is
called last when adding a port thus nothing can fail after it.
Reported-by: syzbot+88533dc8b582309bf3ee@syzkaller.appspotmail.com
Fixes: 5be5a2df40f0 ("bridge: Add filtering support for default_pvid")
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/bridge/br_vlan.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 7df269092103..5f3950f00f73 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -677,6 +677,11 @@ void br_vlan_flush(struct net_bridge *br)
ASSERT_RTNL();
+ /* delete auto-added default pvid local fdb before flushing vlans
+ * otherwise it will be leaked on bridge device init failure
+ */
+ br_fdb_delete_by_port(br, NULL, 0, 1);
+
vg = br_vlan_group(br);
__vlan_flush(vg);
RCU_INIT_POINTER(br->vlgrp, NULL);
--
2.22.0

View file

@ -0,0 +1,62 @@
From a19d4e34f092fdb74e39de0193627f16a38997b8 Mon Sep 17 00:00:00 2001
From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Date: Tue, 30 Jul 2019 14:21:00 +0300
Subject: [PATCH 789/826] net: bridge: mcast: don't delete permanent entries
when fast leave is enabled
[ Upstream commit 5c725b6b65067909548ac9ca9bc777098ec9883d ]
When permanent entries were introduced by the commit below, they were
exempt from timing out and thus igmp leave wouldn't affect them unless
fast leave was enabled on the port which was added before permanent
entries existed. It shouldn't matter if fast leave is enabled or not
if the user added a permanent entry it shouldn't be deleted on igmp
leave.
Before:
$ echo 1 > /sys/class/net/eth4/brport/multicast_fast_leave
$ bridge mdb add dev br0 port eth4 grp 229.1.1.1 permanent
$ bridge mdb show
dev br0 port eth4 grp 229.1.1.1 permanent
< join and leave 229.1.1.1 on eth4 >
$ bridge mdb show
$
After:
$ echo 1 > /sys/class/net/eth4/brport/multicast_fast_leave
$ bridge mdb add dev br0 port eth4 grp 229.1.1.1 permanent
$ bridge mdb show
dev br0 port eth4 grp 229.1.1.1 permanent
< join and leave 229.1.1.1 on eth4 >
$ bridge mdb show
dev br0 port eth4 grp 229.1.1.1 permanent
Fixes: ccb1c31a7a87 ("bridge: add flags to distinguish permanent mdb entires")
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/bridge/br_multicast.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index fb54d32321ec..6a362da211e1 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1621,6 +1621,9 @@ br_multicast_leave_group(struct net_bridge *br,
if (!br_port_group_equal(p, port, src))
continue;
+ if (p->flags & MDB_PG_FLAGS_PERMANENT)
+ break;
+
rcu_assign_pointer(*pp, p->next);
hlist_del_init(&p->mglist);
del_timer(&p->timer);
--
2.22.0

View file

@ -0,0 +1,135 @@
From edb7ad69c439cdb960d9f519233d8d9771e329b5 Mon Sep 17 00:00:00 2001
From: Jiri Pirko <jiri@mellanox.com>
Date: Sun, 28 Jul 2019 14:56:36 +0200
Subject: [PATCH 790/826] net: fix ifindex collision during namespace removal
[ Upstream commit 55b40dbf0e76b4bfb9d8b3a16a0208640a9a45df ]
Commit aca51397d014 ("netns: Fix arbitrary net_device-s corruptions
on net_ns stop.") introduced a possibility to hit a BUG in case device
is returning back to init_net and two following conditions are met:
1) dev->ifindex value is used in a name of another "dev%d"
device in init_net.
2) dev->name is used by another device in init_net.
Under real life circumstances this is hard to get. Therefore this has
been present happily for over 10 years. To reproduce:
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 86:89:3f:86:61:29 brd ff:ff:ff:ff:ff:ff
3: enp0s2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
$ ip netns add ns1
$ ip -n ns1 link add dummy1ns1 type dummy
$ ip -n ns1 link add dummy2ns1 type dummy
$ ip link set enp0s2 netns ns1
$ ip -n ns1 link set enp0s2 name dummy0
[ 100.858894] virtio_net virtio0 dummy0: renamed from enp0s2
$ ip link add dev4 type dummy
$ ip -n ns1 a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy1ns1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 16:63:4c:38:3e:ff brd ff:ff:ff:ff:ff:ff
3: dummy2ns1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether aa:9e:86:dd:6b:5d brd ff:ff:ff:ff:ff:ff
4: dummy0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 86:89:3f:86:61:29 brd ff:ff:ff:ff:ff:ff
4: dev4: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5a:e1:4a:b6:ec:f8 brd ff:ff:ff:ff:ff:ff
$ ip netns del ns1
[ 158.717795] default_device_exit: failed to move dummy0 to init_net: -17
[ 158.719316] ------------[ cut here ]------------
[ 158.720591] kernel BUG at net/core/dev.c:9824!
[ 158.722260] invalid opcode: 0000 [#1] SMP KASAN PTI
[ 158.723728] CPU: 0 PID: 56 Comm: kworker/u2:1 Not tainted 5.3.0-rc1+ #18
[ 158.725422] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 158.727508] Workqueue: netns cleanup_net
[ 158.728915] RIP: 0010:default_device_exit.cold+0x1d/0x1f
[ 158.730683] Code: 84 e8 18 c9 3e fe 0f 0b e9 70 90 ff ff e8 36 e4 52 fe 89 d9 4c 89 e2 48 c7 c6 80 d6 25 84 48 c7 c7 20 c0 25 84 e8 f4 c8 3e
[ 158.736854] RSP: 0018:ffff8880347e7b90 EFLAGS: 00010282
[ 158.738752] RAX: 000000000000003b RBX: 00000000ffffffef RCX: 0000000000000000
[ 158.741369] RDX: 0000000000000000 RSI: ffffffff8128013d RDI: ffffed10068fcf64
[ 158.743418] RBP: ffff888033550170 R08: 000000000000003b R09: fffffbfff0b94b9c
[ 158.745626] R10: fffffbfff0b94b9b R11: ffffffff85ca5cdf R12: ffff888032f28000
[ 158.748405] R13: dffffc0000000000 R14: ffff8880335501b8 R15: 1ffff110068fcf72
[ 158.750638] FS: 0000000000000000(0000) GS:ffff888036000000(0000) knlGS:0000000000000000
[ 158.752944] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 158.755245] CR2: 00007fe8b45d21d0 CR3: 00000000340b4005 CR4: 0000000000360ef0
[ 158.757654] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 158.760012] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 158.762758] Call Trace:
[ 158.763882] ? dev_change_net_namespace+0xbb0/0xbb0
[ 158.766148] ? devlink_nl_cmd_set_doit+0x520/0x520
[ 158.768034] ? dev_change_net_namespace+0xbb0/0xbb0
[ 158.769870] ops_exit_list.isra.0+0xa8/0x150
[ 158.771544] cleanup_net+0x446/0x8f0
[ 158.772945] ? unregister_pernet_operations+0x4a0/0x4a0
[ 158.775294] process_one_work+0xa1a/0x1740
[ 158.776896] ? pwq_dec_nr_in_flight+0x310/0x310
[ 158.779143] ? do_raw_spin_lock+0x11b/0x280
[ 158.780848] worker_thread+0x9e/0x1060
[ 158.782500] ? process_one_work+0x1740/0x1740
[ 158.784454] kthread+0x31b/0x420
[ 158.786082] ? __kthread_create_on_node+0x3f0/0x3f0
[ 158.788286] ret_from_fork+0x3a/0x50
[ 158.789871] ---[ end trace defd6c657c71f936 ]---
[ 158.792273] RIP: 0010:default_device_exit.cold+0x1d/0x1f
[ 158.795478] Code: 84 e8 18 c9 3e fe 0f 0b e9 70 90 ff ff e8 36 e4 52 fe 89 d9 4c 89 e2 48 c7 c6 80 d6 25 84 48 c7 c7 20 c0 25 84 e8 f4 c8 3e
[ 158.804854] RSP: 0018:ffff8880347e7b90 EFLAGS: 00010282
[ 158.807865] RAX: 000000000000003b RBX: 00000000ffffffef RCX: 0000000000000000
[ 158.811794] RDX: 0000000000000000 RSI: ffffffff8128013d RDI: ffffed10068fcf64
[ 158.816652] RBP: ffff888033550170 R08: 000000000000003b R09: fffffbfff0b94b9c
[ 158.820930] R10: fffffbfff0b94b9b R11: ffffffff85ca5cdf R12: ffff888032f28000
[ 158.825113] R13: dffffc0000000000 R14: ffff8880335501b8 R15: 1ffff110068fcf72
[ 158.829899] FS: 0000000000000000(0000) GS:ffff888036000000(0000) knlGS:0000000000000000
[ 158.834923] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 158.838164] CR2: 00007fe8b45d21d0 CR3: 00000000340b4005 CR4: 0000000000360ef0
[ 158.841917] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 158.845149] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Fix this by checking if a device with the same name exists in init_net
and fallback to original code - dev%d to allocate name - in case it does.
This was found using syzkaller.
Fixes: aca51397d014 ("netns: Fix arbitrary net_device-s corruptions on net_ns stop.")
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/core/dev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index 138951d28643..e4b4cb40da00 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -9510,6 +9510,8 @@ static void __net_exit default_device_exit(struct net *net)
/* Push remaining network devices to init_net */
snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
+ if (__dev_get_by_name(&init_net, fb_name))
+ snprintf(fb_name, IFNAMSIZ, "dev%%d");
err = dev_change_net_namespace(dev, &init_net, fb_name);
if (err) {
pr_emerg("%s: failed to move %s to init_net: %d\n",
--
2.22.0

View file

@ -0,0 +1,81 @@
From 858f82c63667281719805a1b03a1405f14ac0269 Mon Sep 17 00:00:00 2001
From: Qian Cai <cai@lca.pw>
Date: Thu, 1 Aug 2019 09:52:54 -0400
Subject: [PATCH 791/826] net/mlx5e: always initialize frag->last_in_page
[ Upstream commit 60d60c8fbd8d1acf25b041ecd72ae4fa16e9405b ]
The commit 069d11465a80 ("net/mlx5e: RX, Enhance legacy Receive Queue
memory scheme") introduced an undefined behaviour below due to
"frag->last_in_page" is only initialized in mlx5e_init_frags_partition()
when,
if (next_frag.offset + frag_info[f].frag_stride > PAGE_SIZE)
or after bailed out the loop,
for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++)
As the result, there could be some "frag" have uninitialized
value of "last_in_page".
Later, get_frag() obtains those "frag" and check "frag->last_in_page" in
mlx5e_put_rx_frag() and triggers the error during boot. Fix it by always
initializing "frag->last_in_page" to "false" in
mlx5e_init_frags_partition().
UBSAN: Undefined behaviour in
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c:325:12
load of value 170 is not a valid value for type 'bool' (aka '_Bool')
Call trace:
dump_backtrace+0x0/0x264
show_stack+0x20/0x2c
dump_stack+0xb0/0x104
__ubsan_handle_load_invalid_value+0x104/0x128
mlx5e_handle_rx_cqe+0x8e8/0x12cc [mlx5_core]
mlx5e_poll_rx_cq+0xca8/0x1a94 [mlx5_core]
mlx5e_napi_poll+0x17c/0xa30 [mlx5_core]
net_rx_action+0x248/0x940
__do_softirq+0x350/0x7b8
irq_exit+0x200/0x26c
__handle_domain_irq+0xc8/0x128
gic_handle_irq+0x138/0x228
el1_irq+0xb8/0x140
arch_cpu_idle+0x1a4/0x348
do_idle+0x114/0x1b0
cpu_startup_entry+0x24/0x28
rest_init+0x1ac/0x1dc
arch_call_rest_init+0x10/0x18
start_kernel+0x4d4/0x57c
Fixes: 069d11465a80 ("net/mlx5e: RX, Enhance legacy Receive Queue memory scheme")
Signed-off-by: Qian Cai <cai@lca.pw>
Reviewed-by: Tariq Toukan <tariqt@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 0f1c296c3ce4..83ab2c0e6b61 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -420,12 +420,11 @@ static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix)
static void mlx5e_init_frags_partition(struct mlx5e_rq *rq)
{
- struct mlx5e_wqe_frag_info next_frag, *prev;
+ struct mlx5e_wqe_frag_info next_frag = {};
+ struct mlx5e_wqe_frag_info *prev = NULL;
int i;
next_frag.di = &rq->wqe.di[0];
- next_frag.offset = 0;
- prev = NULL;
for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) {
struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
--
2.22.0

View file

@ -0,0 +1,46 @@
From 4dddd08b571d73e9acb87b4b7fff763ba3e6d6cd Mon Sep 17 00:00:00 2001
From: Mark Zhang <markz@mellanox.com>
Date: Tue, 9 Jul 2019 05:37:12 +0300
Subject: [PATCH 792/826] net/mlx5: Use reversed order when unregister devices
[ Upstream commit 08aa5e7da6bce1a1963f63cf32c2e7ad434ad578 ]
When lag is active, which is controlled by the bonded mlx5e netdev, mlx5
interface unregestering must happen in the reverse order where rdma is
unregistered (unloaded) first, to guarantee all references to the lag
context in hardware is removed, then remove mlx5e netdev interface which
will cleanup the lag context from hardware.
Without this fix during destroy of LAG interface, we observed following
errors:
* mlx5_cmd_check:752:(pid 12556): DESTROY_LAG(0x843) op_mod(0x0) failed,
status bad parameter(0x3), syndrome (0xe4ac33)
* mlx5_cmd_check:752:(pid 12556): DESTROY_LAG(0x843) op_mod(0x0) failed,
status bad parameter(0x3), syndrome (0xa5aee8).
Fixes: a31208b1e11d ("net/mlx5_core: New init and exit flow for mlx5_core")
Reviewed-by: Parav Pandit <parav@mellanox.com>
Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Mark Zhang <markz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/mellanox/mlx5/core/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
index 1c225be9c7db..3692d6a1cce8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
@@ -307,7 +307,7 @@ void mlx5_unregister_device(struct mlx5_core_dev *dev)
struct mlx5_interface *intf;
mutex_lock(&mlx5_intf_mutex);
- list_for_each_entry(intf, &intf_list, list)
+ list_for_each_entry_reverse(intf, &intf_list, list)
mlx5_remove_device(intf, priv);
list_del(&priv->dev_list);
mutex_unlock(&mlx5_intf_mutex);
--
2.22.0

View file

@ -0,0 +1,60 @@
From c8b05980c4bf7abfe9a016c34f8bf3bb5396cbfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
Date: Sat, 27 Jul 2019 11:40:11 +0200
Subject: [PATCH 793/826] net: phylink: Fix flow control for fixed-link
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[ Upstream commit 8aace4f3eba2a3ceb431e18683ea0e1ecbade5cd ]
In phylink_parse_fixedlink() the pl->link_config.advertising bits are AND
with pl->supported, pl->supported is zeroed and only the speed/duplex
modes and MII bits are set.
So pl->link_config.advertising always loses the flow control/pause bits.
By setting Pause and Asym_Pause bits in pl->supported, the flow control
work again when devicetree "pause" is set in fixes-link node and the MAC
advertise that is supports pause.
Results with this patch.
Legend:
- DT = 'Pause' is set in the fixed-link in devicetree.
- validate() = Yes means phylink_set(mask, Pause) is set in the
validate().
- flow = results reported my link is Up line.
+-----+------------+-------+
| DT | validate() | flow |
+-----+------------+-------+
| Yes | Yes | rx/tx |
| No | Yes | off |
| Yes | No | off |
+-----+------------+-------+
Fixes: 9525ae83959b ("phylink: add phylink infrastructure")
Signed-off-by: René van Dorst <opensource@vdorst.com>
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/phy/phylink.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index e029c7977a56..2e8056d48f4a 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -226,6 +226,8 @@ static int phylink_parse_fixedlink(struct phylink *pl,
__ETHTOOL_LINK_MODE_MASK_NBITS, true);
linkmode_zero(pl->supported);
phylink_set(pl->supported, MII);
+ phylink_set(pl->supported, Pause);
+ phylink_set(pl->supported, Asym_Pause);
if (s) {
__set_bit(s->bit, pl->supported);
} else {
--
2.22.0

View file

@ -0,0 +1,92 @@
From 44b96a38c2b5dd6e67039898201fdbcbaa4974ae Mon Sep 17 00:00:00 2001
From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Date: Thu, 25 Jul 2019 12:07:12 -0600
Subject: [PATCH 794/826] net: qualcomm: rmnet: Fix incorrect UL checksum
offload logic
[ Upstream commit a7cf3d24ee6081930feb4c830a7f6f16ebe31c49 ]
The udp_ip4_ind bit is set only for IPv4 UDP non-fragmented packets
so that the hardware can flip the checksum to 0xFFFF if the computed
checksum is 0 per RFC768.
However, this bit had to be set for IPv6 UDP non fragmented packets
as well per hardware requirements. Otherwise, IPv6 UDP packets
with computed checksum as 0 were transmitted by hardware and were
dropped in the network.
In addition to setting this bit for IPv6 UDP, the field is also
appropriately renamed to udp_ind as part of this change.
Fixes: 5eb5f8608ef1 ("net: qualcomm: rmnet: Add support for TX checksum offload")
Cc: Sean Tranchetti <stranche@codeaurora.org>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 2 +-
.../net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 13 +++++++++----
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index 884f1f52dcc2..70879a3ab567 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -59,7 +59,7 @@ struct rmnet_map_dl_csum_trailer {
struct rmnet_map_ul_csum_header {
__be16 csum_start_offset;
u16 csum_insert_offset:14;
- u16 udp_ip4_ind:1;
+ u16 udp_ind:1;
u16 csum_enabled:1;
} __aligned(1);
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index 57a9c314a665..b2090cedd2e9 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -215,9 +215,9 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr,
ul_header->csum_insert_offset = skb->csum_offset;
ul_header->csum_enabled = 1;
if (ip4h->protocol == IPPROTO_UDP)
- ul_header->udp_ip4_ind = 1;
+ ul_header->udp_ind = 1;
else
- ul_header->udp_ip4_ind = 0;
+ ul_header->udp_ind = 0;
/* Changing remaining fields to network order */
hdr++;
@@ -248,6 +248,7 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
struct rmnet_map_ul_csum_header *ul_header,
struct sk_buff *skb)
{
+ struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr;
__be16 *hdr = (__be16 *)ul_header, offset;
offset = htons((__force u16)(skb_transport_header(skb) -
@@ -255,7 +256,11 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
ul_header->csum_start_offset = offset;
ul_header->csum_insert_offset = skb->csum_offset;
ul_header->csum_enabled = 1;
- ul_header->udp_ip4_ind = 0;
+
+ if (ip6h->nexthdr == IPPROTO_UDP)
+ ul_header->udp_ind = 1;
+ else
+ ul_header->udp_ind = 0;
/* Changing remaining fields to network order */
hdr++;
@@ -428,7 +433,7 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
ul_header->csum_start_offset = 0;
ul_header->csum_insert_offset = 0;
ul_header->csum_enabled = 0;
- ul_header->udp_ip4_ind = 0;
+ ul_header->udp_ind = 0;
priv->stats.csum_sw++;
}
--
2.22.0

View file

@ -0,0 +1,51 @@
From d82dc254b9670068fe8c2652553eb144cfa26399 Mon Sep 17 00:00:00 2001
From: Jia-Ju Bai <baijiaju1990@gmail.com>
Date: Mon, 29 Jul 2019 16:24:33 +0800
Subject: [PATCH 795/826] net: sched: Fix a possible null-pointer dereference
in dequeue_func()
[ Upstream commit 051c7b39be4a91f6b7d8c4548444e4b850f1f56c ]
In dequeue_func(), there is an if statement on line 74 to check whether
skb is NULL:
if (skb)
When skb is NULL, it is used on line 77:
prefetch(&skb->end);
Thus, a possible null-pointer dereference may occur.
To fix this bug, skb->end is used when skb is not NULL.
This bug is found by a static analysis tool STCheck written by us.
Fixes: 76e3cc126bb2 ("codel: Controlled Delay AQM")
Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/sched/sch_codel.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c
index 17cd81f84b5d..77fae0b7c6ee 100644
--- a/net/sched/sch_codel.c
+++ b/net/sched/sch_codel.c
@@ -71,10 +71,10 @@ static struct sk_buff *dequeue_func(struct codel_vars *vars, void *ctx)
struct Qdisc *sch = ctx;
struct sk_buff *skb = __qdisc_dequeue_head(&sch->q);
- if (skb)
+ if (skb) {
sch->qstats.backlog -= qdisc_pkt_len(skb);
-
- prefetch(&skb->end); /* we'll need skb_shinfo() */
+ prefetch(&skb->end); /* we'll need skb_shinfo() */
+ }
return skb;
}
--
2.22.0

View file

@ -0,0 +1,49 @@
From cb20f74135df76ab386afa3bb1ad1af6b995f697 Mon Sep 17 00:00:00 2001
From: Roman Mashak <mrv@mojatatu.com>
Date: Fri, 2 Aug 2019 15:16:46 -0400
Subject: [PATCH 796/826] net sched: update vlan action for batched events
operations
[ Upstream commit b35475c5491a14c8ce7a5046ef7bcda8a860581a ]
Add get_fill_size() routine used to calculate the action size
when building a batch of events.
Fixes: c7e2b9689 ("sched: introduce vlan action")
Signed-off-by: Roman Mashak <mrv@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/sched/act_vlan.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 033d273afe50..20a7d4dc381c 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -296,6 +296,14 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index,
return tcf_idr_search(tn, a, index);
}
+static size_t tcf_vlan_get_fill_size(const struct tc_action *act)
+{
+ return nla_total_size(sizeof(struct tc_vlan))
+ + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_ID */
+ + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_PROTOCOL */
+ + nla_total_size(sizeof(u8)); /* TCA_VLAN_PUSH_VLAN_PRIORITY */
+}
+
static struct tc_action_ops act_vlan_ops = {
.kind = "vlan",
.type = TCA_ACT_VLAN,
@@ -305,6 +313,7 @@ static struct tc_action_ops act_vlan_ops = {
.init = tcf_vlan_init,
.cleanup = tcf_vlan_cleanup,
.walk = tcf_vlan_walker,
+ .get_fill_size = tcf_vlan_get_fill_size,
.lookup = tcf_vlan_search,
.size = sizeof(struct tcf_vlan),
};
--
2.22.0

View file

@ -0,0 +1,638 @@
From 51d240a144a5742977b4a421ea42b7da5bf1439c Mon Sep 17 00:00:00 2001
From: Dmytro Linkin <dmitrolin@mellanox.com>
Date: Thu, 1 Aug 2019 13:02:51 +0000
Subject: [PATCH 797/826] net: sched: use temporary variable for actions
indexes
[ Upstream commit 7be8ef2cdbfe41a2e524b7c6cc3f8e6cfaa906e4 ]
Currently init call of all actions (except ipt) init their 'parm'
structure as a direct pointer to nla data in skb. This leads to race
condition when some of the filter actions were initialized successfully
(and were assigned with idr action index that was written directly
into nla data), but then were deleted and retried (due to following
action module missing or classifier-initiated retry), in which case
action init code tries to insert action to idr with index that was
assigned on previous iteration. During retry the index can be reused
by another action that was inserted concurrently, which causes
unintended action sharing between filters.
To fix described race condition, save action idr index to temporary
stack-allocated variable instead on nla data.
Fixes: 0190c1d452a9 ("net: sched: atomically check-allocate action")
Signed-off-by: Dmytro Linkin <dmitrolin@mellanox.com>
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/sched/act_bpf.c | 9 +++++----
net/sched/act_connmark.c | 9 +++++----
net/sched/act_csum.c | 9 +++++----
net/sched/act_gact.c | 8 +++++---
net/sched/act_ife.c | 8 +++++---
net/sched/act_mirred.c | 13 +++++++------
net/sched/act_nat.c | 9 +++++----
net/sched/act_pedit.c | 10 ++++++----
net/sched/act_police.c | 8 +++++---
net/sched/act_sample.c | 10 +++++-----
net/sched/act_simple.c | 10 ++++++----
net/sched/act_skbedit.c | 11 ++++++-----
net/sched/act_skbmod.c | 11 ++++++-----
net/sched/act_tunnel_key.c | 8 +++++---
net/sched/act_vlan.c | 16 +++++++++-------
15 files changed, 85 insertions(+), 64 deletions(-)
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 0c68bc9cf0b4..20fae5ca87fa 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -287,6 +287,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
struct tcf_bpf *prog;
bool is_bpf, is_ebpf;
int ret, res = 0;
+ u32 index;
if (!nla)
return -EINVAL;
@@ -299,13 +300,13 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
-
- ret = tcf_idr_check_alloc(tn, &parm->index, act, bind);
+ index = parm->index;
+ ret = tcf_idr_check_alloc(tn, &index, act, bind);
if (!ret) {
- ret = tcf_idr_create(tn, parm->index, est, act,
+ ret = tcf_idr_create(tn, index, est, act,
&act_bpf_ops, bind, true);
if (ret < 0) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 6f0f273f1139..605436747978 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -104,6 +104,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
struct tcf_connmark_info *ci;
struct tc_connmark *parm;
int ret = 0;
+ u32 index;
if (!nla)
return -EINVAL;
@@ -117,13 +118,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_CONNMARK_PARMS]);
-
- ret = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ ret = tcf_idr_check_alloc(tn, &index, a, bind);
if (!ret) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_connmark_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index b8a67ae3105a..40437197e053 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -55,6 +55,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
struct tc_csum *parm;
struct tcf_csum *p;
int ret = 0, err;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -66,13 +67,13 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
if (tb[TCA_CSUM_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_CSUM_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_csum_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index cd1d9bd32ef9..72d3347bdd41 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -64,6 +64,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
struct tc_gact *parm;
struct tcf_gact *gact;
int ret = 0;
+ u32 index;
int err;
#ifdef CONFIG_GACT_PROB
struct tc_gact_p *p_parm = NULL;
@@ -79,6 +80,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
if (tb[TCA_GACT_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_GACT_PARMS]);
+ index = parm->index;
#ifndef CONFIG_GACT_PROB
if (tb[TCA_GACT_PROB] != NULL)
@@ -91,12 +93,12 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
}
#endif
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_gact_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 915b6e94da63..24047e0e5db0 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -482,6 +482,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
u8 *saddr = NULL;
bool exists = false;
int ret = 0;
+ u32 index;
int err;
if (!nla) {
@@ -509,7 +510,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (!p)
return -ENOMEM;
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0) {
kfree(p);
return err;
@@ -521,10 +523,10 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
+ ret = tcf_idr_create(tn, index, est, a, &act_ife_ops,
bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
kfree(p);
return ret;
}
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index f767e78e38c9..548614bd9366 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -104,6 +104,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
struct net_device *dev;
bool exists = false;
int ret, err;
+ u32 index;
if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed");
@@ -117,8 +118,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
parm = nla_data(tb[TCA_MIRRED_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -135,21 +136,21 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option");
return -EINVAL;
}
if (!exists) {
if (!parm->ifindex) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
return -EINVAL;
}
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_mirred_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 4313aa102440..619828920b97 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -45,6 +45,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
struct tc_nat *parm;
int ret = 0, err;
struct tcf_nat *p;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -56,13 +57,13 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
if (tb[TCA_NAT_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_NAT_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_nat_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index ca535a8585bc..82d258b2a75a 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -149,6 +149,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
struct tcf_pedit *p;
int ret = 0, err;
int ksize;
+ u32 index;
if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Pedit requires attributes to be passed");
@@ -178,18 +179,19 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
if (IS_ERR(keys_ex))
return PTR_ERR(keys_ex);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
if (!parm->nkeys) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
ret = -EINVAL;
goto out_free;
}
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_pedit_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
goto out_free;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 5d8bfa878477..997c34db1491 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -85,6 +85,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
struct tc_action_net *tn = net_generic(net, police_net_id);
bool exists = false;
+ u32 index;
int size;
if (nla == NULL)
@@ -101,7 +102,8 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_POLICE_TBF]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -109,10 +111,10 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
return 0;
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, NULL, a,
+ ret = tcf_idr_create(tn, index, NULL, a,
&act_police_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index c7f5d630d97c..ac37654ca292 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -43,7 +43,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
struct tc_action_net *tn = net_generic(net, sample_net_id);
struct nlattr *tb[TCA_SAMPLE_MAX + 1];
struct psample_group *psample_group;
- u32 psample_group_num, rate;
+ u32 psample_group_num, rate, index;
struct tc_sample *parm;
struct tcf_sample *s;
bool exists = false;
@@ -59,8 +59,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_SAMPLE_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -68,10 +68,10 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
return 0;
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_sample_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 52400d49f81f..658efae71a09 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -88,6 +88,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
struct tcf_defact *d;
bool exists = false;
int ret = 0, err;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -100,7 +101,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_DEF_PARMS]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -111,15 +113,15 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_simp_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 86d90fc5e97e..7709710a41f7 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -107,6 +107,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
u16 *queue_mapping = NULL, *ptype = NULL;
bool exists = false;
int ret = 0, err;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -153,8 +154,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
}
parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -165,15 +166,15 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_skbedit_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index 588077fafd6c..3038493d18ca 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -88,12 +88,12 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
struct nlattr *tb[TCA_SKBMOD_MAX + 1];
struct tcf_skbmod_params *p, *p_old;
struct tc_skbmod *parm;
+ u32 lflags = 0, index;
struct tcf_skbmod *d;
bool exists = false;
u8 *daddr = NULL;
u8 *saddr = NULL;
u16 eth_type = 0;
- u32 lflags = 0;
int ret = 0, err;
if (!nla)
@@ -122,10 +122,11 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
}
parm = nla_data(tb[TCA_SKBMOD_PARMS]);
+ index = parm->index;
if (parm->flags & SKBMOD_F_SWAPMAC)
lflags = SKBMOD_F_SWAPMAC;
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -136,15 +137,15 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_skbmod_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index 72d9c432e8b4..66bfe57e74ae 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -224,6 +224,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
__be16 flags;
u8 tos, ttl;
int ret = 0;
+ u32 index;
int err;
if (!nla) {
@@ -244,7 +245,8 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
}
parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -338,7 +340,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_tunnel_key_ops, bind, true);
if (ret) {
NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
@@ -384,7 +386,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 20a7d4dc381c..da993edd2e40 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -118,6 +118,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
u8 push_prio = 0;
bool exists = false;
int ret = 0, err;
+ u32 index;
if (!nla)
return -EINVAL;
@@ -129,7 +130,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (!tb[TCA_VLAN_PARMS])
return -EINVAL;
parm = nla_data(tb[TCA_VLAN_PARMS]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -145,7 +147,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
@@ -153,7 +155,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -ERANGE;
}
@@ -167,7 +169,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EPROTONOSUPPORT;
}
} else {
@@ -181,16 +183,16 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
action = parm->v_action;
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_vlan_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
--
2.22.0

View file

@ -0,0 +1,50 @@
From ce58a3655121936ebf353db542315e3531233113 Mon Sep 17 00:00:00 2001
From: Ursula Braun <ubraun@linux.ibm.com>
Date: Fri, 2 Aug 2019 10:16:38 +0200
Subject: [PATCH 798/826] net/smc: do not schedule tx_work in SMC_CLOSED state
[ Upstream commit f9cedf1a9b1cdcfb0c52edb391d01771e43994a4 ]
The setsockopts options TCP_NODELAY and TCP_CORK may schedule the
tx worker. Make sure the socket is not yet moved into SMC_CLOSED
state (for instance by a shutdown SHUT_RDWR call).
Reported-by: syzbot+92209502e7aab127c75f@syzkaller.appspotmail.com
Reported-by: syzbot+b972214bb803a343f4fe@syzkaller.appspotmail.com
Fixes: 01d2f7e2cdd31 ("net/smc: sockopts TCP_NODELAY and TCP_CORK")
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/smc/af_smc.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 9bbab6ba2dab..26dcd02b2d0c 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -1680,14 +1680,18 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
}
break;
case TCP_NODELAY:
- if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+ if (sk->sk_state != SMC_INIT &&
+ sk->sk_state != SMC_LISTEN &&
+ sk->sk_state != SMC_CLOSED) {
if (val && !smc->use_fallback)
mod_delayed_work(system_wq, &smc->conn.tx_work,
0);
}
break;
case TCP_CORK:
- if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+ if (sk->sk_state != SMC_INIT &&
+ sk->sk_state != SMC_LISTEN &&
+ sk->sk_state != SMC_CLOSED) {
if (!val && !smc->use_fallback)
mod_delayed_work(system_wq, &smc->conn.tx_work,
0);
--
2.22.0

View file

@ -0,0 +1,84 @@
From cd7f02fecac188f3363ef1d420b284c2239947e0 Mon Sep 17 00:00:00 2001
From: Johan Hovold <johan@kernel.org>
Date: Mon, 5 Aug 2019 12:00:55 +0200
Subject: [PATCH 799/826] NFC: nfcmrvl: fix gpio-handling regression
[ Upstream commit c3953a3c2d3175d2f9f0304c9a1ba89e7743c5e4 ]
Fix two reset-gpio sanity checks which were never converted to use
gpio_is_valid(), and make sure to use -EINVAL to indicate a missing
reset line also for the UART-driver module parameter and for the USB
driver.
This specifically prevents the UART and USB drivers from incidentally
trying to request and use gpio 0, and also avoids triggering a WARN() in
gpio_to_desc() during probe when no valid reset line has been specified.
Fixes: e33a3f84f88f ("NFC: nfcmrvl: allow gpio 0 for reset signalling")
Reported-by: syzbot+cf35b76f35e068a1107f@syzkaller.appspotmail.com
Tested-by: syzbot+cf35b76f35e068a1107f@syzkaller.appspotmail.com
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nfc/nfcmrvl/main.c | 4 ++--
drivers/nfc/nfcmrvl/uart.c | 4 ++--
drivers/nfc/nfcmrvl/usb.c | 1 +
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index e65d027b91fa..529be35ac178 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -244,7 +244,7 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
/* Reset possible fault of previous session */
clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);
- if (priv->config.reset_n_io) {
+ if (gpio_is_valid(priv->config.reset_n_io)) {
nfc_info(priv->dev, "reset the chip\n");
gpio_set_value(priv->config.reset_n_io, 0);
usleep_range(5000, 10000);
@@ -255,7 +255,7 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
void nfcmrvl_chip_halt(struct nfcmrvl_private *priv)
{
- if (priv->config.reset_n_io)
+ if (gpio_is_valid(priv->config.reset_n_io))
gpio_set_value(priv->config.reset_n_io, 0);
}
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
index 9a22056e8d9e..e5a622ce4b95 100644
--- a/drivers/nfc/nfcmrvl/uart.c
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -26,7 +26,7 @@
static unsigned int hci_muxed;
static unsigned int flow_control;
static unsigned int break_control;
-static unsigned int reset_n_io;
+static int reset_n_io = -EINVAL;
/*
** NFCMRVL NCI OPS
@@ -231,5 +231,5 @@ MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
module_param(hci_muxed, uint, 0);
MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
-module_param(reset_n_io, uint, 0);
+module_param(reset_n_io, int, 0);
MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index 945cc903d8f1..888e298f610b 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -305,6 +305,7 @@ static int nfcmrvl_probe(struct usb_interface *intf,
/* No configuration for USB */
memset(&config, 0, sizeof(config));
+ config.reset_n_io = -EINVAL;
nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
--
2.22.0

View file

@ -0,0 +1,37 @@
From eaa34bd4f7b5e505c6c211cb906f6a2ce2242e4c Mon Sep 17 00:00:00 2001
From: Claudiu Manoil <claudiu.manoil@nxp.com>
Date: Thu, 25 Jul 2019 16:33:18 +0300
Subject: [PATCH 800/826] ocelot: Cancel delayed work before wq destruction
[ Upstream commit c5d139697d5d9ecf9c7cd92d7d7838a173508900 ]
Make sure the delayed work for stats update is not pending before
wq destruction.
This fixes the module unload path.
The issue is there since day 1.
Fixes: a556c76adc05 ("net: mscc: Add initial Ocelot switch support")
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/mscc/ocelot.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 10291198decd..732ba21d3369 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -1767,6 +1767,7 @@ EXPORT_SYMBOL(ocelot_init);
void ocelot_deinit(struct ocelot *ocelot)
{
+ cancel_delayed_work(&ocelot->stats_work);
destroy_workqueue(ocelot->stats_queue);
mutex_destroy(&ocelot->stats_lock);
}
--
2.22.0

View file

@ -0,0 +1,88 @@
From 5295d651548559e90245a5d744566af98d951df1 Mon Sep 17 00:00:00 2001
From: Taras Kondratiuk <takondra@cisco.com>
Date: Mon, 29 Jul 2019 22:15:07 +0000
Subject: [PATCH 801/826] tipc: compat: allow tipc commands without arguments
[ Upstream commit 4da5f0018eef4c0de31675b670c80e82e13e99d1 ]
Commit 2753ca5d9009 ("tipc: fix uninit-value in tipc_nl_compat_doit")
broke older tipc tools that use compat interface (e.g. tipc-config from
tipcutils package):
% tipc-config -p
operation not supported
The commit started to reject TIPC netlink compat messages that do not
have attributes. It is too restrictive because some of such messages are
valid (they don't need any arguments):
% grep 'tx none' include/uapi/linux/tipc_config.h
#define TIPC_CMD_NOOP 0x0000 /* tx none, rx none */
#define TIPC_CMD_GET_MEDIA_NAMES 0x0002 /* tx none, rx media_name(s) */
#define TIPC_CMD_GET_BEARER_NAMES 0x0003 /* tx none, rx bearer_name(s) */
#define TIPC_CMD_SHOW_PORTS 0x0006 /* tx none, rx ultra_string */
#define TIPC_CMD_GET_REMOTE_MNG 0x4003 /* tx none, rx unsigned */
#define TIPC_CMD_GET_MAX_PORTS 0x4004 /* tx none, rx unsigned */
#define TIPC_CMD_GET_NETID 0x400B /* tx none, rx unsigned */
#define TIPC_CMD_NOT_NET_ADMIN 0xC001 /* tx none, rx none */
This patch relaxes the original fix and rejects messages without
arguments only if such arguments are expected by a command (reg_type is
non zero).
Fixes: 2753ca5d9009 ("tipc: fix uninit-value in tipc_nl_compat_doit")
Cc: stable@vger.kernel.org
Signed-off-by: Taras Kondratiuk <takondra@cisco.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/tipc/netlink_compat.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index 85ebb675600c..318c541970ec 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -55,6 +55,7 @@ struct tipc_nl_compat_msg {
int rep_type;
int rep_size;
int req_type;
+ int req_size;
struct net *net;
struct sk_buff *rep;
struct tlv_desc *req;
@@ -257,7 +258,8 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
int err;
struct sk_buff *arg;
- if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
+ if (msg->req_type && (!msg->req_size ||
+ !TLV_CHECK_TYPE(msg->req, msg->req_type)))
return -EINVAL;
msg->rep = tipc_tlv_alloc(msg->rep_size);
@@ -354,7 +356,8 @@ static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
{
int err;
- if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
+ if (msg->req_type && (!msg->req_size ||
+ !TLV_CHECK_TYPE(msg->req, msg->req_type)))
return -EINVAL;
err = __tipc_nl_compat_doit(cmd, msg);
@@ -1276,8 +1279,8 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
goto send;
}
- len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
- if (!len || !TLV_OK(msg.req, len)) {
+ msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) {
msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
err = -EOPNOTSUPP;
goto send;
--
2.22.0

View file

@ -0,0 +1,46 @@
From f378724e10ced69c5e55db2e23ad350ede76f174 Mon Sep 17 00:00:00 2001
From: Alexis Bauvin <abauvin@scaleway.com>
Date: Tue, 23 Jul 2019 16:23:01 +0200
Subject: [PATCH 802/826] tun: mark small packets as owned by the tap sock
[ Upstream commit 4b663366246be1d1d4b1b8b01245b2e88ad9e706 ]
- v1 -> v2: Move skb_set_owner_w to __tun_build_skb to reduce patch size
Small packets going out of a tap device go through an optimized code
path that uses build_skb() rather than sock_alloc_send_pskb(). The
latter calls skb_set_owner_w(), but the small packet code path does not.
The net effect is that small packets are not owned by the userland
application's socket (e.g. QEMU), while large packets are.
This can be seen with a TCP session, where packets are not owned when
the window size is small enough (around PAGE_SIZE), while they are once
the window grows (note that this requires the host to support virtio
tso for the guest to offload segmentation).
All this leads to inconsistent behaviour in the kernel, especially on
netfilter modules that uses sk->socket (e.g. xt_owner).
Fixes: 66ccbc9c87c2 ("tap: use build_skb() for small packet")
Signed-off-by: Alexis Bauvin <abauvin@scaleway.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/tun.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index b67fee56ec81..5fa7047ea361 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1682,6 +1682,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
skb_reserve(skb, pad - delta);
skb_put(skb, len);
+ skb_set_owner_w(skb, tfile->socket.sk);
get_page(alloc_frag->page);
alloc_frag->offset += buflen;
--
2.22.0

View file

@ -0,0 +1,42 @@
From cd84a10792f08d3d0cc1cbeed07634e454fe9abd Mon Sep 17 00:00:00 2001
From: Edward Srouji <edwards@mellanox.com>
Date: Tue, 23 Jul 2019 10:12:55 +0300
Subject: [PATCH 803/826] net/mlx5: Fix modify_cq_in alignment
[ Upstream commit 7a32f2962c56d9d8a836b4469855caeee8766bd4 ]
Fix modify_cq_in alignment to match the device specification.
After this fix the 'cq_umem_valid' field will be in the right offset.
Cc: <stable@vger.kernel.org> # 4.19
Fixes: bd37197554eb ("net/mlx5: Update mlx5_ifc with DEVX UID bits")
Signed-off-by: Edward Srouji <edwards@mellanox.com>
Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/mlx5/mlx5_ifc.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index f043d65b9bac..177f11c96187 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -5623,7 +5623,12 @@ struct mlx5_ifc_modify_cq_in_bits {
struct mlx5_ifc_cqc_bits cq_context;
- u8 reserved_at_280[0x600];
+ u8 reserved_at_280[0x60];
+
+ u8 cq_umem_valid[0x1];
+ u8 reserved_at_2e1[0x1f];
+
+ u8 reserved_at_300[0x580];
u8 pas[0][0x40];
};
--
2.22.0

View file

@ -0,0 +1,106 @@
From 0ccf47265e4cb7fd13d339ee20a84bdbdbd466ef Mon Sep 17 00:00:00 2001
From: Ariel Levkovich <lariel@mellanox.com>
Date: Sat, 6 Jul 2019 18:06:15 +0300
Subject: [PATCH 804/826] net/mlx5e: Prevent encap flow counter update async to
user query
[ Upstream commit 90bb769291161cf25a818d69cf608c181654473e ]
This patch prevents a race between user invoked cached counters
query and a neighbor last usage updater.
The cached flow counter stats can be queried by calling
"mlx5_fc_query_cached" which provides the number of bytes and
packets that passed via this flow since the last time this counter
was queried.
It does so by reducting the last saved stats from the current, cached
stats and then updating the last saved stats with the cached stats.
It also provide the lastuse value for that flow.
Since "mlx5e_tc_update_neigh_used_value" needs to retrieve the
last usage time of encapsulation flows, it calls the flow counter
query method periodically and async to user queries of the flow counter
using cls_flower.
This call is causing the driver to update the last reported bytes and
packets from the cache and therefore, future user queries of the flow
stats will return lower than expected number for bytes and packets
since the last saved stats in the driver was updated async to the last
saved stats in cls_flower.
This causes wrong stats presentation of encapsulation flows to user.
Since the neighbor usage updater only needs the lastuse stats from the
cached counter, the fix is to use a dedicated lastuse query call that
returns the lastuse value without synching between the cached stats and
the last saved stats.
Fixes: f6dfb4c3f216 ("net/mlx5e: Update neighbour 'used' state using HW flow rules counters")
Signed-off-by: Ariel Levkovich <lariel@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++--
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c | 5 +++++
include/linux/mlx5/fs.h | 1 +
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 9f7f8425f676..c8928ce69185 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -992,13 +992,13 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
{
struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
- u64 bytes, packets, lastuse = 0;
struct mlx5e_tc_flow *flow;
struct mlx5e_encap_entry *e;
struct mlx5_fc *counter;
struct neigh_table *tbl;
bool neigh_used = false;
struct neighbour *n;
+ u64 lastuse;
if (m_neigh->family == AF_INET)
tbl = &arp_tbl;
@@ -1015,7 +1015,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
list_for_each_entry(flow, &e->flows, encap) {
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
counter = mlx5_flow_rule_counter(flow->rule[0]);
- mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
+ lastuse = mlx5_fc_query_lastuse(counter);
if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
neigh_used = true;
break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 58af6be13dfa..808ddd732e04 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -321,6 +321,11 @@ int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
}
EXPORT_SYMBOL(mlx5_fc_query);
+u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter)
+{
+ return counter->cache.lastuse;
+}
+
void mlx5_fc_query_cached(struct mlx5_fc *counter,
u64 *bytes, u64 *packets, u64 *lastuse)
{
diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h
index 804516e4f483..3386399feadc 100644
--- a/include/linux/mlx5/fs.h
+++ b/include/linux/mlx5/fs.h
@@ -188,6 +188,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handler,
struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handler);
struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging);
void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
+u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
void mlx5_fc_query_cached(struct mlx5_fc *counter,
u64 *bytes, u64 *packets, u64 *lastuse);
int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
--
2.22.0

View file

@ -0,0 +1,55 @@
From 473430ed61174498db9fcac8bbfee122657d3933 Mon Sep 17 00:00:00 2001
From: Heiner Kallweit <hkallweit1@gmail.com>
Date: Sat, 27 Jul 2019 12:45:10 +0200
Subject: [PATCH 805/826] r8169: don't use MSI before RTL8168d
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[ Upstream commit 003bd5b4a7b4a94b501e3a1e2e7c9df6b2a94ed4 ]
It was reported that after resuming from suspend network fails with
error "do_IRQ: 3.38 No irq handler for vector", see [0]. Enabling WoL
can work around the issue, but the only actual fix is to disable MSI.
So let's mimic the behavior of the vendor driver and disable MSI on
all chip versions before RTL8168d.
[0] https://bugzilla.kernel.org/show_bug.cgi?id=204079
Fixes: 6c6aa15fdea5 ("r8169: improve interrupt handling")
Reported-by: Dušan Dragić <dragic.dusan@gmail.com>
Tested-by: Dušan Dragić <dragic.dusan@gmail.com>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/realtek/r8169.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index a6992c4c7313..0c8b7146637e 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -7239,13 +7239,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
{
unsigned int flags;
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
RTL_W8(tp, Cfg9346, Cfg9346_Lock);
+ /* fall through */
+ case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_24:
flags = PCI_IRQ_LEGACY;
- } else {
+ break;
+ default:
flags = PCI_IRQ_ALL_TYPES;
+ break;
}
return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags);
--
2.22.0

View file

@ -0,0 +1,145 @@
From e6e9bcef12ca2e2119f999d38dbca5147b06bc14 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Tue, 30 Jul 2019 21:25:20 +0200
Subject: [PATCH 806/826] compat_ioctl: pppoe: fix PPPOEIOCSFWD handling
[ Upstream commit 055d88242a6046a1ceac3167290f054c72571cd9 ]
Support for handling the PPPOEIOCSFWD ioctl in compat mode was added in
linux-2.5.69 along with hundreds of other commands, but was always broken
sincen only the structure is compatible, but the command number is not,
due to the size being sizeof(size_t), or at first sizeof(sizeof((struct
sockaddr_pppox)), which is different on 64-bit architectures.
Guillaume Nault adds:
And the implementation was broken until 2016 (see 29e73269aa4d ("pppoe:
fix reference counting in PPPoE proxy")), and nobody ever noticed. I
should probably have removed this ioctl entirely instead of fixing it.
Clearly, it has never been used.
Fix it by adding a compat_ioctl handler for all pppoe variants that
translates the command number and then calls the regular ioctl function.
All other ioctl commands handled by pppoe are compatible between 32-bit
and 64-bit, and require compat_ptr() conversion.
This should apply to all stable kernels.
Acked-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ppp/pppoe.c | 3 +++
drivers/net/ppp/pppox.c | 13 +++++++++++++
drivers/net/ppp/pptp.c | 3 +++
fs/compat_ioctl.c | 3 ---
include/linux/if_pppox.h | 3 +++
net/l2tp/l2tp_ppp.c | 3 +++
6 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index f22639f0116a..c04f3dc17d76 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1120,6 +1120,9 @@ static const struct proto_ops pppoe_ops = {
.recvmsg = pppoe_recvmsg,
.mmap = sock_no_mmap,
.ioctl = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pppox_compat_ioctl,
+#endif
};
static const struct pppox_proto pppoe_proto = {
diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c
index c0599b3b23c0..9128e42e33e7 100644
--- a/drivers/net/ppp/pppox.c
+++ b/drivers/net/ppp/pppox.c
@@ -22,6 +22,7 @@
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/net.h>
@@ -103,6 +104,18 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL(pppox_ioctl);
+#ifdef CONFIG_COMPAT
+int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == PPPOEIOCSFWD32)
+ cmd = PPPOEIOCSFWD;
+
+ return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+
+EXPORT_SYMBOL(pppox_compat_ioctl);
+#endif
+
static int pppox_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 7321a4eca235..9ad3ff40a563 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -633,6 +633,9 @@ static const struct proto_ops pptp_ops = {
.recvmsg = sock_no_recvmsg,
.mmap = sock_no_mmap,
.ioctl = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pppox_compat_ioctl,
+#endif
};
static const struct pppox_proto pppox_pptp_proto = {
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a9b00942e87d..8f08095ee54e 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -894,9 +894,6 @@ COMPATIBLE_IOCTL(PPPIOCDISCONN)
COMPATIBLE_IOCTL(PPPIOCATTCHAN)
COMPATIBLE_IOCTL(PPPIOCGCHAN)
COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
/* Big A */
/* sparc only */
/* Big Q for sound/OSS */
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index ba7a9b0c7c57..24e9b360da65 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -84,6 +84,9 @@ extern int register_pppox_proto(int proto_num, const struct pppox_proto *pp);
extern void unregister_pppox_proto(int proto_num);
extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+
+#define PPPOEIOCSFWD32 _IOW(0xB1 ,0, compat_size_t)
/* PPPoX socket states */
enum {
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 04d9946dcdba..c0956781665e 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1686,6 +1686,9 @@ static const struct proto_ops pppol2tp_ops = {
.recvmsg = pppol2tp_recvmsg,
.mmap = sock_no_mmap,
.ioctl = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pppox_compat_ioctl,
+#endif
};
static const struct pppox_proto pppol2tp_proto = {
--
2.22.0

View file

@ -0,0 +1,44 @@
From 7528e95b7519d24027a4362e2a05a12d4747586f Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Fri, 31 May 2019 10:38:57 -0700
Subject: [PATCH 807/826] cgroup: Call cgroup_release() before __exit_signal()
commit 6b115bf58e6f013ca75e7115aabcbd56c20ff31d upstream.
cgroup_release() calls cgroup_subsys->release() which is used by the
pids controller to uncharge its pid. We want to use it to manage
iteration of dying tasks which requires putting it before
__unhash_process(). Move cgroup_release() above __exit_signal().
While this makes it uncharge before the pid is freed, pid is RCU freed
anyway and the window is very narrow.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/exit.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/exit.c b/kernel/exit.c
index 5c0964dc805a..e10de9836dd7 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -194,6 +194,7 @@ void release_task(struct task_struct *p)
rcu_read_unlock();
proc_flush_task(p);
+ cgroup_release(p);
write_lock_irq(&tasklist_lock);
ptrace_release_task(p);
@@ -219,7 +220,6 @@ void release_task(struct task_struct *p)
}
write_unlock_irq(&tasklist_lock);
- cgroup_release(p);
release_thread(p);
call_rcu(&p->rcu, delayed_put_task_struct);
--
2.22.0

View file

@ -0,0 +1,154 @@
From 370b9e6399da09fe10005fe455878b356de7b85f Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Fri, 31 May 2019 10:38:58 -0700
Subject: [PATCH 808/826] cgroup: Implement css_task_iter_skip()
commit b636fd38dc40113f853337a7d2a6885ad23b8811 upstream.
When a task is moved out of a cset, task iterators pointing to the
task are advanced using the normal css_task_iter_advance() call. This
is fine but we'll be tracking dying tasks on csets and thus moving
tasks from cset->tasks to (to be added) cset->dying_tasks. When we
remove a task from cset->tasks, if we advance the iterators, they may
move over to the next cset before we had the chance to add the task
back on the dying list, which can allow the task to escape iteration.
This patch separates out skipping from advancing. Skipping only moves
the affected iterators to the next pointer rather than fully advancing
it and the following advancing will recognize that the cursor has
already been moved forward and do the rest of advancing. This ensures
that when a task moves from one list to another in its cset, as long
as it moves in the right direction, it's always visible to iteration.
This doesn't cause any visible behavior changes.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/cgroup.h | 3 +++
kernel/cgroup/cgroup.c | 60 +++++++++++++++++++++++++-----------------
2 files changed, 39 insertions(+), 24 deletions(-)
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 8937d48a5389..f85e65b248b7 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -43,6 +43,9 @@
/* walk all threaded css_sets in the domain */
#define CSS_TASK_ITER_THREADED (1U << 1)
+/* internal flags */
+#define CSS_TASK_ITER_SKIPPED (1U << 16)
+
/* a css_task_iter should be treated as an opaque object */
struct css_task_iter {
struct cgroup_subsys *ss;
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 81441117f611..c093e187f6a6 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -212,7 +212,8 @@ static struct cftype cgroup_base_files[];
static int cgroup_apply_control(struct cgroup *cgrp);
static void cgroup_finalize_control(struct cgroup *cgrp, int ret);
-static void css_task_iter_advance(struct css_task_iter *it);
+static void css_task_iter_skip(struct css_task_iter *it,
+ struct task_struct *task);
static int cgroup_destroy_locked(struct cgroup *cgrp);
static struct cgroup_subsys_state *css_create(struct cgroup *cgrp,
struct cgroup_subsys *ss);
@@ -775,6 +776,21 @@ static void css_set_update_populated(struct css_set *cset, bool populated)
cgroup_update_populated(link->cgrp, populated);
}
+/*
+ * @task is leaving, advance task iterators which are pointing to it so
+ * that they can resume at the next position. Advancing an iterator might
+ * remove it from the list, use safe walk. See css_task_iter_skip() for
+ * details.
+ */
+static void css_set_skip_task_iters(struct css_set *cset,
+ struct task_struct *task)
+{
+ struct css_task_iter *it, *pos;
+
+ list_for_each_entry_safe(it, pos, &cset->task_iters, iters_node)
+ css_task_iter_skip(it, task);
+}
+
/**
* css_set_move_task - move a task from one css_set to another
* @task: task being moved
@@ -800,22 +816,9 @@ static void css_set_move_task(struct task_struct *task,
css_set_update_populated(to_cset, true);
if (from_cset) {
- struct css_task_iter *it, *pos;
-
WARN_ON_ONCE(list_empty(&task->cg_list));
- /*
- * @task is leaving, advance task iterators which are
- * pointing to it so that they can resume at the next
- * position. Advancing an iterator might remove it from
- * the list, use safe walk. See css_task_iter_advance*()
- * for details.
- */
- list_for_each_entry_safe(it, pos, &from_cset->task_iters,
- iters_node)
- if (it->task_pos == &task->cg_list)
- css_task_iter_advance(it);
-
+ css_set_skip_task_iters(from_cset, task);
list_del_init(&task->cg_list);
if (!css_set_populated(from_cset))
css_set_update_populated(from_cset, false);
@@ -4183,10 +4186,19 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
list_add(&it->iters_node, &cset->task_iters);
}
-static void css_task_iter_advance(struct css_task_iter *it)
+static void css_task_iter_skip(struct css_task_iter *it,
+ struct task_struct *task)
{
- struct list_head *next;
+ lockdep_assert_held(&css_set_lock);
+
+ if (it->task_pos == &task->cg_list) {
+ it->task_pos = it->task_pos->next;
+ it->flags |= CSS_TASK_ITER_SKIPPED;
+ }
+}
+static void css_task_iter_advance(struct css_task_iter *it)
+{
lockdep_assert_held(&css_set_lock);
repeat:
if (it->task_pos) {
@@ -4195,15 +4207,15 @@ static void css_task_iter_advance(struct css_task_iter *it)
* consumed first and then ->mg_tasks. After ->mg_tasks,
* we move onto the next cset.
*/
- next = it->task_pos->next;
-
- if (next == it->tasks_head)
- next = it->mg_tasks_head->next;
+ if (it->flags & CSS_TASK_ITER_SKIPPED)
+ it->flags &= ~CSS_TASK_ITER_SKIPPED;
+ else
+ it->task_pos = it->task_pos->next;
- if (next == it->mg_tasks_head)
+ if (it->task_pos == it->tasks_head)
+ it->task_pos = it->mg_tasks_head->next;
+ if (it->task_pos == it->mg_tasks_head)
css_task_iter_advance_css_set(it);
- else
- it->task_pos = next;
} else {
/* called from start, proceed to the first cset */
css_task_iter_advance_css_set(it);
--
2.22.0

View file

@ -0,0 +1,163 @@
From 4340d175b89896d069c1e875f5b98c80a408f680 Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Fri, 31 May 2019 10:38:58 -0700
Subject: [PATCH 809/826] cgroup: Include dying leaders with live threads in
PROCS iterations
commit c03cd7738a83b13739f00546166969342c8ff014 upstream.
CSS_TASK_ITER_PROCS currently iterates live group leaders; however,
this means that a process with dying leader and live threads will be
skipped. IOW, cgroup.procs might be empty while cgroup.threads isn't,
which is confusing to say the least.
Fix it by making cset track dying tasks and include dying leaders with
live threads in PROCS iteration.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Topi Miettinen <toiwoton@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/cgroup-defs.h | 1 +
include/linux/cgroup.h | 1 +
kernel/cgroup/cgroup.c | 44 +++++++++++++++++++++++++++++++------
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index a6090154b2ab..a01ebb630abc 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -207,6 +207,7 @@ struct css_set {
*/
struct list_head tasks;
struct list_head mg_tasks;
+ struct list_head dying_tasks;
/* all css_task_iters currently walking this cset */
struct list_head task_iters;
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index f85e65b248b7..b4854b48a4f3 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -60,6 +60,7 @@ struct css_task_iter {
struct list_head *task_pos;
struct list_head *tasks_head;
struct list_head *mg_tasks_head;
+ struct list_head *dying_tasks_head;
struct css_set *cur_cset;
struct css_set *cur_dcset;
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index c093e187f6a6..89dd464f6862 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -673,6 +673,7 @@ struct css_set init_css_set = {
.dom_cset = &init_css_set,
.tasks = LIST_HEAD_INIT(init_css_set.tasks),
.mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks),
+ .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks),
.task_iters = LIST_HEAD_INIT(init_css_set.task_iters),
.threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets),
.cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links),
@@ -1145,6 +1146,7 @@ static struct css_set *find_css_set(struct css_set *old_cset,
cset->dom_cset = cset;
INIT_LIST_HEAD(&cset->tasks);
INIT_LIST_HEAD(&cset->mg_tasks);
+ INIT_LIST_HEAD(&cset->dying_tasks);
INIT_LIST_HEAD(&cset->task_iters);
INIT_LIST_HEAD(&cset->threaded_csets);
INIT_HLIST_NODE(&cset->hlist);
@@ -4152,15 +4154,18 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
it->task_pos = NULL;
return;
}
- } while (!css_set_populated(cset));
+ } while (!css_set_populated(cset) && !list_empty(&cset->dying_tasks));
if (!list_empty(&cset->tasks))
it->task_pos = cset->tasks.next;
- else
+ else if (!list_empty(&cset->mg_tasks))
it->task_pos = cset->mg_tasks.next;
+ else
+ it->task_pos = cset->dying_tasks.next;
it->tasks_head = &cset->tasks;
it->mg_tasks_head = &cset->mg_tasks;
+ it->dying_tasks_head = &cset->dying_tasks;
/*
* We don't keep css_sets locked across iteration steps and thus
@@ -4199,6 +4204,8 @@ static void css_task_iter_skip(struct css_task_iter *it,
static void css_task_iter_advance(struct css_task_iter *it)
{
+ struct task_struct *task;
+
lockdep_assert_held(&css_set_lock);
repeat:
if (it->task_pos) {
@@ -4215,17 +4222,32 @@ static void css_task_iter_advance(struct css_task_iter *it)
if (it->task_pos == it->tasks_head)
it->task_pos = it->mg_tasks_head->next;
if (it->task_pos == it->mg_tasks_head)
+ it->task_pos = it->dying_tasks_head->next;
+ if (it->task_pos == it->dying_tasks_head)
css_task_iter_advance_css_set(it);
} else {
/* called from start, proceed to the first cset */
css_task_iter_advance_css_set(it);
}
- /* if PROCS, skip over tasks which aren't group leaders */
- if ((it->flags & CSS_TASK_ITER_PROCS) && it->task_pos &&
- !thread_group_leader(list_entry(it->task_pos, struct task_struct,
- cg_list)))
- goto repeat;
+ if (!it->task_pos)
+ return;
+
+ task = list_entry(it->task_pos, struct task_struct, cg_list);
+
+ if (it->flags & CSS_TASK_ITER_PROCS) {
+ /* if PROCS, skip over tasks which aren't group leaders */
+ if (!thread_group_leader(task))
+ goto repeat;
+
+ /* and dying leaders w/o live member threads */
+ if (!atomic_read(&task->signal->live))
+ goto repeat;
+ } else {
+ /* skip all dying ones */
+ if (task->flags & PF_EXITING)
+ goto repeat;
+ }
}
/**
@@ -5682,6 +5704,7 @@ void cgroup_exit(struct task_struct *tsk)
if (!list_empty(&tsk->cg_list)) {
spin_lock_irq(&css_set_lock);
css_set_move_task(tsk, cset, NULL, false);
+ list_add_tail(&tsk->cg_list, &cset->dying_tasks);
cset->nr_tasks--;
spin_unlock_irq(&css_set_lock);
} else {
@@ -5702,6 +5725,13 @@ void cgroup_release(struct task_struct *task)
do_each_subsys_mask(ss, ssid, have_release_callback) {
ss->release(task);
} while_each_subsys_mask();
+
+ if (use_task_css_set_links) {
+ spin_lock_irq(&css_set_lock);
+ css_set_skip_task_iters(task_css_set(task), task);
+ list_del_init(&task->cg_list);
+ spin_unlock_irq(&css_set_lock);
+ }
}
void cgroup_free(struct task_struct *task)
--
2.22.0

View file

@ -0,0 +1,45 @@
From 0a9abd277819058b6beafa40bfe0a56f19edec38 Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Wed, 5 Jun 2019 09:54:34 -0700
Subject: [PATCH 810/826] cgroup: css_task_iter_skip()'d iterators must be
advanced before accessed
commit cee0c33c546a93957a52ae9ab6bebadbee765ec5 upstream.
b636fd38dc40 ("cgroup: Implement css_task_iter_skip()") introduced
css_task_iter_skip() which is used to fix task iterations skipping
dying threadgroup leaders with live threads. Skipping is implemented
as a subportion of full advancing but css_task_iter_next() forgot to
fully advance a skipped iterator before determining the next task to
visit causing it to return invalid task pointers.
Fix it by making css_task_iter_next() fully advance the iterator if it
has been skipped since the previous iteration.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: syzbot
Link: http://lkml.kernel.org/r/00000000000097025d058a7fd785@google.com
Fixes: b636fd38dc40 ("cgroup: Implement css_task_iter_skip()")
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/cgroup/cgroup.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 89dd464f6862..ddde75bae7af 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -4303,6 +4303,10 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it)
spin_lock_irq(&css_set_lock);
+ /* @it may be half-advanced by skips, finish advancing */
+ if (it->flags & CSS_TASK_ITER_SKIPPED)
+ css_task_iter_advance(it);
+
if (it->task_pos) {
it->cur_task = list_entry(it->task_pos, struct task_struct,
cg_list);
--
2.22.0

View file

@ -0,0 +1,39 @@
From ebda41dd170fd160e44f97d7a2a215ae9d0009b1 Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Mon, 10 Jun 2019 09:08:27 -0700
Subject: [PATCH 811/826] cgroup: Fix css_task_iter_advance_css_set() cset skip
condition
commit c596687a008b579c503afb7a64fcacc7270fae9e upstream.
While adding handling for dying task group leaders c03cd7738a83
("cgroup: Include dying leaders with live threads in PROCS
iterations") added an inverted cset skip condition to
css_task_iter_advance_css_set(). It should skip cset if it's
completely empty but was incorrectly testing for the inverse condition
for the dying_tasks list. Fix it.
Signed-off-by: Tejun Heo <tj@kernel.org>
Fixes: c03cd7738a83 ("cgroup: Include dying leaders with live threads in PROCS iterations")
Reported-by: syzbot+d4bba5ccd4f9a2a68681@syzkaller.appspotmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/cgroup/cgroup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index ddde75bae7af..78ef274b036e 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -4154,7 +4154,7 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
it->task_pos = NULL;
return;
}
- } while (!css_set_populated(cset) && !list_empty(&cset->dying_tasks));
+ } while (!css_set_populated(cset) && list_empty(&cset->dying_tasks));
if (!list_empty(&cset->tasks))
it->task_pos = cset->tasks.next;
--
2.22.0

View file

@ -0,0 +1,56 @@
From 48fcdaba7b0d31e59f01ce96b4f53e8149787d1a Mon Sep 17 00:00:00 2001
From: Lukas Wunner <lukas@wunner.de>
Date: Wed, 3 Jul 2019 12:29:31 +0200
Subject: [PATCH 812/826] spi: bcm2835: Fix 3-wire mode if DMA is enabled
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit 8d8bef50365847134b51c1ec46786bc2873e4e47 upstream.
Commit 6935224da248 ("spi: bcm2835: enable support of 3-wire mode")
added 3-wire support to the BCM2835 SPI driver by setting the REN bit
(Read Enable) in the CS register when receiving data. The REN bit puts
the transmitter in high-impedance state. The driver recognizes that
data is to be received by checking whether the rx_buf of a transfer is
non-NULL.
Commit 3ecd37edaa2a ("spi: bcm2835: enable dma modes for transfers
meeting certain conditions") subsequently broke 3-wire support because
it set the SPI_MASTER_MUST_RX flag which causes spi_map_msg() to replace
rx_buf with a dummy buffer if it is NULL. As a result, rx_buf is
*always* non-NULL if DMA is enabled.
Reinstate 3-wire support by not only checking whether rx_buf is non-NULL,
but also checking that it is not the dummy buffer.
Fixes: 3ecd37edaa2a ("spi: bcm2835: enable dma modes for transfers meeting certain conditions")
Reported-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: stable@vger.kernel.org # v4.2+
Cc: Martin Sperl <kernel@martin.sperl.org>
Acked-by: Stefan Wahren <wahrenst@gmx.net>
Link: https://lore.kernel.org/r/328318841455e505370ef8ecad97b646c033dc8a.1562148527.git.lukas@wunner.de
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/spi/spi-bcm2835.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 25abf2d1732a..eab27d41ba83 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -554,7 +554,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
/* handle all the 3-wire mode */
- if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
+ if (spi->mode & SPI_3WIRE && tfr->rx_buf &&
+ tfr->rx_buf != master->dummy_rx)
cs |= BCM2835_SPI_CS_REN;
else
cs &= ~BCM2835_SPI_CS_REN;
--
2.22.0

View file

@ -0,0 +1,32 @@
From 167347104c80c4a61e0eff9de19682f5342477e1 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Fri, 3 Aug 2018 11:22:27 +0200
Subject: [PATCH 814/826] drm/vc4: Fix TILE_Y_OFFSET definitions
Y_OFFSET field starts at bit 8 not 7.
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180803092231.26446-1-boris.brezillon@bootlin.com
---
drivers/gpu/drm/vc4/vc4_regs.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index d6864fa4bd14..ccbd6b377ffe 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -1043,8 +1043,8 @@ enum hvs_pixel_format {
#define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
#define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
/* Y offset within a tile. */
-#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7)
-#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7
+#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 8)
+#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 8
#define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
#define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
--
2.22.0

View file

@ -0,0 +1,33 @@
From 904a5b062a6fb566da579b5ccc4c11ee93d825e3 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Fri, 3 Aug 2018 11:22:28 +0200
Subject: [PATCH 815/826] drm/vc4: Define missing PITCH0_SINK_PIX field
This is needed to support X/Y negative placement of planes using
T-format buffers.
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180803092231.26446-2-boris.brezillon@bootlin.com
---
drivers/gpu/drm/vc4/vc4_regs.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index ccbd6b377ffe..931088014272 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -1037,6 +1037,10 @@ enum hvs_pixel_format {
#define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0)
#define SCALER_TILE_HEIGHT_SHIFT 0
+/* Common PITCH0 fields */
+#define SCALER_PITCH0_SINK_PIX_MASK VC4_MASK(31, 26)
+#define SCALER_PITCH0_SINK_PIX_SHIFT 26
+
/* PITCH0 fields for T-tiled. */
#define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
#define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
--
2.22.0

View file

@ -0,0 +1,161 @@
From 299176a3472b3dcec51a29cf561f7fee804d0614 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@bootlin.com>
Date: Fri, 3 Aug 2018 11:22:29 +0200
Subject: [PATCH 816/826] drm/vc4: Use drm_atomic_helper_check_plane_state() to
simplify the logic
drm_atomic_helper_check_plane_state() takes care of checking the
scaling capabilities and calculating the clipped X/Y offsets for us.
Rely on this function instead of open-coding the logic.
Incidentally, it seems to fix a problem we had with negative X/Y
positioning of YUV planes.
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20180803092231.26446-3-boris.brezillon@bootlin.com
---
drivers/gpu/drm/vc4/vc4_plane.c | 103 ++++++++++++++++----------------
1 file changed, 52 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 3c3d97dbbb51..09186d69753b 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -313,31 +313,59 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
u32 subpixel_src_mask = (1 << 16) - 1;
u32 format = fb->format->format;
int num_planes = fb->format->num_planes;
- u32 h_subsample = 1;
- u32 v_subsample = 1;
- int ret;
- int i;
+ int min_scale = 1, max_scale = INT_MAX;
+ struct drm_crtc_state *crtc_state;
+ u32 h_subsample, v_subsample;
+ int i, ret;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+ state->crtc);
+ if (!crtc_state) {
+ DRM_DEBUG_KMS("Invalid crtc state\n");
+ return -EINVAL;
+ }
+
+ /* No configuring scaling on the cursor plane, since it gets
+ * non-vblank-synced updates, and scaling requires LBM changes which
+ * have to be vblank-synced.
+ */
+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+ min_scale = DRM_PLANE_HELPER_NO_SCALING;
+ max_scale = DRM_PLANE_HELPER_NO_SCALING;
+ } else {
+ min_scale = 1;
+ max_scale = INT_MAX;
+ }
+
+ ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+ min_scale, max_scale,
+ true, true);
+ if (ret)
+ return ret;
+
+ h_subsample = drm_format_horz_chroma_subsampling(format);
+ v_subsample = drm_format_vert_chroma_subsampling(format);
for (i = 0; i < num_planes; i++)
vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
/* We don't support subpixel source positioning for scaling. */
- if ((state->src_x & subpixel_src_mask) ||
- (state->src_y & subpixel_src_mask) ||
- (state->src_w & subpixel_src_mask) ||
- (state->src_h & subpixel_src_mask)) {
+ if ((state->src.x1 & subpixel_src_mask) ||
+ (state->src.x2 & subpixel_src_mask) ||
+ (state->src.y1 & subpixel_src_mask) ||
+ (state->src.y2 & subpixel_src_mask)) {
return -EINVAL;
}
- vc4_state->src_x = state->src_x >> 16;
- vc4_state->src_y = state->src_y >> 16;
- vc4_state->src_w[0] = state->src_w >> 16;
- vc4_state->src_h[0] = state->src_h >> 16;
+ vc4_state->src_x = state->src.x1 >> 16;
+ vc4_state->src_y = state->src.y1 >> 16;
+ vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
+ vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
- vc4_state->crtc_x = state->crtc_x;
- vc4_state->crtc_y = state->crtc_y;
- vc4_state->crtc_w = state->crtc_w;
- vc4_state->crtc_h = state->crtc_h;
+ vc4_state->crtc_x = state->dst.x1;
+ vc4_state->crtc_y = state->dst.y1;
+ vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
+ vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
ret = vc4_plane_margins_adj(state);
if (ret)
@@ -354,8 +382,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
if (num_planes > 1) {
vc4_state->is_yuv = true;
- h_subsample = drm_format_horz_chroma_subsampling(format);
- v_subsample = drm_format_vert_chroma_subsampling(format);
vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
@@ -380,39 +406,14 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
vc4_state->y_scaling[1] = VC4_SCALING_NONE;
}
- /* No configuring scaling on the cursor plane, since it gets
- non-vblank-synced updates, and scaling requires requires
- LBM changes which have to be vblank-synced.
- */
- if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
- return -EINVAL;
-
- /* Clamp the on-screen start x/y to 0. The hardware doesn't
- * support negative y, and negative x wastes bandwidth.
- */
- if (vc4_state->crtc_x < 0) {
- for (i = 0; i < num_planes; i++) {
- u32 cpp = fb->format->cpp[i];
- u32 subs = ((i == 0) ? 1 : h_subsample);
-
- vc4_state->offsets[i] += (cpp *
- (-vc4_state->crtc_x) / subs);
- }
- vc4_state->src_w[0] += vc4_state->crtc_x;
- vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
- vc4_state->crtc_x = 0;
- }
-
- if (vc4_state->crtc_y < 0) {
- for (i = 0; i < num_planes; i++) {
- u32 subs = ((i == 0) ? 1 : v_subsample);
-
- vc4_state->offsets[i] += (fb->pitches[i] *
- (-vc4_state->crtc_y) / subs);
- }
- vc4_state->src_h[0] += vc4_state->crtc_y;
- vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
- vc4_state->crtc_y = 0;
+ /* Adjust the base pointer to the first pixel to be scanned out. */
+ for (i = 0; i < num_planes; i++) {
+ vc4_state->offsets[i] += (vc4_state->src_y /
+ (i ? v_subsample : 1)) *
+ fb->pitches[i];
+ vc4_state->offsets[i] += (vc4_state->src_x /
+ (i ? h_subsample : 1)) *
+ fb->format->cpp[i];
}
return 0;
--
2.22.0

View file

@ -0,0 +1,78 @@
From ed9e15008174c71274bda7bfd6168ba8b6b0f5f8 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@bootlin.com>
Date: Fri, 3 Aug 2018 11:22:30 +0200
Subject: [PATCH 817/826] drm/vc4: Move ->offsets[] adjustment out of
setup_clipping_and_scaling()
The offset adjustment depends on the framebuffer modified, so let's
just move this operation in the DRM_FORMAT_MOD_LINEAR case inside
vc4_plane_mode_set().
This we'll be able to fix offset calculation for
DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED and DRM_FORMAT_MOD_BROADCOM_SANDXXX.
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20180803092231.26446-4-boris.brezillon@bootlin.com
---
drivers/gpu/drm/vc4/vc4_plane.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 09186d69753b..42e96641f1ac 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -406,16 +406,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
vc4_state->y_scaling[1] = VC4_SCALING_NONE;
}
- /* Adjust the base pointer to the first pixel to be scanned out. */
- for (i = 0; i < num_planes; i++) {
- vc4_state->offsets[i] += (vc4_state->src_y /
- (i ? v_subsample : 1)) *
- fb->pitches[i];
- vc4_state->offsets[i] += (vc4_state->src_x /
- (i ? h_subsample : 1)) *
- fb->format->cpp[i];
- }
-
return 0;
}
@@ -523,6 +513,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
int num_planes = drm_format_num_planes(format->drm);
+ u32 h_subsample, v_subsample;
bool mix_plane_alpha;
bool covers_screen;
u32 scl0, scl1, pitch0;
@@ -568,10 +559,25 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
scl1 = vc4_get_scl_field(state, 0);
}
+ h_subsample = drm_format_horz_chroma_subsampling(format->drm);
+ v_subsample = drm_format_vert_chroma_subsampling(format->drm);
+
switch (base_format_mod) {
case DRM_FORMAT_MOD_LINEAR:
tiling = SCALER_CTL0_TILING_LINEAR;
pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
+
+ /* Adjust the base pointer to the first pixel to be scanned
+ * out.
+ */
+ for (i = 0; i < num_planes; i++) {
+ vc4_state->offsets[i] += vc4_state->src_y /
+ (i ? v_subsample : 1) *
+ fb->pitches[i];
+ vc4_state->offsets[i] += vc4_state->src_x /
+ (i ? h_subsample : 1) *
+ fb->format->cpp[i];
+ }
break;
case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
--
2.22.0

View file

@ -0,0 +1,91 @@
From c3f1afdbcfef63fa720f6143f1ee417d8d87d4e7 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@bootlin.com>
Date: Fri, 3 Aug 2018 11:22:31 +0200
Subject: [PATCH 818/826] drm/vc4: Fix X/Y positioning of planes using T_TILES
modifier
X/Y positioning of T-format buffers is quite tricky and the current
implementation was failing to position a plane using this format
correctly when the CRTC X, Y or both X and Y offsets were negative.
It was also failing when the SRC X/Y offsets were != 0.
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20180803092231.26446-5-boris.brezillon@bootlin.com
---
drivers/gpu/drm/vc4/vc4_plane.c | 50 ++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 42e96641f1ac..267f8125d86f 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -578,22 +578,58 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
(i ? h_subsample : 1) *
fb->format->cpp[i];
}
+
break;
case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
- /* For T-tiled, the FB pitch is "how many bytes from
- * one row to the next, such that pitch * tile_h ==
- * tile_size * tiles_per_row."
- */
u32 tile_size_shift = 12; /* T tiles are 4kb */
+ /* Whole-tile offsets, mostly for setting the pitch. */
+ u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
+ u32 tile_w_mask = (1 << tile_w_shift) - 1;
+ /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
+ * the height (in pixels) of a 4k tile.
+ */
+ u32 tile_h_mask = (2 << tile_h_shift) - 1;
+ /* For T-tiled, the FB pitch is "how many bytes from one row to
+ * the next, such that
+ *
+ * pitch * tile_h == tile_size * tiles_per_row
+ */
u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
+ u32 tiles_l = vc4_state->src_x >> tile_w_shift;
+ u32 tiles_r = tiles_w - tiles_l;
+ u32 tiles_t = vc4_state->src_y >> tile_h_shift;
+ /* Intra-tile offsets, which modify the base address (the
+ * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
+ * base address).
+ */
+ u32 tile_y = (vc4_state->src_y >> 4) & 1;
+ u32 subtile_y = (vc4_state->src_y >> 2) & 3;
+ u32 utile_y = vc4_state->src_y & 3;
+ u32 x_off = vc4_state->src_x & tile_w_mask;
+ u32 y_off = vc4_state->src_y & tile_h_mask;
tiling = SCALER_CTL0_TILING_256B_OR_T;
+ pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
+ VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
+ VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
+ VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
+ vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
+ vc4_state->offsets[0] += subtile_y << 8;
+ vc4_state->offsets[0] += utile_y << 4;
+
+ /* Rows of tiles alternate left-to-right and right-to-left. */
+ if (tiles_t & 1) {
+ pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
+ vc4_state->offsets[0] += (tiles_w - tiles_l) <<
+ tile_size_shift;
+ vc4_state->offsets[0] -= (1 + !tile_y) << 10;
+ } else {
+ vc4_state->offsets[0] += tiles_l << tile_size_shift;
+ vc4_state->offsets[0] += tile_y << 10;
+ }
- pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
- VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
- VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
break;
}
--
2.22.0

View file

@ -0,0 +1,62 @@
From f1c1b67b26ed3cb789037d1c844d4105deaa3cfd Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@bootlin.com>
Date: Thu, 15 Nov 2018 11:58:51 +0100
Subject: [PATCH 819/826] drm/vc4: Fix NULL pointer dereference in the async
update path
vc4_plane_atomic_async_update() calls vc4_plane_atomic_check()
which in turn calls vc4_plane_setup_clipping_and_scaling(), and since
commit 58a6a36fe8e0 ("drm/vc4: Use
drm_atomic_helper_check_plane_state() to simplify the logic"), this
function accesses plane_state->state which will be NULL when called
from the async update path because we're passing the current plane
state, and plane_state->state has been assigned to NULL in
drm_atomic_helper_swap_state().
Pass the new state instead of the current one (the new state has
->state set to a non-NULL value).
Fixes: 58a6a36fe8e0 ("drm/vc4: Use drm_atomic_helper_check_plane_state() to simplify the logic")
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20181115105852.9844-1-boris.brezillon@bootlin.com
---
drivers/gpu/drm/vc4/vc4_plane.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 267f8125d86f..ce2749d90dd0 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -905,7 +905,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
static void vc4_plane_atomic_async_update(struct drm_plane *plane,
struct drm_plane_state *state)
{
- struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
+ struct vc4_plane_state *vc4_state, *new_vc4_state;
if (plane->state->fb != state->fb) {
vc4_plane_async_set_fb(plane, state->fb);
@@ -927,7 +927,18 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
plane->state->src_y = state->src_y;
/* Update the display list based on the new crtc_x/y. */
- vc4_plane_atomic_check(plane, plane->state);
+ vc4_plane_atomic_check(plane, state);
+
+ new_vc4_state = to_vc4_plane_state(state);
+ vc4_state = to_vc4_plane_state(plane->state);
+
+ /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
+ vc4_state->dlist[vc4_state->pos0_offset] =
+ new_vc4_state->dlist[vc4_state->pos0_offset];
+ vc4_state->dlist[vc4_state->pos2_offset] =
+ new_vc4_state->dlist[vc4_state->pos2_offset];
+ vc4_state->dlist[vc4_state->ptr0_offset] =
+ new_vc4_state->dlist[vc4_state->ptr0_offset];
/* Note that we can't just call vc4_plane_write_dlist()
* because that would smash the context data that the HVS is
--
2.22.0

View file

@ -0,0 +1,72 @@
From 1f8e54151926498bd1f462d758301669cb354fd0 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 12 Aug 2019 15:48:39 +0100
Subject: [PATCH 822/826] ARM: dts: bcm2711-rpi-4-b: I2C aliases and pulls
The I2C interface nodes need aliases to give them fixed bus numbers,
and setting the pulls on the GPIOs (particularly 9-13) increases the
chances of the bus working with weak or absent external pulls.
See: https://www.raspberrypi.org/forums/posting.php?mode=reply&f=107&t=248439
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
index 9b5c4f8a4d17..18c0f9599d3a 100644
--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
@@ -23,6 +23,10 @@
mmc0 = &emmc2;
mmc1 = &mmcnr;
mmc2 = &sdhost;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
/delete-property/ ethernet;
/delete-property/ intc;
ethernet0 = &genet;
@@ -207,31 +211,37 @@
i2c0_pins: i2c0 {
brcm,pins = <0 1>;
brcm,function = <BCM2835_FSEL_ALT0>;
+ brcm,pull = <BCM2835_PUD_UP>;
};
i2c1_pins: i2c1 {
brcm,pins = <2 3>;
brcm,function = <BCM2835_FSEL_ALT0>;
+ brcm,pull = <BCM2835_PUD_UP>;
};
i2c3_pins: i2c3 {
brcm,pins = <4 5>;
brcm,function = <BCM2835_FSEL_ALT5>;
+ brcm,pull = <BCM2835_PUD_UP>;
};
i2c4_pins: i2c4 {
brcm,pins = <8 9>;
brcm,function = <BCM2835_FSEL_ALT5>;
+ brcm,pull = <BCM2835_PUD_UP>;
};
i2c5_pins: i2c5 {
brcm,pins = <12 13>;
brcm,function = <BCM2835_FSEL_ALT5>;
+ brcm,pull = <BCM2835_PUD_UP>;
};
i2c6_pins: i2c6 {
brcm,pins = <22 23>;
brcm,function = <BCM2835_FSEL_ALT5>;
+ brcm,pull = <BCM2835_PUD_UP>;
};
i2s_pins: i2s {
--
2.22.0

View file

@ -0,0 +1,67 @@
From 5f945aad8e7668a6f59b281c60aad87524a32a15 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.org>
Date: Tue, 13 Aug 2019 15:53:29 +0100
Subject: [PATCH 823/826] xhci: Use more event ring segment table entries
Users have reported log spam created by "Event Ring Full" xHC event
TRBs. These are caused by interrupt latency in conjunction with a very
busy set of devices on the bus. The errors are benign, but throughput
will suffer as the xHC will pause processing of transfers until the
event ring is drained by the kernel. Expand the number of event TRB slots
available by increasing the number of event ring segments in the ERST.
Controllers have a hardware-defined limit as to the number of ERST
entries they can process, so make the actual number in use
min(ERST_MAX_SEGS, hw_max).
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
---
drivers/usb/host/xhci-mem.c | 8 +++++---
drivers/usb/host/xhci.h | 4 ++--
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index b1f27aa38b10..7e417b71d24c 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -2491,9 +2491,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* Event ring setup: Allocate a normal ring, but also setup
* the event ring segment table (ERST). Section 4.9.3.
*/
+ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2);
+ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
- 0, flags);
+ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT,
+ 0, flags);
if (!xhci->event_ring)
goto fail;
if (xhci_check_trb_in_td_math(xhci) < 0)
@@ -2506,7 +2508,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/* set ERST count with the number of entries in the segment table */
val = readl(&xhci->ir_set->erst_size);
val &= ERST_SIZE_MASK;
- val |= ERST_NUM_SEGS;
+ val |= val2;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"// Write ERST size = %i to ir_set 0 (some bits preserved)",
val);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3a6c451777e7..ec515c563a37 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1643,8 +1643,8 @@ struct urb_priv {
* Each segment table entry is 4*32bits long. 1K seems like an ok size:
* (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
* meaning 64 ring segments.
- * Initial allocated size of the ERST, in number of entries */
-#define ERST_NUM_SEGS 1
+ * Maximum number of segments in the ERST */
+#define ERST_MAX_SEGS 8
/* Initial allocated size of the ERST, in number of entries */
#define ERST_SIZE 64
/* Initial number of event segment rings allocated */
--
2.22.0

View file

@ -0,0 +1,64 @@
From c0e4ca17457d6669a263e86a88f0036875fc019e Mon Sep 17 00:00:00 2001
From: P33M <2474547+P33M@users.noreply.github.com>
Date: Wed, 14 Aug 2019 14:35:50 +0100
Subject: [PATCH 824/826] dwc_otg: use align_buf for small IN control transfers
(#3150)
The hardware will do a 4-byte write to memory on any IN packet received
that is between 1 and 3 bytes long. This tramples memory in the uvcvideo
driver, as it uses a sequence of 1- and 2-byte control transfers to
query the min/max/range/step of each individual camera control and
gives us buffers that are offsets into a struct.
Catch small control transfers in the data phase and use the align_buf
to bounce the correct number of bytes into the URB's buffer.
In general, short packets on non-control endpoints should be OK as URBs
should have enough buffer space for a wMaxPacket size transfer.
See: https://github.com/raspberrypi/linux/issues/3148
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
---
drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
index cdfb9a6b7c59..9f2cd510c301 100644
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
@@ -1182,6 +1182,7 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
dwc_otg_qtd_t *qtd;
dwc_otg_hcd_urb_t *urb;
void* ptr = NULL;
+ uint16_t wLength;
uint32_t intr_enable;
unsigned long flags;
gintmsk_data_t gintmsk = { .d32 = 0, };
@@ -1293,6 +1294,23 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
break;
case DWC_OTG_CONTROL_DATA:
DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
+ /*
+ * Hardware bug: small IN packets with length < 4
+ * cause a 4-byte write to memory. We can only catch
+ * the case where we know a short packet is going to be
+ * returned in a control transfer, as the length is
+ * specified in the setup packet. This is only an issue
+ * for drivers that insist on packing a device's various
+ * properties into a struct and querying them one at a
+ * time (uvcvideo).
+ * Force the use of align_buf so that the subsequent
+ * memcpy puts the right number of bytes in the URB's
+ * buffer.
+ */
+ wLength = ((uint16_t *)urb->setup_packet)[3];
+ if (hc->ep_is_in && wLength < 4)
+ ptr = hc->xfer_buff;
+
hc->data_pid_start = qtd->data_toggle;
break;
case DWC_OTG_CONTROL_STATUS:
--
2.22.0

View file

@ -0,0 +1,834 @@
From ea2c11a187c0e248343452846457b94715e04969 Mon Sep 17 00:00:00 2001
From: yaroslavros <yaroslavros@gmail.com>
Date: Wed, 14 Aug 2019 15:22:55 +0100
Subject: [PATCH 825/826] Ported pcie-brcmstb bounce buffer implementation to
ARM64. (#3144)
Ported pcie-brcmstb bounce buffer implementation to ARM64.
This enables full 4G RAM usage on Raspberry Pi in 64-bit mode.
Signed-off-by: Yaroslav Rosomakho <yaroslavros@gmail.com>
---
arch/arm64/include/asm/dma-mapping.h | 21 +
arch/arm64/mm/dma-mapping.c | 50 ++
drivers/pci/controller/Makefile | 3 +
drivers/pci/controller/pcie-brcmstb-bounce.h | 2 +-
.../pci/controller/pcie-brcmstb-bounce64.c | 576 ++++++++++++++++++
drivers/pci/controller/pcie-brcmstb.c | 30 +-
6 files changed, 658 insertions(+), 24 deletions(-)
create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce64.c
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index b7847eb8a7bb..9195e524cb08 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -24,6 +24,27 @@
#include <xen/xen.h>
#include <asm/xen/hypervisor.h>
+extern void *arm64_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+ gfp_t gfp, unsigned long attrs);
+extern void arm64_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, unsigned long attrs);
+extern int arm64_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ unsigned long attrs);
+extern int arm64_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ unsigned long attrs);
+extern int arm64_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir, unsigned long attrs);
+extern void arm64_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int,
+ enum dma_data_direction dir, unsigned long attrs);
+extern void arm64_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir);
+extern void arm64_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir);
+
+
+
extern const struct dma_map_ops dummy_dma_ops;
static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index d3a5bb16f0b2..b1f6d4e1f464 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -138,6 +138,12 @@ static void *__dma_alloc(struct device *dev, size_t size,
return NULL;
}
+void *arm64_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+ gfp_t gfp, unsigned long attrs)
+{
+ return __dma_alloc(dev, size, handle, gfp, attrs);
+}
+
static void __dma_free(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
unsigned long attrs)
@@ -154,6 +160,12 @@ static void __dma_free(struct device *dev, size_t size,
swiotlb_free(dev, size, swiotlb_addr, dma_handle, attrs);
}
+void arm64_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, unsigned long attrs)
+{
+ __dma_free(dev, size, cpu_addr, handle, attrs);
+}
+
static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
@@ -197,6 +209,12 @@ static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
return ret;
}
+int arm64_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ return __swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
+}
+
static void __swiotlb_unmap_sg_attrs(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir,
@@ -213,6 +231,12 @@ static void __swiotlb_unmap_sg_attrs(struct device *dev,
swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
}
+void arm64_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ __swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
+}
+
static void __swiotlb_sync_single_for_cpu(struct device *dev,
dma_addr_t dev_addr, size_t size,
enum dma_data_direction dir)
@@ -245,6 +269,12 @@ static void __swiotlb_sync_sg_for_cpu(struct device *dev,
swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
}
+void arm64_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ __swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
+}
+
static void __swiotlb_sync_sg_for_device(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir)
@@ -259,6 +289,12 @@ static void __swiotlb_sync_sg_for_device(struct device *dev,
sg->length, dir);
}
+void arm64_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ __swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
+}
+
static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
unsigned long pfn, size_t size)
{
@@ -294,6 +330,13 @@ static int __swiotlb_mmap(struct device *dev,
return __swiotlb_mmap_pfn(vma, pfn, size);
}
+int arm64_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ unsigned long attrs)
+{
+ return __swiotlb_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
+
static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
struct page *page, size_t size)
{
@@ -314,6 +357,13 @@ static int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
return __swiotlb_get_sgtable_page(sgt, page, size);
}
+int arm64_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ unsigned long attrs)
+{
+ return __swiotlb_get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs);
+}
+
static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
{
if (swiotlb)
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index c40b7b982ea4..71be2a0a7e68 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -32,6 +32,9 @@ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
ifdef CONFIG_ARM
obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
endif
+ifdef CONFIG_ARM64
+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce64.o
+endif
obj-$(CONFIG_VMD) += vmd.o
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
diff --git a/drivers/pci/controller/pcie-brcmstb-bounce.h b/drivers/pci/controller/pcie-brcmstb-bounce.h
index 2fe20a14d035..7caa0781329b 100644
--- a/drivers/pci/controller/pcie-brcmstb-bounce.h
+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
@@ -6,7 +6,7 @@
#ifndef _PCIE_BRCMSTB_BOUNCE_H
#define _PCIE_BRCMSTB_BOUNCE_H
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
dma_addr_t threshold);
diff --git a/drivers/pci/controller/pcie-brcmstb-bounce64.c b/drivers/pci/controller/pcie-brcmstb-bounce64.c
new file mode 100644
index 000000000000..d9f1a46fc331
--- /dev/null
+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
@@ -0,0 +1,576 @@
+/*
+ * This code started out as a version of arch/arm/common/dmabounce.c,
+ * modified to cope with highmem pages. Now it has been changed heavily -
+ * it now preallocates a large block (currently 4MB) and carves it up
+ * sequentially in ring fashion, and DMA is used to copy the data - to the
+ * point where very little of the original remains.
+ *
+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
+ *
+ * Original version by Brad Parker (brad@heeltoe.com)
+ * Re-written by Christopher Hoover <ch@murgatroid.com>
+ * Made generic by Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Hewlett Packard Company.
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/page-flags.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-direct.h>
+#include <linux/dmapool.h>
+#include <linux/list.h>
+#include <linux/scatterlist.h>
+#include <linux/bitmap.h>
+#include <linux/swiotlb.h>
+
+#include <asm/cacheflush.h>
+
+#define STATS
+
+#ifdef STATS
+#define DO_STATS(X) do { X ; } while (0)
+#else
+#define DO_STATS(X) do { } while (0)
+#endif
+
+/* ************************************************** */
+
+struct safe_buffer {
+ struct list_head node;
+
+ /* original request */
+ size_t size;
+ int direction;
+
+ struct dmabounce_pool *pool;
+ void *safe;
+ dma_addr_t unsafe_dma_addr;
+ dma_addr_t safe_dma_addr;
+};
+
+struct dmabounce_pool {
+ unsigned long pages;
+ void *virt_addr;
+ dma_addr_t dma_addr;
+ unsigned long *alloc_map;
+ unsigned long alloc_pos;
+ spinlock_t lock;
+ struct device *dev;
+ unsigned long num_pages;
+#ifdef STATS
+ size_t max_size;
+ unsigned long num_bufs;
+ unsigned long max_bufs;
+ unsigned long max_pages;
+#endif
+};
+
+struct dmabounce_device_info {
+ struct device *dev;
+ dma_addr_t threshold;
+ struct list_head safe_buffers;
+ struct dmabounce_pool pool;
+ rwlock_t lock;
+#ifdef STATS
+ unsigned long map_count;
+ unsigned long unmap_count;
+ unsigned long sync_dev_count;
+ unsigned long sync_cpu_count;
+ unsigned long fail_count;
+ int attr_res;
+#endif
+};
+
+static struct dmabounce_device_info *g_dmabounce_device_info;
+
+extern int bcm2838_dma40_memcpy_init(void);
+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
+
+#ifdef STATS
+static ssize_t
+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
+ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
+ device_info->map_count,
+ device_info->unmap_count,
+ device_info->sync_dev_count,
+ device_info->sync_cpu_count,
+ device_info->fail_count,
+ device_info->pool.max_size,
+ device_info->pool.num_bufs,
+ device_info->pool.max_bufs,
+ device_info->pool.num_pages * PAGE_SIZE,
+ device_info->pool.max_pages * PAGE_SIZE);
+}
+
+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
+#endif
+
+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
+ unsigned long buffer_size)
+{
+ int ret = -ENOMEM;
+ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
+ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
+ if (!pool->alloc_map)
+ goto err_bitmap;
+ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
+ &pool->dma_addr, GFP_KERNEL);
+ if (!pool->virt_addr)
+ goto err_dmabuf;
+
+ pool->alloc_pos = 0;
+ spin_lock_init(&pool->lock);
+ pool->dev = dev;
+ pool->num_pages = 0;
+
+ DO_STATS(pool->max_size = 0);
+ DO_STATS(pool->num_bufs = 0);
+ DO_STATS(pool->max_bufs = 0);
+ DO_STATS(pool->max_pages = 0);
+
+ return 0;
+
+err_dmabuf:
+ bitmap_free(pool->alloc_map);
+err_bitmap:
+ return ret;
+}
+
+static void bounce_destroy(struct dmabounce_pool *pool)
+{
+ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
+ pool->dma_addr);
+
+ bitmap_free(pool->alloc_map);
+}
+
+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
+ dma_addr_t *dmaaddrp)
+{
+ unsigned long pages;
+ unsigned long flags;
+ unsigned long pos;
+
+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
+
+ DO_STATS(pool->max_size = max(size, pool->max_size));
+
+ spin_lock_irqsave(&pool->lock, flags);
+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
+ pool->alloc_pos, pages, 0);
+ /* If not found, try from the start */
+ if (pos >= pool->pages && pool->alloc_pos)
+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
+ 0, pages, 0);
+
+ if (pos >= pool->pages) {
+ spin_unlock_irqrestore(&pool->lock, flags);
+ return NULL;
+ }
+
+ bitmap_set(pool->alloc_map, pos, pages);
+ pool->alloc_pos = (pos + pages) % pool->pages;
+ pool->num_pages += pages;
+
+ DO_STATS(pool->num_bufs++);
+ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
+ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
+
+ spin_unlock_irqrestore(&pool->lock, flags);
+
+ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
+
+ return pool->virt_addr + pos * PAGE_SIZE;
+}
+
+static void
+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
+{
+ unsigned long pages;
+ unsigned long flags;
+ unsigned long pos;
+
+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
+ pos = (buf - pool->virt_addr)/PAGE_SIZE;
+
+ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
+
+ spin_lock_irqsave(&pool->lock, flags);
+ bitmap_clear(pool->alloc_map, pos, pages);
+ pool->num_pages -= pages;
+ if (pool->num_pages == 0)
+ pool->alloc_pos = 0;
+ DO_STATS(pool->num_bufs--);
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+/* allocate a 'safe' buffer and keep track of it */
+static struct safe_buffer *
+alloc_safe_buffer(struct dmabounce_device_info *device_info,
+ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
+{
+ struct safe_buffer *buf;
+ struct dmabounce_pool *pool = &device_info->pool;
+ struct device *dev = device_info->dev;
+ unsigned long flags;
+
+ /*
+ * Although one might expect this to be called in thread context,
+ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
+ * was previously used to select the appropriate allocation mode,
+ * but this is unsafe.
+ */
+ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
+ if (!buf) {
+ dev_warn(dev, "%s: kmalloc failed\n", __func__);
+ return NULL;
+ }
+
+ buf->unsafe_dma_addr = dma_addr;
+ buf->size = size;
+ buf->direction = dir;
+ buf->pool = pool;
+
+ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
+
+ if (!buf->safe) {
+ dev_warn(dev,
+ "%s: could not alloc dma memory (size=%d)\n",
+ __func__, size);
+ kfree(buf);
+ return NULL;
+ }
+
+ write_lock_irqsave(&device_info->lock, flags);
+ list_add(&buf->node, &device_info->safe_buffers);
+ write_unlock_irqrestore(&device_info->lock, flags);
+
+ return buf;
+}
+
+/* determine if a buffer is from our "safe" pool */
+static struct safe_buffer *
+find_safe_buffer(struct dmabounce_device_info *device_info,
+ dma_addr_t safe_dma_addr)
+{
+ struct safe_buffer *b, *rb = NULL;
+ unsigned long flags;
+
+ read_lock_irqsave(&device_info->lock, flags);
+
+ list_for_each_entry(b, &device_info->safe_buffers, node)
+ if (b->safe_dma_addr <= safe_dma_addr &&
+ b->safe_dma_addr + b->size > safe_dma_addr) {
+ rb = b;
+ break;
+ }
+
+ read_unlock_irqrestore(&device_info->lock, flags);
+ return rb;
+}
+
+static void
+free_safe_buffer(struct dmabounce_device_info *device_info,
+ struct safe_buffer *buf)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&device_info->lock, flags);
+ list_del(&buf->node);
+ write_unlock_irqrestore(&device_info->lock, flags);
+
+ bounce_free(buf->pool, buf->safe, buf->size);
+
+ kfree(buf);
+}
+
+/* ************************************************** */
+
+static struct safe_buffer *
+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
+{
+ if (!dev || !g_dmabounce_device_info)
+ return NULL;
+ if (dma_mapping_error(dev, dma_addr)) {
+ dev_err(dev, "Trying to %s invalid mapping\n", where);
+ return NULL;
+ }
+ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
+}
+
+static dma_addr_t
+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ BUG_ON(buf->size != size);
+ BUG_ON(buf->direction != dir);
+
+ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
+ (u64)buf->safe_dma_addr);
+
+ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
+ size);
+
+ return buf->safe_dma_addr;
+}
+
+static dma_addr_t
+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ BUG_ON(buf->size != size);
+ BUG_ON(buf->direction != dir);
+
+ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
+ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
+ (u64)buf->unsafe_dma_addr);
+
+ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
+ size);
+ }
+ return buf->unsafe_dma_addr;
+}
+
+/* ************************************************** */
+
+/*
+ * see if a buffer address is in an 'unsafe' range. if it is
+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
+ * substitute the safe buffer for the unsafe one.
+ * (basically move the buffer from an unsafe area to a safe one)
+ */
+static dma_addr_t
+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
+ dma_addr_t dma_addr;
+
+ dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
+
+ swiotlb_sync_single_for_device(dev, dma_addr, size, dir);
+ if (!is_device_dma_coherent(dev))
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
+
+ if (device_info && (dma_addr + size) > device_info->threshold) {
+ struct safe_buffer *buf;
+
+ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
+ if (!buf) {
+ DO_STATS(device_info->fail_count++);
+ return (~(dma_addr_t)0x0);
+ }
+
+ DO_STATS(device_info->map_count++);
+
+ dma_addr = map_single(dev, buf, size, dir, attrs);
+ }
+ return dma_addr;
+}
+
+/*
+ * see if a mapped address was really a "safe" buffer and if so, copy
+ * the data from the safe buffer back to the unsafe buffer and free up
+ * the safe buffer. (basically return things back to the way they
+ * should be)
+ */
+static void
+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ struct safe_buffer *buf;
+
+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
+ if (buf) {
+ DO_STATS(g_dmabounce_device_info->unmap_count++);
+ dma_addr = unmap_single(dev, buf, size, dir, attrs);
+ free_safe_buffer(g_dmabounce_device_info, buf);
+ }
+
+ if (!is_device_dma_coherent(dev))
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
+ swiotlb_sync_single_for_cpu(dev, dma_addr, size, dir);
+}
+
+/*
+ * A version of dmabounce_map_page that assumes the mapping has already
+ * been created - intended for streaming operation.
+ */
+static void
+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction dir)
+{
+ struct safe_buffer *buf;
+
+ swiotlb_sync_single_for_device(dev, dma_addr, size, dir);
+ if (!is_device_dma_coherent(dev))
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
+
+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
+ if (buf) {
+ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
+ map_single(dev, buf, size, dir, 0);
+ }
+}
+
+/*
+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
+ * intended for streaming operation.
+ */
+static void
+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir)
+{
+ struct safe_buffer *buf;
+
+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
+ if (buf) {
+ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
+ dma_addr = unmap_single(dev, buf, size, dir, 0);
+ }
+
+ if (!is_device_dma_coherent(dev))
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
+ swiotlb_sync_single_for_cpu(dev, dma_addr, size, dir);
+}
+
+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
+{
+ if (g_dmabounce_device_info)
+ return 0;
+
+ return swiotlb_dma_supported(dev, dma_mask);
+}
+
+static int dmabounce_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return swiotlb_dma_mapping_error(dev, dma_addr);
+}
+
+static const struct dma_map_ops dmabounce_ops = {
+ .alloc = arm64_dma_alloc,
+ .free = arm64_dma_free,
+ .mmap = arm64_dma_mmap,
+ .get_sgtable = arm64_dma_get_sgtable,
+ .map_page = dmabounce_map_page,
+ .unmap_page = dmabounce_unmap_page,
+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
+ .sync_single_for_device = dmabounce_sync_for_device,
+ .map_sg = arm64_dma_map_sg,
+ .unmap_sg = arm64_dma_unmap_sg,
+ .sync_sg_for_cpu = arm64_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = arm64_dma_sync_sg_for_device,
+ .dma_supported = dmabounce_dma_supported,
+ .mapping_error = dmabounce_mapping_error,
+};
+
+int brcm_pcie_bounce_init(struct device *dev,
+ unsigned long buffer_size,
+ dma_addr_t threshold)
+{
+ struct dmabounce_device_info *device_info;
+ int ret;
+
+ /* Only support a single client */
+ if (g_dmabounce_device_info)
+ return -EBUSY;
+
+ ret = bcm2838_dma40_memcpy_init();
+ if (ret)
+ return ret;
+
+ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
+ if (!device_info) {
+ dev_err(dev,
+ "Could not allocated dmabounce_device_info\n");
+ return -ENOMEM;
+ }
+
+ ret = bounce_create(&device_info->pool, dev, buffer_size);
+ if (ret) {
+ dev_err(dev,
+ "dmabounce: could not allocate %ld byte DMA pool\n",
+ buffer_size);
+ goto err_bounce;
+ }
+
+ device_info->dev = dev;
+ device_info->threshold = threshold;
+ INIT_LIST_HEAD(&device_info->safe_buffers);
+ rwlock_init(&device_info->lock);
+
+ DO_STATS(device_info->map_count = 0);
+ DO_STATS(device_info->unmap_count = 0);
+ DO_STATS(device_info->sync_dev_count = 0);
+ DO_STATS(device_info->sync_cpu_count = 0);
+ DO_STATS(device_info->fail_count = 0);
+ DO_STATS(device_info->attr_res =
+ device_create_file(dev, &dev_attr_dmabounce_stats));
+
+ g_dmabounce_device_info = device_info;
+
+ dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
+ buffer_size / 1024, &threshold);
+
+ return 0;
+
+ err_bounce:
+ kfree(device_info);
+ return ret;
+}
+EXPORT_SYMBOL(brcm_pcie_bounce_init);
+
+void brcm_pcie_bounce_uninit(struct device *dev)
+{
+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
+
+ g_dmabounce_device_info = NULL;
+
+ if (!device_info) {
+ dev_warn(dev,
+ "Never registered with dmabounce but attempting"
+ "to unregister!\n");
+ return;
+ }
+
+ if (!list_empty(&device_info->safe_buffers)) {
+ dev_err(dev,
+ "Removing from dmabounce with pending buffers!\n");
+ BUG();
+ }
+
+ bounce_destroy(&device_info->pool);
+
+ DO_STATS(if (device_info->attr_res == 0)
+ device_remove_file(dev, &dev_attr_dmabounce_stats));
+
+ kfree(device_info);
+}
+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
+
+int brcm_pcie_bounce_register_dev(struct device *dev)
+{
+ set_dma_ops(dev, &dmabounce_ops);
+
+ return 0;
+}
+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
+
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index f99ab05ab477..f279ed67e4e1 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -617,28 +617,6 @@ static const struct dma_map_ops brcm_dma_ops = {
static void brcm_set_dma_ops(struct device *dev)
{
- int ret;
-
- if (IS_ENABLED(CONFIG_ARM64)) {
- /*
- * We are going to invoke get_dma_ops(). That
- * function, at this point in time, invokes
- * get_arch_dma_ops(), and for ARM64 that function
- * returns a pointer to dummy_dma_ops. So then we'd
- * like to call arch_setup_dma_ops(), but that isn't
- * exported. Instead, we call of_dma_configure(),
- * which is exported, and this calls
- * arch_setup_dma_ops(). Once we do this the call to
- * get_dma_ops() will work properly because
- * dev->dma_ops will be set.
- */
- ret = of_dma_configure(dev, dev->of_node, true);
- if (ret) {
- dev_err(dev, "of_dma_configure() failed: %d\n", ret);
- return;
- }
- }
-
arch_dma_ops = get_dma_ops(dev);
if (!arch_dma_ops) {
dev_err(dev, "failed to get arch_dma_ops\n");
@@ -657,12 +635,12 @@ static int brcmstb_platform_notifier(struct notifier_block *nb,
extern unsigned long max_pfn;
struct device *dev = __dev;
const char *rc_name = "0000:00:00.0";
+ int ret;
switch (event) {
case BUS_NOTIFY_ADD_DEVICE:
if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
strcmp(dev->kobj.name, rc_name)) {
- int ret;
ret = brcm_pcie_bounce_register_dev(dev);
if (ret) {
@@ -671,6 +649,12 @@ static int brcmstb_platform_notifier(struct notifier_block *nb,
ret);
return ret;
}
+ } else if (IS_ENABLED(CONFIG_ARM64)) {
+ ret = of_dma_configure(dev, dev->of_node, true);
+ if (ret) {
+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
+ return;
+ }
}
brcm_set_dma_ops(dev);
return NOTIFY_OK;
--
2.22.0

View file

@ -0,0 +1,53 @@
From fc5826fb999e0b32900d1f487e90c27a92010214 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 15 Aug 2019 12:02:34 +0100
Subject: [PATCH 826/826] configs: arm64/vcm2711: Enable V3D
Enable the V3D driver, which depends on BCM2835_POWER.
Originally submitted by GitHub user 'phire' in a slightly different
form.
See: https://github.com/raspberrypi/linux/pull/3063
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm64/configs/bcm2711_defconfig | 2 ++
drivers/gpu/drm/v3d/Kconfig | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig
index e06ba27ccb25..200f66c006d6 100644
--- a/arch/arm64/configs/bcm2711_defconfig
+++ b/arch/arm64/configs/bcm2711_defconfig
@@ -791,6 +791,7 @@ CONFIG_DRM_LOAD_EDID_FIRMWARE=y
CONFIG_DRM_UDL=m
CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
+CONFIG_DRM_V3D=m
CONFIG_DRM_VC4=m
CONFIG_DRM_TINYDRM=m
CONFIG_TINYDRM_MI0283QT=m
@@ -1135,6 +1136,7 @@ CONFIG_VIDEO_BCM2835=m
CONFIG_MAILBOX=y
CONFIG_BCM2835_MBOX=y
# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_BCM2835_POWER=y
CONFIG_RASPBERRYPI_POWER=y
CONFIG_EXTCON=m
CONFIG_EXTCON_ARIZONA=m
diff --git a/drivers/gpu/drm/v3d/Kconfig b/drivers/gpu/drm/v3d/Kconfig
index 1552bf552c94..2967459b8fb0 100644
--- a/drivers/gpu/drm/v3d/Kconfig
+++ b/drivers/gpu/drm/v3d/Kconfig
@@ -1,6 +1,6 @@
config DRM_V3D
tristate "Broadcom V3D 3.x and newer"
- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST
+ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST
depends on DRM
depends on COMMON_CLK
depends on MMU
--
2.22.0