mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
Update odroidxu4-current to 5.4.176 (#3458)
* Update odroidxu4-current to 5.4.176 * Update odroidxu4-current to 5.4.177
This commit is contained in:
9538
patch/kernel/archive/odroidxu4-5.4/patch-5.4.173-174.patch
Normal file
9538
patch/kernel/archive/odroidxu4-5.4/patch-5.4.173-174.patch
Normal file
File diff suppressed because it is too large
Load Diff
891
patch/kernel/archive/odroidxu4-5.4/patch-5.4.174-175.patch
Normal file
891
patch/kernel/archive/odroidxu4-5.4/patch-5.4.174-175.patch
Normal file
@@ -0,0 +1,891 @@
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 3075f06f77131..2f6c51097d003 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
-SUBLEVEL = 174
|
||||
+SUBLEVEL = 175
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
index 50c64146d4926..af81f386793ca 100644
|
||||
--- a/arch/arm/boot/dts/bcm283x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
@@ -183,6 +183,7 @@
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
+ gpio-ranges = <&gpio 0 0 54>;
|
||||
|
||||
/* Defines pin muxing groups according to
|
||||
* BCM2835-ARM-Peripherals.pdf page 102.
|
||||
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
|
||||
index 08b35587bc6dc..352c102f3459c 100644
|
||||
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
|
||||
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
|
||||
@@ -118,6 +118,9 @@ struct drm_i915_gem_object {
|
||||
|
||||
I915_SELFTEST_DECLARE(struct list_head st_link);
|
||||
|
||||
+ unsigned long flags;
|
||||
+#define I915_BO_WAS_BOUND_BIT 0
|
||||
+
|
||||
/*
|
||||
* Is the object to be mapped as read-only to the GPU
|
||||
* Only honoured if hardware has relevant pte bit
|
||||
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
|
||||
index 18f0ce0135c17..aa63fa0ab575e 100644
|
||||
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
|
||||
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "i915_gem_object.h"
|
||||
#include "i915_scatterlist.h"
|
||||
|
||||
+#include "gt/intel_gt.h"
|
||||
+
|
||||
void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
|
||||
struct sg_table *pages,
|
||||
unsigned int sg_page_sizes)
|
||||
@@ -176,6 +178,14 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
|
||||
__i915_gem_object_reset_page_iter(obj);
|
||||
obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
|
||||
|
||||
+ if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
|
||||
+ struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
+ intel_wakeref_t wakeref;
|
||||
+
|
||||
+ with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref)
|
||||
+ intel_gt_invalidate_tlbs(&i915->gt);
|
||||
+ }
|
||||
+
|
||||
return pages;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
|
||||
index d48ec9a76ed16..c8c070375d298 100644
|
||||
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
|
||||
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
|
||||
@@ -15,6 +15,8 @@ void intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915)
|
||||
|
||||
spin_lock_init(>->irq_lock);
|
||||
|
||||
+ mutex_init(>->tlb_invalidate_lock);
|
||||
+
|
||||
INIT_LIST_HEAD(>->closed_vma);
|
||||
spin_lock_init(>->closed_lock);
|
||||
|
||||
@@ -266,3 +268,100 @@ void intel_gt_driver_late_release(struct intel_gt *gt)
|
||||
intel_uc_driver_late_release(>->uc);
|
||||
intel_gt_fini_reset(gt);
|
||||
}
|
||||
+
|
||||
+struct reg_and_bit {
|
||||
+ i915_reg_t reg;
|
||||
+ u32 bit;
|
||||
+};
|
||||
+
|
||||
+static struct reg_and_bit
|
||||
+get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
|
||||
+ const i915_reg_t *regs, const unsigned int num)
|
||||
+{
|
||||
+ const unsigned int class = engine->class;
|
||||
+ struct reg_and_bit rb = { };
|
||||
+
|
||||
+ if (WARN_ON_ONCE(class >= num || !regs[class].reg))
|
||||
+ return rb;
|
||||
+
|
||||
+ rb.reg = regs[class];
|
||||
+ if (gen8 && class == VIDEO_DECODE_CLASS)
|
||||
+ rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */
|
||||
+ else
|
||||
+ rb.bit = engine->instance;
|
||||
+
|
||||
+ rb.bit = BIT(rb.bit);
|
||||
+
|
||||
+ return rb;
|
||||
+}
|
||||
+
|
||||
+void intel_gt_invalidate_tlbs(struct intel_gt *gt)
|
||||
+{
|
||||
+ static const i915_reg_t gen8_regs[] = {
|
||||
+ [RENDER_CLASS] = GEN8_RTCR,
|
||||
+ [VIDEO_DECODE_CLASS] = GEN8_M1TCR, /* , GEN8_M2TCR */
|
||||
+ [VIDEO_ENHANCEMENT_CLASS] = GEN8_VTCR,
|
||||
+ [COPY_ENGINE_CLASS] = GEN8_BTCR,
|
||||
+ };
|
||||
+ static const i915_reg_t gen12_regs[] = {
|
||||
+ [RENDER_CLASS] = GEN12_GFX_TLB_INV_CR,
|
||||
+ [VIDEO_DECODE_CLASS] = GEN12_VD_TLB_INV_CR,
|
||||
+ [VIDEO_ENHANCEMENT_CLASS] = GEN12_VE_TLB_INV_CR,
|
||||
+ [COPY_ENGINE_CLASS] = GEN12_BLT_TLB_INV_CR,
|
||||
+ };
|
||||
+ struct drm_i915_private *i915 = gt->i915;
|
||||
+ struct intel_uncore *uncore = gt->uncore;
|
||||
+ struct intel_engine_cs *engine;
|
||||
+ enum intel_engine_id id;
|
||||
+ const i915_reg_t *regs;
|
||||
+ unsigned int num = 0;
|
||||
+
|
||||
+ if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
|
||||
+ return;
|
||||
+
|
||||
+ if (INTEL_GEN(i915) == 12) {
|
||||
+ regs = gen12_regs;
|
||||
+ num = ARRAY_SIZE(gen12_regs);
|
||||
+ } else if (INTEL_GEN(i915) >= 8 && INTEL_GEN(i915) <= 11) {
|
||||
+ regs = gen8_regs;
|
||||
+ num = ARRAY_SIZE(gen8_regs);
|
||||
+ } else if (INTEL_GEN(i915) < 8) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (WARN_ONCE(!num, "Platform does not implement TLB invalidation!"))
|
||||
+ return;
|
||||
+
|
||||
+ GEM_TRACE("\n");
|
||||
+
|
||||
+ assert_rpm_wakelock_held(&i915->runtime_pm);
|
||||
+
|
||||
+ mutex_lock(>->tlb_invalidate_lock);
|
||||
+ intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
|
||||
+
|
||||
+ for_each_engine(engine, gt, id) {
|
||||
+ /*
|
||||
+ * HW architecture suggest typical invalidation time at 40us,
|
||||
+ * with pessimistic cases up to 100us and a recommendation to
|
||||
+ * cap at 1ms. We go a bit higher just in case.
|
||||
+ */
|
||||
+ const unsigned int timeout_us = 100;
|
||||
+ const unsigned int timeout_ms = 4;
|
||||
+ struct reg_and_bit rb;
|
||||
+
|
||||
+ rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
|
||||
+ if (!i915_mmio_reg_offset(rb.reg))
|
||||
+ continue;
|
||||
+
|
||||
+ intel_uncore_write_fw(uncore, rb.reg, rb.bit);
|
||||
+ if (__intel_wait_for_register_fw(uncore,
|
||||
+ rb.reg, rb.bit, 0,
|
||||
+ timeout_us, timeout_ms,
|
||||
+ NULL))
|
||||
+ DRM_ERROR_RATELIMITED("%s TLB invalidation did not complete in %ums!\n",
|
||||
+ engine->name, timeout_ms);
|
||||
+ }
|
||||
+
|
||||
+ intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
|
||||
+ mutex_unlock(>->tlb_invalidate_lock);
|
||||
+}
|
||||
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h
|
||||
index 4920cb351f109..4eab15bdcd97b 100644
|
||||
--- a/drivers/gpu/drm/i915/gt/intel_gt.h
|
||||
+++ b/drivers/gpu/drm/i915/gt/intel_gt.h
|
||||
@@ -57,4 +57,6 @@ static inline bool intel_gt_is_wedged(struct intel_gt *gt)
|
||||
|
||||
void intel_gt_queue_hangcheck(struct intel_gt *gt);
|
||||
|
||||
+void intel_gt_invalidate_tlbs(struct intel_gt *gt);
|
||||
+
|
||||
#endif /* __INTEL_GT_H__ */
|
||||
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h
|
||||
index dc295c196d11c..82a78719b32d5 100644
|
||||
--- a/drivers/gpu/drm/i915/gt/intel_gt_types.h
|
||||
+++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h
|
||||
@@ -40,6 +40,8 @@ struct intel_gt {
|
||||
|
||||
struct intel_uc uc;
|
||||
|
||||
+ struct mutex tlb_invalidate_lock;
|
||||
+
|
||||
struct intel_gt_timelines {
|
||||
spinlock_t lock; /* protects active_list */
|
||||
struct list_head active_list;
|
||||
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
|
||||
index 7b6e68f082f8c..1386d0f5eac63 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_reg.h
|
||||
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
||||
@@ -2519,6 +2519,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
||||
#define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1 << 28)
|
||||
#define GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT (1 << 24)
|
||||
|
||||
+#define GEN8_RTCR _MMIO(0x4260)
|
||||
+#define GEN8_M1TCR _MMIO(0x4264)
|
||||
+#define GEN8_M2TCR _MMIO(0x4268)
|
||||
+#define GEN8_BTCR _MMIO(0x426c)
|
||||
+#define GEN8_VTCR _MMIO(0x4270)
|
||||
+
|
||||
#if 0
|
||||
#define PRB0_TAIL _MMIO(0x2030)
|
||||
#define PRB0_HEAD _MMIO(0x2034)
|
||||
@@ -2602,6 +2608,11 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
||||
#define FAULT_VA_HIGH_BITS (0xf << 0)
|
||||
#define FAULT_GTT_SEL (1 << 4)
|
||||
|
||||
+#define GEN12_GFX_TLB_INV_CR _MMIO(0xced8)
|
||||
+#define GEN12_VD_TLB_INV_CR _MMIO(0xcedc)
|
||||
+#define GEN12_VE_TLB_INV_CR _MMIO(0xcee0)
|
||||
+#define GEN12_BLT_TLB_INV_CR _MMIO(0xcee4)
|
||||
+
|
||||
#define FPGA_DBG _MMIO(0x42300)
|
||||
#define FPGA_DBG_RM_NOCLAIM (1 << 31)
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
|
||||
index e0e677b2a3a94..c24f49ee10d73 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_vma.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_vma.c
|
||||
@@ -341,6 +341,10 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
|
||||
return ret;
|
||||
|
||||
vma->flags |= bind_flags;
|
||||
+
|
||||
+ if (vma->obj)
|
||||
+ set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
|
||||
index 5eb73ded8e07a..765f7a62870db 100644
|
||||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
|
||||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
|
||||
@@ -1002,15 +1002,14 @@ extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
|
||||
struct vmw_private *dev_priv,
|
||||
struct vmw_fence_obj **p_fence,
|
||||
uint32_t *p_handle);
|
||||
-extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
||||
+extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
||||
struct vmw_fpriv *vmw_fp,
|
||||
int ret,
|
||||
struct drm_vmw_fence_rep __user
|
||||
*user_fence_rep,
|
||||
struct vmw_fence_obj *fence,
|
||||
uint32_t fence_handle,
|
||||
- int32_t out_fence_fd,
|
||||
- struct sync_file *sync_file);
|
||||
+ int32_t out_fence_fd);
|
||||
bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
|
||||
|
||||
/**
|
||||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
|
||||
index ff86d49dc5e8a..e3d20048075bf 100644
|
||||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
|
||||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
|
||||
@@ -3413,17 +3413,17 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
|
||||
* Also if copying fails, user-space will be unable to signal the fence object
|
||||
* so we wait for it immediately, and then unreference the user-space reference.
|
||||
*/
|
||||
-void
|
||||
+int
|
||||
vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
||||
struct vmw_fpriv *vmw_fp, int ret,
|
||||
struct drm_vmw_fence_rep __user *user_fence_rep,
|
||||
struct vmw_fence_obj *fence, uint32_t fence_handle,
|
||||
- int32_t out_fence_fd, struct sync_file *sync_file)
|
||||
+ int32_t out_fence_fd)
|
||||
{
|
||||
struct drm_vmw_fence_rep fence_rep;
|
||||
|
||||
if (user_fence_rep == NULL)
|
||||
- return;
|
||||
+ return 0;
|
||||
|
||||
memset(&fence_rep, 0, sizeof(fence_rep));
|
||||
|
||||
@@ -3451,20 +3451,14 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
||||
* handle.
|
||||
*/
|
||||
if (unlikely(ret != 0) && (fence_rep.error == 0)) {
|
||||
- if (sync_file)
|
||||
- fput(sync_file->file);
|
||||
-
|
||||
- if (fence_rep.fd != -1) {
|
||||
- put_unused_fd(fence_rep.fd);
|
||||
- fence_rep.fd = -1;
|
||||
- }
|
||||
-
|
||||
ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle,
|
||||
TTM_REF_USAGE);
|
||||
VMW_DEBUG_USER("Fence copy error. Syncing.\n");
|
||||
(void) vmw_fence_obj_wait(fence, false, false,
|
||||
VMW_FENCE_WAIT_TIMEOUT);
|
||||
}
|
||||
+
|
||||
+ return ret ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3806,16 +3800,23 @@ int vmw_execbuf_process(struct drm_file *file_priv,
|
||||
|
||||
(void) vmw_fence_obj_wait(fence, false, false,
|
||||
VMW_FENCE_WAIT_TIMEOUT);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
|
||||
+ user_fence_rep, fence, handle, out_fence_fd);
|
||||
+
|
||||
+ if (sync_file) {
|
||||
+ if (ret) {
|
||||
+ /* usercopy of fence failed, put the file object */
|
||||
+ fput(sync_file->file);
|
||||
+ put_unused_fd(out_fence_fd);
|
||||
} else {
|
||||
/* Link the fence with the FD created earlier */
|
||||
fd_install(out_fence_fd, sync_file->file);
|
||||
}
|
||||
}
|
||||
|
||||
- vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
|
||||
- user_fence_rep, fence, handle, out_fence_fd,
|
||||
- sync_file);
|
||||
-
|
||||
/* Don't unreference when handing fence out */
|
||||
if (unlikely(out_fence != NULL)) {
|
||||
*out_fence = fence;
|
||||
@@ -3833,7 +3834,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
|
||||
*/
|
||||
vmw_validation_unref_lists(&val_ctx);
|
||||
|
||||
- return 0;
|
||||
+ return ret;
|
||||
|
||||
out_unlock_binding:
|
||||
mutex_unlock(&dev_priv->binding_mutex);
|
||||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
|
||||
index 178a6cd1a06fe..874093a0b04f0 100644
|
||||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
|
||||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
|
||||
@@ -1171,7 +1171,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
|
||||
- handle, -1, NULL);
|
||||
+ handle, -1);
|
||||
vmw_fence_obj_unreference(&fence);
|
||||
return 0;
|
||||
out_no_create:
|
||||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
|
||||
index 33b1519887474..0b800c3540492 100644
|
||||
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
|
||||
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
|
||||
@@ -2570,7 +2570,7 @@ void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv,
|
||||
if (file_priv)
|
||||
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
|
||||
ret, user_fence_rep, fence,
|
||||
- handle, -1, NULL);
|
||||
+ handle, -1);
|
||||
if (out_fence)
|
||||
*out_fence = fence;
|
||||
else
|
||||
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
|
||||
index 2c01e2ebef7aa..d97c19ef75830 100644
|
||||
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
|
||||
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
|
||||
@@ -218,8 +218,7 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
|
||||
static struct esdhc_soc_data usdhc_imx8qxp_data = {
|
||||
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
|
||||
- | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
|
||||
- | ESDHC_FLAG_CQHCI,
|
||||
+ | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES,
|
||||
};
|
||||
|
||||
struct pltfm_imx_data {
|
||||
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
index 0de1a3a96984c..fa742535f6791 100644
|
||||
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/init.h>
|
||||
+#include <linux/interrupt.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
@@ -37,12 +38,10 @@
|
||||
|
||||
#define MODULE_NAME "pinctrl-bcm2835"
|
||||
#define BCM2835_NUM_GPIOS 54
|
||||
+#define BCM2711_NUM_GPIOS 58
|
||||
#define BCM2835_NUM_BANKS 2
|
||||
#define BCM2835_NUM_IRQS 3
|
||||
|
||||
-#define BCM2835_PIN_BITMAP_SZ \
|
||||
- DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8)
|
||||
-
|
||||
/* GPIO register offsets */
|
||||
#define GPFSEL0 0x0 /* Function Select */
|
||||
#define GPSET0 0x1c /* Pin Output Set */
|
||||
@@ -78,13 +77,15 @@
|
||||
struct bcm2835_pinctrl {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
+ int *wake_irq;
|
||||
|
||||
/* note: locking assumes each bank will have its own unsigned long */
|
||||
unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
|
||||
- unsigned int irq_type[BCM2835_NUM_GPIOS];
|
||||
+ unsigned int irq_type[BCM2711_NUM_GPIOS];
|
||||
|
||||
struct pinctrl_dev *pctl_dev;
|
||||
struct gpio_chip gpio_chip;
|
||||
+ struct pinctrl_desc pctl_desc;
|
||||
struct pinctrl_gpio_range gpio_range;
|
||||
|
||||
raw_spinlock_t irq_lock[BCM2835_NUM_BANKS];
|
||||
@@ -147,6 +148,10 @@ static struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
|
||||
BCM2835_GPIO_PIN(51),
|
||||
BCM2835_GPIO_PIN(52),
|
||||
BCM2835_GPIO_PIN(53),
|
||||
+ BCM2835_GPIO_PIN(54),
|
||||
+ BCM2835_GPIO_PIN(55),
|
||||
+ BCM2835_GPIO_PIN(56),
|
||||
+ BCM2835_GPIO_PIN(57),
|
||||
};
|
||||
|
||||
/* one pin per group */
|
||||
@@ -205,6 +210,10 @@ static const char * const bcm2835_gpio_groups[] = {
|
||||
"gpio51",
|
||||
"gpio52",
|
||||
"gpio53",
|
||||
+ "gpio54",
|
||||
+ "gpio55",
|
||||
+ "gpio56",
|
||||
+ "gpio57",
|
||||
};
|
||||
|
||||
enum bcm2835_fsel {
|
||||
@@ -355,6 +364,22 @@ static const struct gpio_chip bcm2835_gpio_chip = {
|
||||
.can_sleep = false,
|
||||
};
|
||||
|
||||
+static const struct gpio_chip bcm2711_gpio_chip = {
|
||||
+ .label = "pinctrl-bcm2711",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .request = gpiochip_generic_request,
|
||||
+ .free = gpiochip_generic_free,
|
||||
+ .direction_input = bcm2835_gpio_direction_input,
|
||||
+ .direction_output = bcm2835_gpio_direction_output,
|
||||
+ .get_direction = bcm2835_gpio_get_direction,
|
||||
+ .get = bcm2835_gpio_get,
|
||||
+ .set = bcm2835_gpio_set,
|
||||
+ .set_config = gpiochip_generic_config,
|
||||
+ .base = -1,
|
||||
+ .ngpio = BCM2711_NUM_GPIOS,
|
||||
+ .can_sleep = false,
|
||||
+};
|
||||
+
|
||||
static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
|
||||
unsigned int bank, u32 mask)
|
||||
{
|
||||
@@ -401,7 +426,7 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
|
||||
bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000);
|
||||
bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
|
||||
break;
|
||||
- case 2: /* IRQ2 covers GPIOs 46-53 */
|
||||
+ case 2: /* IRQ2 covers GPIOs 46-57 */
|
||||
bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
|
||||
break;
|
||||
}
|
||||
@@ -409,6 +434,11 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_exit(host_chip, desc);
|
||||
}
|
||||
|
||||
+static irqreturn_t bcm2835_gpio_wake_irq_handler(int irq, void *dev_id)
|
||||
+{
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
|
||||
unsigned reg, unsigned offset, bool enable)
|
||||
{
|
||||
@@ -608,6 +638,34 @@ static void bcm2835_gpio_irq_ack(struct irq_data *data)
|
||||
bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
|
||||
}
|
||||
|
||||
+static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
|
||||
+{
|
||||
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
|
||||
+ unsigned gpio = irqd_to_hwirq(data);
|
||||
+ unsigned int irqgroup;
|
||||
+ int ret = -EINVAL;
|
||||
+
|
||||
+ if (!pc->wake_irq)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (gpio <= 27)
|
||||
+ irqgroup = 0;
|
||||
+ else if (gpio >= 28 && gpio <= 45)
|
||||
+ irqgroup = 1;
|
||||
+ else if (gpio >= 46 && gpio <= 57)
|
||||
+ irqgroup = 2;
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (on)
|
||||
+ ret = enable_irq_wake(pc->wake_irq[irqgroup]);
|
||||
+ else
|
||||
+ ret = disable_irq_wake(pc->wake_irq[irqgroup]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static struct irq_chip bcm2835_gpio_irq_chip = {
|
||||
.name = MODULE_NAME,
|
||||
.irq_enable = bcm2835_gpio_irq_enable,
|
||||
@@ -616,11 +674,13 @@ static struct irq_chip bcm2835_gpio_irq_chip = {
|
||||
.irq_ack = bcm2835_gpio_irq_ack,
|
||||
.irq_mask = bcm2835_gpio_irq_disable,
|
||||
.irq_unmask = bcm2835_gpio_irq_enable,
|
||||
+ .irq_set_wake = bcm2835_gpio_irq_set_wake,
|
||||
+ .flags = IRQCHIP_MASK_ON_SUSPEND,
|
||||
};
|
||||
|
||||
static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
- return ARRAY_SIZE(bcm2835_gpio_groups);
|
||||
+ return BCM2835_NUM_GPIOS;
|
||||
}
|
||||
|
||||
static const char *bcm2835_pctl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
@@ -778,7 +838,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
err = of_property_read_u32_index(np, "brcm,pins", i, &pin);
|
||||
if (err)
|
||||
goto out;
|
||||
- if (pin >= ARRAY_SIZE(bcm2835_gpio_pins)) {
|
||||
+ if (pin >= pc->pctl_desc.npins) {
|
||||
dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n",
|
||||
np, pin);
|
||||
err = -EINVAL;
|
||||
@@ -854,7 +914,7 @@ static int bcm2835_pmx_get_function_groups(struct pinctrl_dev *pctldev,
|
||||
{
|
||||
/* every pin can do every function */
|
||||
*groups = bcm2835_gpio_groups;
|
||||
- *num_groups = ARRAY_SIZE(bcm2835_gpio_groups);
|
||||
+ *num_groups = BCM2835_NUM_GPIOS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1054,29 +1114,66 @@ static const struct pinconf_ops bcm2711_pinconf_ops = {
|
||||
.pin_config_set = bcm2711_pinconf_set,
|
||||
};
|
||||
|
||||
-static struct pinctrl_desc bcm2835_pinctrl_desc = {
|
||||
+static const struct pinctrl_desc bcm2835_pinctrl_desc = {
|
||||
.name = MODULE_NAME,
|
||||
.pins = bcm2835_gpio_pins,
|
||||
- .npins = ARRAY_SIZE(bcm2835_gpio_pins),
|
||||
+ .npins = BCM2835_NUM_GPIOS,
|
||||
.pctlops = &bcm2835_pctl_ops,
|
||||
.pmxops = &bcm2835_pmx_ops,
|
||||
.confops = &bcm2835_pinconf_ops,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
-static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = {
|
||||
+static const struct pinctrl_desc bcm2711_pinctrl_desc = {
|
||||
+ .name = "pinctrl-bcm2711",
|
||||
+ .pins = bcm2835_gpio_pins,
|
||||
+ .npins = BCM2711_NUM_GPIOS,
|
||||
+ .pctlops = &bcm2835_pctl_ops,
|
||||
+ .pmxops = &bcm2835_pmx_ops,
|
||||
+ .confops = &bcm2711_pinconf_ops,
|
||||
+ .owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static const struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = {
|
||||
.name = MODULE_NAME,
|
||||
.npins = BCM2835_NUM_GPIOS,
|
||||
};
|
||||
|
||||
+static const struct pinctrl_gpio_range bcm2711_pinctrl_gpio_range = {
|
||||
+ .name = "pinctrl-bcm2711",
|
||||
+ .npins = BCM2711_NUM_GPIOS,
|
||||
+};
|
||||
+
|
||||
+struct bcm_plat_data {
|
||||
+ const struct gpio_chip *gpio_chip;
|
||||
+ const struct pinctrl_desc *pctl_desc;
|
||||
+ const struct pinctrl_gpio_range *gpio_range;
|
||||
+};
|
||||
+
|
||||
+static const struct bcm_plat_data bcm2835_plat_data = {
|
||||
+ .gpio_chip = &bcm2835_gpio_chip,
|
||||
+ .pctl_desc = &bcm2835_pinctrl_desc,
|
||||
+ .gpio_range = &bcm2835_pinctrl_gpio_range,
|
||||
+};
|
||||
+
|
||||
+static const struct bcm_plat_data bcm2711_plat_data = {
|
||||
+ .gpio_chip = &bcm2711_gpio_chip,
|
||||
+ .pctl_desc = &bcm2711_pinctrl_desc,
|
||||
+ .gpio_range = &bcm2711_pinctrl_gpio_range,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id bcm2835_pinctrl_match[] = {
|
||||
{
|
||||
.compatible = "brcm,bcm2835-gpio",
|
||||
- .data = &bcm2835_pinconf_ops,
|
||||
+ .data = &bcm2835_plat_data,
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,bcm2711-gpio",
|
||||
- .data = &bcm2711_pinconf_ops,
|
||||
+ .data = &bcm2711_plat_data,
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "brcm,bcm7211-gpio",
|
||||
+ .data = &bcm2711_plat_data,
|
||||
},
|
||||
{}
|
||||
};
|
||||
@@ -1085,14 +1182,16 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
+ const struct bcm_plat_data *pdata;
|
||||
struct bcm2835_pinctrl *pc;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct resource iomem;
|
||||
int err, i;
|
||||
const struct of_device_id *match;
|
||||
+ int is_7211 = 0;
|
||||
|
||||
- BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2835_NUM_GPIOS);
|
||||
- BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2835_NUM_GPIOS);
|
||||
+ BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2711_NUM_GPIOS);
|
||||
+ BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2711_NUM_GPIOS);
|
||||
|
||||
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
@@ -1111,7 +1210,14 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pc->base))
|
||||
return PTR_ERR(pc->base);
|
||||
|
||||
- pc->gpio_chip = bcm2835_gpio_chip;
|
||||
+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
|
||||
+ if (!match)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ pdata = match->data;
|
||||
+ is_7211 = of_device_is_compatible(np, "brcm,bcm7211-gpio");
|
||||
+
|
||||
+ pc->gpio_chip = *pdata->gpio_chip;
|
||||
pc->gpio_chip.parent = dev;
|
||||
pc->gpio_chip.of_node = np;
|
||||
|
||||
@@ -1135,6 +1241,18 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
raw_spin_lock_init(&pc->irq_lock[i]);
|
||||
}
|
||||
|
||||
+ pc->pctl_desc = *pdata->pctl_desc;
|
||||
+ pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
|
||||
+ if (IS_ERR(pc->pctl_dev)) {
|
||||
+ gpiochip_remove(&pc->gpio_chip);
|
||||
+ return PTR_ERR(pc->pctl_dev);
|
||||
+ }
|
||||
+
|
||||
+ pc->gpio_range = *pdata->gpio_range;
|
||||
+ pc->gpio_range.base = pc->gpio_chip.base;
|
||||
+ pc->gpio_range.gc = &pc->gpio_chip;
|
||||
+ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
+
|
||||
girq = &pc->gpio_chip.irq;
|
||||
girq->chip = &bcm2835_gpio_irq_chip;
|
||||
girq->parent_handler = bcm2835_gpio_irq_handler;
|
||||
@@ -1142,8 +1260,19 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
- if (!girq->parents)
|
||||
+ if (!girq->parents) {
|
||||
+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ if (is_7211) {
|
||||
+ pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
|
||||
+ sizeof(*pc->wake_irq),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!pc->wake_irq)
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Use the same handler for all groups: this is necessary
|
||||
* since we use one gpiochip to cover all lines - the
|
||||
@@ -1151,34 +1280,44 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
* bank that was firing the IRQ and look up the per-group
|
||||
* and bank data.
|
||||
*/
|
||||
- for (i = 0; i < BCM2835_NUM_IRQS; i++)
|
||||
+ for (i = 0; i < BCM2835_NUM_IRQS; i++) {
|
||||
+ int len;
|
||||
+ char *name;
|
||||
+
|
||||
girq->parents[i] = irq_of_parse_and_map(np, i);
|
||||
+ if (!is_7211)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Skip over the all banks interrupts */
|
||||
+ pc->wake_irq[i] = irq_of_parse_and_map(np, i +
|
||||
+ BCM2835_NUM_IRQS + 1);
|
||||
+
|
||||
+ len = strlen(dev_name(pc->dev)) + 16;
|
||||
+ name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
|
||||
+ if (!name)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
|
||||
+
|
||||
+ /* These are optional interrupts */
|
||||
+ err = devm_request_irq(dev, pc->wake_irq[i],
|
||||
+ bcm2835_gpio_wake_irq_handler,
|
||||
+ IRQF_SHARED, name, pc);
|
||||
+ if (err)
|
||||
+ dev_warn(dev, "unable to request wake IRQ %d\n",
|
||||
+ pc->wake_irq[i]);
|
||||
+ }
|
||||
+
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
|
||||
err = gpiochip_add_data(&pc->gpio_chip, pc);
|
||||
if (err) {
|
||||
dev_err(dev, "could not add GPIO chip\n");
|
||||
+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
return err;
|
||||
}
|
||||
|
||||
- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
|
||||
- if (match) {
|
||||
- bcm2835_pinctrl_desc.confops =
|
||||
- (const struct pinconf_ops *)match->data;
|
||||
- }
|
||||
-
|
||||
- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
|
||||
- if (IS_ERR(pc->pctl_dev)) {
|
||||
- gpiochip_remove(&pc->gpio_chip);
|
||||
- return PTR_ERR(pc->pctl_dev);
|
||||
- }
|
||||
-
|
||||
- pc->gpio_range = bcm2835_pinctrl_gpio_range;
|
||||
- pc->gpio_range.base = pc->gpio_chip.base;
|
||||
- pc->gpio_range.gc = &pc->gpio_chip;
|
||||
- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/fs/select.c b/fs/select.c
|
||||
index e51796063cb6e..7716d9d5be1e8 100644
|
||||
--- a/fs/select.c
|
||||
+++ b/fs/select.c
|
||||
@@ -458,9 +458,11 @@ get_max:
|
||||
return max;
|
||||
}
|
||||
|
||||
-#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)
|
||||
-#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR)
|
||||
-#define POLLEX_SET (EPOLLPRI)
|
||||
+#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR |\
|
||||
+ EPOLLNVAL)
|
||||
+#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR |\
|
||||
+ EPOLLNVAL)
|
||||
+#define POLLEX_SET (EPOLLPRI | EPOLLNVAL)
|
||||
|
||||
static inline void wait_key_set(poll_table *wait, unsigned long in,
|
||||
unsigned long out, unsigned long bit,
|
||||
@@ -527,6 +529,7 @@ static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
|
||||
break;
|
||||
if (!(bit & all_bits))
|
||||
continue;
|
||||
+ mask = EPOLLNVAL;
|
||||
f = fdget(i);
|
||||
if (f.file) {
|
||||
wait_key_set(wait, in, out, bit,
|
||||
@@ -534,34 +537,34 @@ static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
|
||||
mask = vfs_poll(f.file, wait);
|
||||
|
||||
fdput(f);
|
||||
- if ((mask & POLLIN_SET) && (in & bit)) {
|
||||
- res_in |= bit;
|
||||
- retval++;
|
||||
- wait->_qproc = NULL;
|
||||
- }
|
||||
- if ((mask & POLLOUT_SET) && (out & bit)) {
|
||||
- res_out |= bit;
|
||||
- retval++;
|
||||
- wait->_qproc = NULL;
|
||||
- }
|
||||
- if ((mask & POLLEX_SET) && (ex & bit)) {
|
||||
- res_ex |= bit;
|
||||
- retval++;
|
||||
- wait->_qproc = NULL;
|
||||
- }
|
||||
- /* got something, stop busy polling */
|
||||
- if (retval) {
|
||||
- can_busy_loop = false;
|
||||
- busy_flag = 0;
|
||||
-
|
||||
- /*
|
||||
- * only remember a returned
|
||||
- * POLL_BUSY_LOOP if we asked for it
|
||||
- */
|
||||
- } else if (busy_flag & mask)
|
||||
- can_busy_loop = true;
|
||||
-
|
||||
}
|
||||
+ if ((mask & POLLIN_SET) && (in & bit)) {
|
||||
+ res_in |= bit;
|
||||
+ retval++;
|
||||
+ wait->_qproc = NULL;
|
||||
+ }
|
||||
+ if ((mask & POLLOUT_SET) && (out & bit)) {
|
||||
+ res_out |= bit;
|
||||
+ retval++;
|
||||
+ wait->_qproc = NULL;
|
||||
+ }
|
||||
+ if ((mask & POLLEX_SET) && (ex & bit)) {
|
||||
+ res_ex |= bit;
|
||||
+ retval++;
|
||||
+ wait->_qproc = NULL;
|
||||
+ }
|
||||
+ /* got something, stop busy polling */
|
||||
+ if (retval) {
|
||||
+ can_busy_loop = false;
|
||||
+ busy_flag = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * only remember a returned
|
||||
+ * POLL_BUSY_LOOP if we asked for it
|
||||
+ */
|
||||
+ } else if (busy_flag & mask)
|
||||
+ can_busy_loop = true;
|
||||
+
|
||||
}
|
||||
if (res_in)
|
||||
*rinp = res_in;
|
||||
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
|
||||
index 7777c35e0a171..5797cf2909b00 100644
|
||||
--- a/kernel/rcu/tree.c
|
||||
+++ b/kernel/rcu/tree.c
|
||||
@@ -1358,10 +1358,11 @@ static void __maybe_unused rcu_advance_cbs_nowake(struct rcu_node *rnp,
|
||||
struct rcu_data *rdp)
|
||||
{
|
||||
rcu_lockdep_assert_cblist_protected(rdp);
|
||||
- if (!rcu_seq_state(rcu_seq_current(&rnp->gp_seq)) ||
|
||||
- !raw_spin_trylock_rcu_node(rnp))
|
||||
+ if (!rcu_seq_state(rcu_seq_current(&rnp->gp_seq)) || !raw_spin_trylock_rcu_node(rnp))
|
||||
return;
|
||||
- WARN_ON_ONCE(rcu_advance_cbs(rnp, rdp));
|
||||
+ // The grace period cannot end while we hold the rcu_node lock.
|
||||
+ if (rcu_seq_state(rcu_seq_current(&rnp->gp_seq)))
|
||||
+ WARN_ON_ONCE(rcu_advance_cbs(rnp, rdp));
|
||||
raw_spin_unlock_rcu_node(rnp);
|
||||
}
|
||||
|
||||
2235
patch/kernel/archive/odroidxu4-5.4/patch-5.4.175-176.patch
Normal file
2235
patch/kernel/archive/odroidxu4-5.4/patch-5.4.175-176.patch
Normal file
File diff suppressed because it is too large
Load Diff
468
patch/kernel/archive/odroidxu4-5.4/patch-5.4.176-177.patch
Normal file
468
patch/kernel/archive/odroidxu4-5.4/patch-5.4.176-177.patch
Normal file
@@ -0,0 +1,468 @@
|
||||
diff --git a/Documentation/accounting/psi.rst b/Documentation/accounting/psi.rst
|
||||
index 621111ce57401..28c0461ba2e1b 100644
|
||||
--- a/Documentation/accounting/psi.rst
|
||||
+++ b/Documentation/accounting/psi.rst
|
||||
@@ -90,7 +90,8 @@ Triggers can be set on more than one psi metric and more than one trigger
|
||||
for the same psi metric can be specified. However for each trigger a separate
|
||||
file descriptor is required to be able to poll it separately from others,
|
||||
therefore for each trigger a separate open() syscall should be made even
|
||||
-when opening the same psi interface file.
|
||||
+when opening the same psi interface file. Write operations to a file descriptor
|
||||
+with an already existing psi trigger will fail with EBUSY.
|
||||
|
||||
Monitors activate only when system enters stall state for the monitored
|
||||
psi metric and deactivates upon exit from the stall state. While system is
|
||||
diff --git a/Makefile b/Makefile
|
||||
index b23aa51ada93e..324939b64d7b7 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
-SUBLEVEL = 176
|
||||
+SUBLEVEL = 177
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
|
||||
index da8c2c4aca7ef..0442d7e1cd20b 100644
|
||||
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
|
||||
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
|
||||
@@ -721,7 +721,9 @@ static void xgbe_stop_timers(struct xgbe_prv_data *pdata)
|
||||
if (!channel->tx_ring)
|
||||
break;
|
||||
|
||||
+ /* Deactivate the Tx timer */
|
||||
del_timer_sync(&channel->tx_timer);
|
||||
+ channel->tx_timer_active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2765,6 +2767,14 @@ read_again:
|
||||
buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
|
||||
len += buf2_len;
|
||||
|
||||
+ if (buf2_len > rdata->rx.buf.dma_len) {
|
||||
+ /* Hardware inconsistency within the descriptors
|
||||
+ * that has resulted in a length underflow.
|
||||
+ */
|
||||
+ error = 1;
|
||||
+ goto skip_data;
|
||||
+ }
|
||||
+
|
||||
if (!skb) {
|
||||
skb = xgbe_create_skb(pdata, napi, rdata,
|
||||
buf1_len);
|
||||
@@ -2794,8 +2804,10 @@ skip_data:
|
||||
if (!last || context_next)
|
||||
goto read_again;
|
||||
|
||||
- if (!skb)
|
||||
+ if (!skb || error) {
|
||||
+ dev_kfree_skb(skb);
|
||||
goto next_packet;
|
||||
+ }
|
||||
|
||||
/* Be sure we don't exceed the configured MTU */
|
||||
max_len = netdev->mtu + ETH_HLEN;
|
||||
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
|
||||
index 345576f1a7470..73ad78f47763c 100644
|
||||
--- a/drivers/net/usb/ipheth.c
|
||||
+++ b/drivers/net/usb/ipheth.c
|
||||
@@ -121,7 +121,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
|
||||
if (tx_buf == NULL)
|
||||
goto free_rx_urb;
|
||||
|
||||
- rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
|
||||
+ rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
|
||||
GFP_KERNEL, &rx_urb->transfer_dma);
|
||||
if (rx_buf == NULL)
|
||||
goto free_tx_buf;
|
||||
@@ -146,7 +146,7 @@ error_nomem:
|
||||
|
||||
static void ipheth_free_urbs(struct ipheth_device *iphone)
|
||||
{
|
||||
- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
|
||||
+ usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
|
||||
iphone->rx_urb->transfer_dma);
|
||||
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
|
||||
iphone->tx_urb->transfer_dma);
|
||||
@@ -317,7 +317,7 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
|
||||
|
||||
usb_fill_bulk_urb(dev->rx_urb, udev,
|
||||
usb_rcvbulkpipe(udev, dev->bulk_in),
|
||||
- dev->rx_buf, IPHETH_BUF_SIZE,
|
||||
+ dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
|
||||
ipheth_rcvbulk_callback,
|
||||
dev);
|
||||
dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
|
||||
index 88b996764ff95..907b8be86ce04 100644
|
||||
--- a/drivers/pci/hotplug/pciehp_hpc.c
|
||||
+++ b/drivers/pci/hotplug/pciehp_hpc.c
|
||||
@@ -577,6 +577,8 @@ read_status:
|
||||
*/
|
||||
if (ctrl->power_fault_detected)
|
||||
status &= ~PCI_EXP_SLTSTA_PFD;
|
||||
+ else if (status & PCI_EXP_SLTSTA_PFD)
|
||||
+ ctrl->power_fault_detected = true;
|
||||
|
||||
events |= status;
|
||||
if (!events) {
|
||||
@@ -586,7 +588,7 @@ read_status:
|
||||
}
|
||||
|
||||
if (status) {
|
||||
- pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events);
|
||||
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, status);
|
||||
|
||||
/*
|
||||
* In MSI mode, all event bits must be zero before the port
|
||||
@@ -660,8 +662,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/* Check Power Fault Detected */
|
||||
- if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
|
||||
- ctrl->power_fault_detected = 1;
|
||||
+ if (events & PCI_EXP_SLTSTA_PFD) {
|
||||
ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
|
||||
pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
|
||||
PCI_EXP_SLTCTL_ATTN_IND_ON);
|
||||
diff --git a/include/linux/psi.h b/include/linux/psi.h
|
||||
index 7b3de73212199..7712b58009276 100644
|
||||
--- a/include/linux/psi.h
|
||||
+++ b/include/linux/psi.h
|
||||
@@ -31,7 +31,7 @@ void cgroup_move_task(struct task_struct *p, struct css_set *to);
|
||||
|
||||
struct psi_trigger *psi_trigger_create(struct psi_group *group,
|
||||
char *buf, size_t nbytes, enum psi_res res);
|
||||
-void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *t);
|
||||
+void psi_trigger_destroy(struct psi_trigger *t);
|
||||
|
||||
__poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
|
||||
poll_table *wait);
|
||||
diff --git a/include/linux/psi_types.h b/include/linux/psi_types.h
|
||||
index 07aaf9b822416..0023052eab23f 100644
|
||||
--- a/include/linux/psi_types.h
|
||||
+++ b/include/linux/psi_types.h
|
||||
@@ -120,9 +120,6 @@ struct psi_trigger {
|
||||
* events to one per window
|
||||
*/
|
||||
u64 last_event_time;
|
||||
-
|
||||
- /* Refcounting to prevent premature destruction */
|
||||
- struct kref refcount;
|
||||
};
|
||||
|
||||
struct psi_group {
|
||||
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
|
||||
index 2d0ef613ca070..5e465c4b1e64c 100644
|
||||
--- a/kernel/cgroup/cgroup-v1.c
|
||||
+++ b/kernel/cgroup/cgroup-v1.c
|
||||
@@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
|
||||
|
||||
BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
|
||||
|
||||
+ /*
|
||||
+ * Release agent gets called with all capabilities,
|
||||
+ * require capabilities to set release agent.
|
||||
+ */
|
||||
+ if ((of->file->f_cred->user_ns != &init_user_ns) ||
|
||||
+ !capable(CAP_SYS_ADMIN))
|
||||
+ return -EPERM;
|
||||
+
|
||||
cgrp = cgroup_kn_lock_live(of->kn, false);
|
||||
if (!cgrp)
|
||||
return -ENODEV;
|
||||
@@ -961,6 +969,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
/* Specifying two release agents is forbidden */
|
||||
if (ctx->release_agent)
|
||||
return cg_invalf(fc, "cgroup1: release_agent respecified");
|
||||
+ /*
|
||||
+ * Release agent gets called with all capabilities,
|
||||
+ * require capabilities to set release agent.
|
||||
+ */
|
||||
+ if ((fc->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
|
||||
+ return cg_invalf(fc, "cgroup1: Setting release_agent not allowed");
|
||||
ctx->release_agent = param->string;
|
||||
param->string = NULL;
|
||||
break;
|
||||
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
|
||||
index 1904ffcee0f1e..ce1745ac7b8c0 100644
|
||||
--- a/kernel/cgroup/cgroup.c
|
||||
+++ b/kernel/cgroup/cgroup.c
|
||||
@@ -3659,6 +3659,12 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
|
||||
cgroup_get(cgrp);
|
||||
cgroup_kn_unlock(of->kn);
|
||||
|
||||
+ /* Allow only one trigger per file descriptor */
|
||||
+ if (of->priv) {
|
||||
+ cgroup_put(cgrp);
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
|
||||
new = psi_trigger_create(psi, buf, nbytes, res);
|
||||
if (IS_ERR(new)) {
|
||||
@@ -3666,8 +3672,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
|
||||
return PTR_ERR(new);
|
||||
}
|
||||
|
||||
- psi_trigger_replace(&of->priv, new);
|
||||
-
|
||||
+ smp_store_release(&of->priv, new);
|
||||
cgroup_put(cgrp);
|
||||
|
||||
return nbytes;
|
||||
@@ -3702,7 +3707,7 @@ static __poll_t cgroup_pressure_poll(struct kernfs_open_file *of,
|
||||
|
||||
static void cgroup_pressure_release(struct kernfs_open_file *of)
|
||||
{
|
||||
- psi_trigger_replace(&of->priv, NULL);
|
||||
+ psi_trigger_destroy(of->priv);
|
||||
}
|
||||
#endif /* CONFIG_PSI */
|
||||
|
||||
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
|
||||
index badfa8f153599..411be8b2e837e 100644
|
||||
--- a/kernel/cgroup/cpuset.c
|
||||
+++ b/kernel/cgroup/cpuset.c
|
||||
@@ -1558,8 +1558,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
* Make sure that subparts_cpus is a subset of cpus_allowed.
|
||||
*/
|
||||
if (cs->nr_subparts_cpus) {
|
||||
- cpumask_andnot(cs->subparts_cpus, cs->subparts_cpus,
|
||||
- cs->cpus_allowed);
|
||||
+ cpumask_and(cs->subparts_cpus, cs->subparts_cpus, cs->cpus_allowed);
|
||||
cs->nr_subparts_cpus = cpumask_weight(cs->subparts_cpus);
|
||||
}
|
||||
spin_unlock_irq(&callback_lock);
|
||||
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c
|
||||
index 9154e745f0978..9dd83eb74a9da 100644
|
||||
--- a/kernel/sched/psi.c
|
||||
+++ b/kernel/sched/psi.c
|
||||
@@ -1046,7 +1046,6 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
|
||||
t->event = 0;
|
||||
t->last_event_time = 0;
|
||||
init_waitqueue_head(&t->event_wait);
|
||||
- kref_init(&t->refcount);
|
||||
|
||||
mutex_lock(&group->trigger_lock);
|
||||
|
||||
@@ -1079,15 +1078,19 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
|
||||
return t;
|
||||
}
|
||||
|
||||
-static void psi_trigger_destroy(struct kref *ref)
|
||||
+void psi_trigger_destroy(struct psi_trigger *t)
|
||||
{
|
||||
- struct psi_trigger *t = container_of(ref, struct psi_trigger, refcount);
|
||||
- struct psi_group *group = t->group;
|
||||
+ struct psi_group *group;
|
||||
struct kthread_worker *kworker_to_destroy = NULL;
|
||||
|
||||
- if (static_branch_likely(&psi_disabled))
|
||||
+ /*
|
||||
+ * We do not check psi_disabled since it might have been disabled after
|
||||
+ * the trigger got created.
|
||||
+ */
|
||||
+ if (!t)
|
||||
return;
|
||||
|
||||
+ group = t->group;
|
||||
/*
|
||||
* Wakeup waiters to stop polling. Can happen if cgroup is deleted
|
||||
* from under a polling process.
|
||||
@@ -1122,9 +1125,9 @@ static void psi_trigger_destroy(struct kref *ref)
|
||||
mutex_unlock(&group->trigger_lock);
|
||||
|
||||
/*
|
||||
- * Wait for both *trigger_ptr from psi_trigger_replace and
|
||||
- * poll_kworker RCUs to complete their read-side critical sections
|
||||
- * before destroying the trigger and optionally the poll_kworker
|
||||
+ * Wait for psi_schedule_poll_work RCU to complete its read-side
|
||||
+ * critical section before destroying the trigger and optionally the
|
||||
+ * poll_task.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
/*
|
||||
@@ -1146,18 +1149,6 @@ static void psi_trigger_destroy(struct kref *ref)
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
-void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *new)
|
||||
-{
|
||||
- struct psi_trigger *old = *trigger_ptr;
|
||||
-
|
||||
- if (static_branch_likely(&psi_disabled))
|
||||
- return;
|
||||
-
|
||||
- rcu_assign_pointer(*trigger_ptr, new);
|
||||
- if (old)
|
||||
- kref_put(&old->refcount, psi_trigger_destroy);
|
||||
-}
|
||||
-
|
||||
__poll_t psi_trigger_poll(void **trigger_ptr,
|
||||
struct file *file, poll_table *wait)
|
||||
{
|
||||
@@ -1167,24 +1158,15 @@ __poll_t psi_trigger_poll(void **trigger_ptr,
|
||||
if (static_branch_likely(&psi_disabled))
|
||||
return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
|
||||
|
||||
- rcu_read_lock();
|
||||
-
|
||||
- t = rcu_dereference(*(void __rcu __force **)trigger_ptr);
|
||||
- if (!t) {
|
||||
- rcu_read_unlock();
|
||||
+ t = smp_load_acquire(trigger_ptr);
|
||||
+ if (!t)
|
||||
return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
|
||||
- }
|
||||
- kref_get(&t->refcount);
|
||||
-
|
||||
- rcu_read_unlock();
|
||||
|
||||
poll_wait(file, &t->event_wait, wait);
|
||||
|
||||
if (cmpxchg(&t->event, 1, 0) == 1)
|
||||
ret |= EPOLLPRI;
|
||||
|
||||
- kref_put(&t->refcount, psi_trigger_destroy);
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1208,14 +1190,24 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
|
||||
|
||||
buf[buf_size - 1] = '\0';
|
||||
|
||||
- new = psi_trigger_create(&psi_system, buf, nbytes, res);
|
||||
- if (IS_ERR(new))
|
||||
- return PTR_ERR(new);
|
||||
-
|
||||
seq = file->private_data;
|
||||
+
|
||||
/* Take seq->lock to protect seq->private from concurrent writes */
|
||||
mutex_lock(&seq->lock);
|
||||
- psi_trigger_replace(&seq->private, new);
|
||||
+
|
||||
+ /* Allow only one trigger per file descriptor */
|
||||
+ if (seq->private) {
|
||||
+ mutex_unlock(&seq->lock);
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ new = psi_trigger_create(&psi_system, buf, nbytes, res);
|
||||
+ if (IS_ERR(new)) {
|
||||
+ mutex_unlock(&seq->lock);
|
||||
+ return PTR_ERR(new);
|
||||
+ }
|
||||
+
|
||||
+ smp_store_release(&seq->private, new);
|
||||
mutex_unlock(&seq->lock);
|
||||
|
||||
return nbytes;
|
||||
@@ -1250,7 +1242,7 @@ static int psi_fop_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *seq = file->private_data;
|
||||
|
||||
- psi_trigger_replace(&seq->private, NULL);
|
||||
+ psi_trigger_destroy(seq->private);
|
||||
return single_release(inode, file);
|
||||
}
|
||||
|
||||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
|
||||
index 55c0f32b9375b..dbc9b2f53649d 100644
|
||||
--- a/net/core/rtnetlink.c
|
||||
+++ b/net/core/rtnetlink.c
|
||||
@@ -3022,8 +3022,8 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
|
||||
unsigned char name_assign_type = NET_NAME_USER;
|
||||
struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
|
||||
- const struct rtnl_link_ops *m_ops = NULL;
|
||||
- struct net_device *master_dev = NULL;
|
||||
+ const struct rtnl_link_ops *m_ops;
|
||||
+ struct net_device *master_dev;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
const struct rtnl_link_ops *ops;
|
||||
struct nlattr *tb[IFLA_MAX + 1];
|
||||
@@ -3063,6 +3063,8 @@ replay:
|
||||
dev = NULL;
|
||||
}
|
||||
|
||||
+ master_dev = NULL;
|
||||
+ m_ops = NULL;
|
||||
if (dev) {
|
||||
master_dev = netdev_master_upper_dev_get(dev);
|
||||
if (master_dev)
|
||||
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
||||
index 839e1caa57a59..ed11013d4b953 100644
|
||||
--- a/net/packet/af_packet.c
|
||||
+++ b/net/packet/af_packet.c
|
||||
@@ -1729,7 +1729,10 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
|
||||
err = -ENOSPC;
|
||||
if (refcount_read(&match->sk_ref) < PACKET_FANOUT_MAX) {
|
||||
__dev_remove_pack(&po->prot_hook);
|
||||
- po->fanout = match;
|
||||
+
|
||||
+ /* Paired with packet_setsockopt(PACKET_FANOUT_DATA) */
|
||||
+ WRITE_ONCE(po->fanout, match);
|
||||
+
|
||||
po->rollover = rollover;
|
||||
rollover = NULL;
|
||||
refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1);
|
||||
@@ -3876,7 +3879,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
||||
}
|
||||
case PACKET_FANOUT_DATA:
|
||||
{
|
||||
- if (!po->fanout)
|
||||
+ /* Paired with the WRITE_ONCE() in fanout_add() */
|
||||
+ if (!READ_ONCE(po->fanout))
|
||||
return -EINVAL;
|
||||
|
||||
return fanout_set_data(po, optval, optlen);
|
||||
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
|
||||
index a4c61205462ac..80205b138d113 100644
|
||||
--- a/net/sched/cls_api.c
|
||||
+++ b/net/sched/cls_api.c
|
||||
@@ -1928,9 +1928,9 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
|
||||
bool prio_allocate;
|
||||
u32 parent;
|
||||
u32 chain_index;
|
||||
- struct Qdisc *q = NULL;
|
||||
+ struct Qdisc *q;
|
||||
struct tcf_chain_info chain_info;
|
||||
- struct tcf_chain *chain = NULL;
|
||||
+ struct tcf_chain *chain;
|
||||
struct tcf_block *block;
|
||||
struct tcf_proto *tp;
|
||||
unsigned long cl;
|
||||
@@ -1958,6 +1958,8 @@ replay:
|
||||
tp = NULL;
|
||||
cl = 0;
|
||||
block = NULL;
|
||||
+ q = NULL;
|
||||
+ chain = NULL;
|
||||
|
||||
if (prio == 0) {
|
||||
/* If no priority is provided by the user,
|
||||
@@ -2764,8 +2766,8 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
|
||||
struct tcmsg *t;
|
||||
u32 parent;
|
||||
u32 chain_index;
|
||||
- struct Qdisc *q = NULL;
|
||||
- struct tcf_chain *chain = NULL;
|
||||
+ struct Qdisc *q;
|
||||
+ struct tcf_chain *chain;
|
||||
struct tcf_block *block;
|
||||
unsigned long cl;
|
||||
int err;
|
||||
@@ -2775,6 +2777,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
|
||||
return -EPERM;
|
||||
|
||||
replay:
|
||||
+ q = NULL;
|
||||
err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
|
||||
rtm_tca_policy, extack);
|
||||
if (err < 0)
|
||||
Reference in New Issue
Block a user