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:
parent
e632bdc531
commit
91d60c33e0
88 changed files with 9140 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in a new issue