3678 lines
119 KiB
Diff
3678 lines
119 KiB
Diff
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml
|
|
index 91c774f106ceb1..ab1196d1ec2dd4 100644
|
|
--- a/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml
|
|
+++ b/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml
|
|
@@ -59,7 +59,6 @@ properties:
|
|
- const: bus
|
|
- const: core
|
|
- const: vsync
|
|
- - const: lut
|
|
- const: tbu
|
|
- const: tbu_rt
|
|
# MSM8996 has additional iommu clock
|
|
diff --git a/Makefile b/Makefile
|
|
index 9b288ccccd6495..ae57f816375ebd 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 6
|
|
PATCHLEVEL = 6
|
|
-SUBLEVEL = 103
|
|
+SUBLEVEL = 104
|
|
EXTRAVERSION =
|
|
NAME = Pinguïn Aangedreven
|
|
|
|
diff --git a/arch/mips/boot/dts/lantiq/danube_easy50712.dts b/arch/mips/boot/dts/lantiq/danube_easy50712.dts
|
|
index 1ce20b7d05cb8c..c4d7aa5753b043 100644
|
|
--- a/arch/mips/boot/dts/lantiq/danube_easy50712.dts
|
|
+++ b/arch/mips/boot/dts/lantiq/danube_easy50712.dts
|
|
@@ -82,13 +82,16 @@ conf_out {
|
|
};
|
|
};
|
|
|
|
- etop@e180000 {
|
|
+ ethernet@e180000 {
|
|
compatible = "lantiq,etop-xway";
|
|
reg = <0xe180000 0x40000>;
|
|
interrupt-parent = <&icu0>;
|
|
interrupts = <73 78>;
|
|
+ interrupt-names = "tx", "rx";
|
|
phy-mode = "rmii";
|
|
mac-address = [ 00 11 22 33 44 55 ];
|
|
+ lantiq,rx-burst-length = <4>;
|
|
+ lantiq,tx-burst-length = <4>;
|
|
};
|
|
|
|
stp0: stp@e100bb0 {
|
|
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
|
|
index 3ed0782252229a..4c72b59fdf98cc 100644
|
|
--- a/arch/mips/lantiq/xway/sysctrl.c
|
|
+++ b/arch/mips/lantiq/xway/sysctrl.c
|
|
@@ -478,7 +478,7 @@ void __init ltq_soc_init(void)
|
|
ifccr = CGU_IFCCR_VR9;
|
|
pcicr = CGU_PCICR_VR9;
|
|
} else {
|
|
- clkdev_add_pmu("1e180000.etop", NULL, 1, 0, PMU_PPE);
|
|
+ clkdev_add_pmu("1e180000.ethernet", NULL, 1, 0, PMU_PPE);
|
|
}
|
|
|
|
if (!of_machine_is_compatible("lantiq,ase"))
|
|
@@ -512,9 +512,9 @@ void __init ltq_soc_init(void)
|
|
CLOCK_133M, CLOCK_133M);
|
|
clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0);
|
|
clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P);
|
|
- clkdev_add_pmu("1e180000.etop", "ppe", 1, 0, PMU_PPE);
|
|
- clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY);
|
|
- clkdev_add_pmu("1e180000.etop", "ephy", 1, 0, PMU_EPHY);
|
|
+ clkdev_add_pmu("1e180000.ethernet", "ppe", 1, 0, PMU_PPE);
|
|
+ clkdev_add_cgu("1e180000.ethernet", "ephycgu", CGU_EPHY);
|
|
+ clkdev_add_pmu("1e180000.ethernet", "ephy", 1, 0, PMU_EPHY);
|
|
clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_ASE_SDIO);
|
|
clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
|
|
} else if (of_machine_is_compatible("lantiq,grx390")) {
|
|
@@ -573,7 +573,7 @@ void __init ltq_soc_init(void)
|
|
clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM);
|
|
clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 0, PMU_USB1_P);
|
|
clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1 | PMU_AHBM);
|
|
- clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH);
|
|
+ clkdev_add_pmu("1e180000.ethernet", "switch", 1, 0, PMU_SWITCH);
|
|
clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
|
|
clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
|
|
clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
|
|
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
|
|
index 5b3c093611baf1..7209d00a9c2576 100644
|
|
--- a/arch/powerpc/kernel/kvm.c
|
|
+++ b/arch/powerpc/kernel/kvm.c
|
|
@@ -632,19 +632,19 @@ static void __init kvm_check_ins(u32 *inst, u32 features)
|
|
#endif
|
|
}
|
|
|
|
- switch (inst_no_rt & ~KVM_MASK_RB) {
|
|
#ifdef CONFIG_PPC_BOOK3S_32
|
|
+ switch (inst_no_rt & ~KVM_MASK_RB) {
|
|
case KVM_INST_MTSRIN:
|
|
if (features & KVM_MAGIC_FEAT_SR) {
|
|
u32 inst_rb = _inst & KVM_MASK_RB;
|
|
kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb);
|
|
}
|
|
break;
|
|
-#endif
|
|
}
|
|
+#endif
|
|
|
|
- switch (_inst) {
|
|
#ifdef CONFIG_BOOKE
|
|
+ switch (_inst) {
|
|
case KVM_INST_WRTEEI_0:
|
|
kvm_patch_ins_wrteei_0(inst);
|
|
break;
|
|
@@ -652,8 +652,8 @@ static void __init kvm_check_ins(u32 *inst, u32 features)
|
|
case KVM_INST_WRTEEI_1:
|
|
kvm_patch_ins_wrtee(inst, 0, 1);
|
|
break;
|
|
-#endif
|
|
}
|
|
+#endif
|
|
}
|
|
|
|
extern u32 kvm_template_start[];
|
|
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
|
|
index 7444fe0e3d08cd..2cb30d9c5b4ae7 100644
|
|
--- a/arch/x86/kernel/cpu/microcode/amd.c
|
|
+++ b/arch/x86/kernel/cpu/microcode/amd.c
|
|
@@ -161,8 +161,28 @@ static int cmp_id(const void *key, const void *elem)
|
|
return 1;
|
|
}
|
|
|
|
+static u32 cpuid_to_ucode_rev(unsigned int val)
|
|
+{
|
|
+ union zen_patch_rev p = {};
|
|
+ union cpuid_1_eax c;
|
|
+
|
|
+ c.full = val;
|
|
+
|
|
+ p.stepping = c.stepping;
|
|
+ p.model = c.model;
|
|
+ p.ext_model = c.ext_model;
|
|
+ p.ext_fam = c.ext_fam;
|
|
+
|
|
+ return p.ucode_rev;
|
|
+}
|
|
+
|
|
static bool need_sha_check(u32 cur_rev)
|
|
{
|
|
+ if (!cur_rev) {
|
|
+ cur_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax);
|
|
+ pr_info_once("No current revision, generating the lowest one: 0x%x\n", cur_rev);
|
|
+ }
|
|
+
|
|
switch (cur_rev >> 8) {
|
|
case 0x80012: return cur_rev <= 0x800126f; break;
|
|
case 0x80082: return cur_rev <= 0x800820f; break;
|
|
@@ -744,8 +764,6 @@ static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equi
|
|
n.equiv_cpu = equiv_cpu;
|
|
n.patch_id = uci->cpu_sig.rev;
|
|
|
|
- WARN_ON_ONCE(!n.patch_id);
|
|
-
|
|
list_for_each_entry(p, µcode_cache, plist)
|
|
if (patch_cpus_equivalent(p, &n, false))
|
|
return p;
|
|
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
|
|
index ba1c2a7f74f766..af4ae9216667ea 100644
|
|
--- a/arch/x86/kvm/lapic.c
|
|
+++ b/arch/x86/kvm/lapic.c
|
|
@@ -847,6 +847,8 @@ static int __pv_send_ipi(unsigned long *ipi_bitmap, struct kvm_apic_map *map,
|
|
if (min > map->max_apic_id)
|
|
return 0;
|
|
|
|
+ min = array_index_nospec(min, map->max_apic_id + 1);
|
|
+
|
|
for_each_set_bit(i, ipi_bitmap,
|
|
min((u32)BITS_PER_LONG, (map->max_apic_id - min + 1))) {
|
|
if (map->phys_map[min + i]) {
|
|
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
|
|
index af0b2b3bc991e2..5088065ac704be 100644
|
|
--- a/arch/x86/kvm/x86.c
|
|
+++ b/arch/x86/kvm/x86.c
|
|
@@ -9802,8 +9802,11 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id)
|
|
rcu_read_lock();
|
|
map = rcu_dereference(vcpu->kvm->arch.apic_map);
|
|
|
|
- if (likely(map) && dest_id <= map->max_apic_id && map->phys_map[dest_id])
|
|
- target = map->phys_map[dest_id]->vcpu;
|
|
+ if (likely(map) && dest_id <= map->max_apic_id) {
|
|
+ dest_id = array_index_nospec(dest_id, map->max_apic_id + 1);
|
|
+ if (map->phys_map[dest_id])
|
|
+ target = map->phys_map[dest_id]->vcpu;
|
|
+ }
|
|
|
|
rcu_read_unlock();
|
|
|
|
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
|
|
index 77d6af61158936..8e304efde3429e 100644
|
|
--- a/drivers/acpi/ec.c
|
|
+++ b/drivers/acpi/ec.c
|
|
@@ -2329,6 +2329,12 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = {
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"),
|
|
}
|
|
},
|
|
+ {
|
|
+ // TUXEDO InfinityBook Pro AMD Gen9
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
|
|
+ },
|
|
+ },
|
|
{ },
|
|
};
|
|
|
|
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
|
|
index ff558908897f3e..9c83fb29b2f1b2 100644
|
|
--- a/drivers/atm/atmtcp.c
|
|
+++ b/drivers/atm/atmtcp.c
|
|
@@ -279,6 +279,19 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci)
|
|
return NULL;
|
|
}
|
|
|
|
+static int atmtcp_c_pre_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
+{
|
|
+ struct atmtcp_hdr *hdr;
|
|
+
|
|
+ if (skb->len < sizeof(struct atmtcp_hdr))
|
|
+ return -EINVAL;
|
|
+
|
|
+ hdr = (struct atmtcp_hdr *)skb->data;
|
|
+ if (hdr->length == ATMTCP_HDR_MAGIC)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
|
|
static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
|
|
{
|
|
@@ -288,9 +301,6 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
|
|
struct sk_buff *new_skb;
|
|
int result = 0;
|
|
|
|
- if (skb->len < sizeof(struct atmtcp_hdr))
|
|
- goto done;
|
|
-
|
|
dev = vcc->dev_data;
|
|
hdr = (struct atmtcp_hdr *) skb->data;
|
|
if (hdr->length == ATMTCP_HDR_MAGIC) {
|
|
@@ -347,6 +357,7 @@ static const struct atmdev_ops atmtcp_v_dev_ops = {
|
|
|
|
static const struct atmdev_ops atmtcp_c_dev_ops = {
|
|
.close = atmtcp_c_close,
|
|
+ .pre_send = atmtcp_c_pre_send,
|
|
.send = atmtcp_c_send
|
|
};
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c
|
|
index 384834fbd59011..7200110197415f 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c
|
|
@@ -89,8 +89,8 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
|
}
|
|
|
|
r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, size,
|
|
- AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
|
|
- AMDGPU_VM_PAGE_EXECUTABLE);
|
|
+ AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
|
|
+ AMDGPU_PTE_EXECUTABLE);
|
|
|
|
if (r) {
|
|
DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r);
|
|
diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c
|
|
index 772d8e662278b9..851f0baf94600c 100644
|
|
--- a/drivers/gpu/drm/display/drm_dp_helper.c
|
|
+++ b/drivers/gpu/drm/display/drm_dp_helper.c
|
|
@@ -663,7 +663,7 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
|
|
* monitor doesn't power down exactly after the throw away read.
|
|
*/
|
|
if (!aux->is_remote) {
|
|
- ret = drm_dp_dpcd_probe(aux, DP_LANE0_1_STATUS);
|
|
+ ret = drm_dp_dpcd_probe(aux, DP_DPCD_REV);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
|
|
index bbe4f1665b6039..dc142f9e4f6028 100644
|
|
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
|
|
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
|
|
@@ -981,12 +981,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|
|
|
if (ret == 0 && args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
|
|
sync_file = sync_file_create(submit->user_fence);
|
|
- if (!sync_file) {
|
|
+ if (!sync_file)
|
|
ret = -ENOMEM;
|
|
- } else {
|
|
- fd_install(out_fence_fd, sync_file->file);
|
|
- args->fence_fd = out_fence_fd;
|
|
- }
|
|
}
|
|
|
|
submit_attach_object_fences(submit);
|
|
@@ -1013,10 +1009,14 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|
out_unlock:
|
|
mutex_unlock(&queue->lock);
|
|
out_post_unlock:
|
|
- if (ret && (out_fence_fd >= 0)) {
|
|
- put_unused_fd(out_fence_fd);
|
|
+ if (ret) {
|
|
+ if (out_fence_fd >= 0)
|
|
+ put_unused_fd(out_fence_fd);
|
|
if (sync_file)
|
|
fput(sync_file->file);
|
|
+ } else if (sync_file) {
|
|
+ fd_install(out_fence_fd, sync_file->file);
|
|
+ args->fence_fd = out_fence_fd;
|
|
}
|
|
|
|
if (!IS_ERR_OR_NULL(submit)) {
|
|
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
|
|
index 7a2cceaee6e97f..1199dfc1194c80 100644
|
|
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
|
|
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
|
|
@@ -663,6 +663,10 @@ static bool nv50_plane_format_mod_supported(struct drm_plane *plane,
|
|
struct nouveau_drm *drm = nouveau_drm(plane->dev);
|
|
uint8_t i;
|
|
|
|
+ /* All chipsets can display all formats in linear layout */
|
|
+ if (modifier == DRM_FORMAT_MOD_LINEAR)
|
|
+ return true;
|
|
+
|
|
if (drm->client.device.info.chipset < 0xc0) {
|
|
const struct drm_format_info *info = drm_format_info(format);
|
|
const uint8_t kind = (modifier >> 12) & 0xff;
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
|
|
index b7da3ab44c277d..7c43397c19e61d 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
|
|
@@ -103,7 +103,7 @@ gm200_flcn_pio_imem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 i
|
|
static void
|
|
gm200_flcn_pio_imem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag)
|
|
{
|
|
- nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag++);
|
|
+ nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag);
|
|
while (len >= 4) {
|
|
nvkm_falcon_wr32(falcon, 0x184 + (port * 0x10), *(u32 *)img);
|
|
img += 4;
|
|
@@ -249,9 +249,11 @@ int
|
|
gm200_flcn_fw_load(struct nvkm_falcon_fw *fw)
|
|
{
|
|
struct nvkm_falcon *falcon = fw->falcon;
|
|
- int target, ret;
|
|
+ int ret;
|
|
|
|
if (fw->inst) {
|
|
+ int target;
|
|
+
|
|
nvkm_falcon_mask(falcon, 0x048, 0x00000001, 0x00000001);
|
|
|
|
switch (nvkm_memory_target(fw->inst)) {
|
|
@@ -285,15 +287,6 @@ gm200_flcn_fw_load(struct nvkm_falcon_fw *fw)
|
|
}
|
|
|
|
if (fw->boot) {
|
|
- switch (nvkm_memory_target(&fw->fw.mem.memory)) {
|
|
- case NVKM_MEM_TARGET_VRAM: target = 4; break;
|
|
- case NVKM_MEM_TARGET_HOST: target = 5; break;
|
|
- case NVKM_MEM_TARGET_NCOH: target = 6; break;
|
|
- default:
|
|
- WARN_ON(1);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
ret = nvkm_falcon_pio_wr(falcon, fw->boot, 0, 0,
|
|
IMEM, falcon->code.limit - fw->boot_size, fw->boot_size,
|
|
fw->boot_addr >> 8, false);
|
|
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
|
|
index 84625e817ce950..896f73aa4d2c82 100644
|
|
--- a/drivers/hid/hid-asus.c
|
|
+++ b/drivers/hid/hid-asus.c
|
|
@@ -1108,7 +1108,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
return ret;
|
|
}
|
|
|
|
- if (!drvdata->input) {
|
|
+ /*
|
|
+ * Check that input registration succeeded. Checking that
|
|
+ * HID_CLAIMED_INPUT is set prevents a UAF when all input devices
|
|
+ * were freed during registration due to no usages being mapped,
|
|
+ * leaving drvdata->input pointing to freed memory.
|
|
+ */
|
|
+ if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) {
|
|
hid_err(hdev, "Asus input not registered\n");
|
|
ret = -ENOMEM;
|
|
goto err_stop_hw;
|
|
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
index 0d1d7162814f32..3f74633070b6ec 100644
|
|
--- a/drivers/hid/hid-ids.h
|
|
+++ b/drivers/hid/hid-ids.h
|
|
@@ -818,6 +818,8 @@
|
|
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
|
|
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e
|
|
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093
|
|
+#define USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT 0x6184
|
|
+#define USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT 0x61ed
|
|
|
|
#define USB_VENDOR_ID_LETSKETCH 0x6161
|
|
#define USB_DEVICE_ID_WP9620N 0x4d15
|
|
@@ -891,6 +893,7 @@
|
|
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
|
|
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
|
|
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
|
|
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543
|
|
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
|
|
#define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548
|
|
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
|
|
diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c
|
|
index 77c2d45ac62a7f..6f5c71660d823b 100644
|
|
--- a/drivers/hid/hid-input-test.c
|
|
+++ b/drivers/hid/hid-input-test.c
|
|
@@ -7,7 +7,7 @@
|
|
|
|
#include <kunit/test.h>
|
|
|
|
-static void hid_test_input_set_battery_charge_status(struct kunit *test)
|
|
+static void hid_test_input_update_battery_charge_status(struct kunit *test)
|
|
{
|
|
struct hid_device *dev;
|
|
bool handled;
|
|
@@ -15,15 +15,15 @@ static void hid_test_input_set_battery_charge_status(struct kunit *test)
|
|
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
|
|
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
|
|
|
|
- handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0);
|
|
+ handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0);
|
|
KUNIT_EXPECT_FALSE(test, handled);
|
|
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
|
|
|
|
- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0);
|
|
+ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0);
|
|
KUNIT_EXPECT_TRUE(test, handled);
|
|
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
|
|
|
|
- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1);
|
|
+ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1);
|
|
KUNIT_EXPECT_TRUE(test, handled);
|
|
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
|
|
}
|
|
@@ -63,7 +63,7 @@ static void hid_test_input_get_battery_property(struct kunit *test)
|
|
}
|
|
|
|
static struct kunit_case hid_input_tests[] = {
|
|
- KUNIT_CASE(hid_test_input_set_battery_charge_status),
|
|
+ KUNIT_CASE(hid_test_input_update_battery_charge_status),
|
|
KUNIT_CASE(hid_test_input_get_battery_property),
|
|
{ }
|
|
};
|
|
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
|
|
index 9d80635a91ebd8..f5c217ac4bfaa7 100644
|
|
--- a/drivers/hid/hid-input.c
|
|
+++ b/drivers/hid/hid-input.c
|
|
@@ -595,13 +595,33 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
|
|
dev->battery = NULL;
|
|
}
|
|
|
|
-static void hidinput_update_battery(struct hid_device *dev, int value)
|
|
+static bool hidinput_update_battery_charge_status(struct hid_device *dev,
|
|
+ unsigned int usage, int value)
|
|
+{
|
|
+ switch (usage) {
|
|
+ case HID_BAT_CHARGING:
|
|
+ dev->battery_charge_status = value ?
|
|
+ POWER_SUPPLY_STATUS_CHARGING :
|
|
+ POWER_SUPPLY_STATUS_DISCHARGING;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
|
|
+ int value)
|
|
{
|
|
int capacity;
|
|
|
|
if (!dev->battery)
|
|
return;
|
|
|
|
+ if (hidinput_update_battery_charge_status(dev, usage, value)) {
|
|
+ power_supply_changed(dev->battery);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (value == 0 || value < dev->battery_min || value > dev->battery_max)
|
|
return;
|
|
|
|
@@ -617,20 +637,6 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
|
|
power_supply_changed(dev->battery);
|
|
}
|
|
}
|
|
-
|
|
-static bool hidinput_set_battery_charge_status(struct hid_device *dev,
|
|
- unsigned int usage, int value)
|
|
-{
|
|
- switch (usage) {
|
|
- case HID_BAT_CHARGING:
|
|
- dev->battery_charge_status = value ?
|
|
- POWER_SUPPLY_STATUS_CHARGING :
|
|
- POWER_SUPPLY_STATUS_DISCHARGING;
|
|
- return true;
|
|
- }
|
|
-
|
|
- return false;
|
|
-}
|
|
#else /* !CONFIG_HID_BATTERY_STRENGTH */
|
|
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
|
|
struct hid_field *field, bool is_percentage)
|
|
@@ -642,14 +648,9 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
|
|
{
|
|
}
|
|
|
|
-static void hidinput_update_battery(struct hid_device *dev, int value)
|
|
-{
|
|
-}
|
|
-
|
|
-static bool hidinput_set_battery_charge_status(struct hid_device *dev,
|
|
- unsigned int usage, int value)
|
|
+static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
|
|
+ int value)
|
|
{
|
|
- return false;
|
|
}
|
|
#endif /* CONFIG_HID_BATTERY_STRENGTH */
|
|
|
|
@@ -1515,11 +1516,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
|
return;
|
|
|
|
if (usage->type == EV_PWR) {
|
|
- bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
|
|
-
|
|
- if (!handled)
|
|
- hidinput_update_battery(hid, value);
|
|
-
|
|
+ hidinput_update_battery(hid, usage->hid, value);
|
|
return;
|
|
}
|
|
|
|
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
|
|
index 37958edec55f5f..e2d5b3f699146d 100644
|
|
--- a/drivers/hid/hid-logitech-dj.c
|
|
+++ b/drivers/hid/hid-logitech-dj.c
|
|
@@ -1983,6 +1983,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
|
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
|
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1),
|
|
.driver_data = recvr_type_gaming_hidpp},
|
|
+ { /* Logitech lightspeed receiver (0xc543) */
|
|
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
|
+ USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2),
|
|
+ .driver_data = recvr_type_gaming_hidpp},
|
|
|
|
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
|
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
|
|
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
|
|
index 4519ee377aa767..3a2c1e48aba20c 100644
|
|
--- a/drivers/hid/hid-logitech-hidpp.c
|
|
+++ b/drivers/hid/hid-logitech-hidpp.c
|
|
@@ -4652,6 +4652,8 @@ static const struct hid_device_id hidpp_devices[] = {
|
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) },
|
|
{ /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */
|
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) },
|
|
+ { /* Logitech G PRO 2 LIGHTSPEED Wireless Mouse over USB */
|
|
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xc09a) },
|
|
|
|
{ /* G935 Gaming Headset */
|
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87),
|
|
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
|
|
index c5bfca8ac5e6e8..a985301a4135f5 100644
|
|
--- a/drivers/hid/hid-mcp2221.c
|
|
+++ b/drivers/hid/hid-mcp2221.c
|
|
@@ -49,6 +49,7 @@ enum {
|
|
MCP2221_I2C_MASK_ADDR_NACK = 0x40,
|
|
MCP2221_I2C_WRADDRL_SEND = 0x21,
|
|
MCP2221_I2C_ADDR_NACK = 0x25,
|
|
+ MCP2221_I2C_READ_PARTIAL = 0x54,
|
|
MCP2221_I2C_READ_COMPL = 0x55,
|
|
MCP2221_ALT_F_NOT_GPIOV = 0xEE,
|
|
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
|
|
@@ -187,6 +188,25 @@ static int mcp_cancel_last_cmd(struct mcp2221 *mcp)
|
|
return mcp_send_data_req_status(mcp, mcp->txbuf, 8);
|
|
}
|
|
|
|
+/* Check if the last command succeeded or failed and return the result.
|
|
+ * If the command did fail, cancel that command which will free the i2c bus.
|
|
+ */
|
|
+static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mcp_chk_last_cmd_status(mcp);
|
|
+ if (ret) {
|
|
+ /* The last command was a failure.
|
|
+ * Send a cancel which will also free the bus.
|
|
+ */
|
|
+ usleep_range(980, 1000);
|
|
+ mcp_cancel_last_cmd(mcp);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int mcp_set_i2c_speed(struct mcp2221 *mcp)
|
|
{
|
|
int ret;
|
|
@@ -241,7 +261,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
|
|
usleep_range(980, 1000);
|
|
|
|
if (last_status) {
|
|
- ret = mcp_chk_last_cmd_status(mcp);
|
|
+ ret = mcp_chk_last_cmd_status_free_bus(mcp);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
@@ -278,6 +298,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
|
|
{
|
|
int ret;
|
|
u16 total_len;
|
|
+ int retries = 0;
|
|
|
|
mcp->txbuf[0] = type;
|
|
if (msg) {
|
|
@@ -301,20 +322,31 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
|
|
mcp->rxbuf_idx = 0;
|
|
|
|
do {
|
|
+ /* Wait for the data to be read by the device */
|
|
+ usleep_range(980, 1000);
|
|
+
|
|
memset(mcp->txbuf, 0, 4);
|
|
mcp->txbuf[0] = MCP2221_I2C_GET_DATA;
|
|
|
|
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = mcp_chk_last_cmd_status(mcp);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- usleep_range(980, 1000);
|
|
+ if (ret) {
|
|
+ if (retries < 5) {
|
|
+ /* The data wasn't ready to read.
|
|
+ * Wait a bit longer and try again.
|
|
+ */
|
|
+ usleep_range(90, 100);
|
|
+ retries++;
|
|
+ } else {
|
|
+ return ret;
|
|
+ }
|
|
+ } else {
|
|
+ retries = 0;
|
|
+ }
|
|
} while (mcp->rxbuf_idx < total_len);
|
|
|
|
+ usleep_range(980, 1000);
|
|
+ ret = mcp_chk_last_cmd_status_free_bus(mcp);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -328,11 +360,6 @@ static int mcp_i2c_xfer(struct i2c_adapter *adapter,
|
|
|
|
mutex_lock(&mcp->lock);
|
|
|
|
- /* Setting speed before every transaction is required for mcp2221 */
|
|
- ret = mcp_set_i2c_speed(mcp);
|
|
- if (ret)
|
|
- goto exit;
|
|
-
|
|
if (num == 1) {
|
|
if (msgs->flags & I2C_M_RD) {
|
|
ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA,
|
|
@@ -417,9 +444,7 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr,
|
|
if (last_status) {
|
|
usleep_range(980, 1000);
|
|
|
|
- ret = mcp_chk_last_cmd_status(mcp);
|
|
- if (ret)
|
|
- return ret;
|
|
+ ret = mcp_chk_last_cmd_status_free_bus(mcp);
|
|
}
|
|
|
|
return ret;
|
|
@@ -437,10 +462,6 @@ static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|
|
|
mutex_lock(&mcp->lock);
|
|
|
|
- ret = mcp_set_i2c_speed(mcp);
|
|
- if (ret)
|
|
- goto exit;
|
|
-
|
|
switch (size) {
|
|
|
|
case I2C_SMBUS_QUICK:
|
|
@@ -791,7 +812,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
|
|
mcp->status = -EIO;
|
|
break;
|
|
}
|
|
- if (data[2] == MCP2221_I2C_READ_COMPL) {
|
|
+ if (data[2] == MCP2221_I2C_READ_COMPL ||
|
|
+ data[2] == MCP2221_I2C_READ_PARTIAL) {
|
|
buf = mcp->rxbuf;
|
|
memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
|
|
mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
|
|
@@ -1152,6 +1174,11 @@ static int mcp2221_probe(struct hid_device *hdev,
|
|
if (i2c_clk_freq < 50)
|
|
i2c_clk_freq = 50;
|
|
mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3;
|
|
+ ret = mcp_set_i2c_speed(mcp);
|
|
+ if (ret) {
|
|
+ hid_err(hdev, "can't set i2c speed: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
|
|
mcp->adapter.owner = THIS_MODULE;
|
|
mcp->adapter.class = I2C_CLASS_HWMON;
|
|
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
|
|
index becd4c1ccf93c1..a85581cd511fd3 100644
|
|
--- a/drivers/hid/hid-multitouch.c
|
|
+++ b/drivers/hid/hid-multitouch.c
|
|
@@ -1448,6 +1448,14 @@ static __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|
if (hdev->vendor == I2C_VENDOR_ID_GOODIX &&
|
|
(hdev->product == I2C_DEVICE_ID_GOODIX_01E8 ||
|
|
hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) {
|
|
+ if (*size < 608) {
|
|
+ dev_info(
|
|
+ &hdev->dev,
|
|
+ "GT7868Q fixup: report descriptor is only %u bytes, skipping\n",
|
|
+ *size);
|
|
+ return rdesc;
|
|
+ }
|
|
+
|
|
if (rdesc[607] == 0x15) {
|
|
rdesc[607] = 0x25;
|
|
dev_info(
|
|
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
|
|
index b5d26f03fe6bb7..a1128c5315fffa 100644
|
|
--- a/drivers/hid/hid-ntrig.c
|
|
+++ b/drivers/hid/hid-ntrig.c
|
|
@@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
|
|
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
|
|
unsigned char *data = kmalloc(8, GFP_KERNEL);
|
|
|
|
+ if (!hid_is_usb(hdev))
|
|
+ return;
|
|
+
|
|
if (!data)
|
|
goto err_free;
|
|
|
|
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
|
|
index 80372342c176af..64f9728018b885 100644
|
|
--- a/drivers/hid/hid-quirks.c
|
|
+++ b/drivers/hid/hid-quirks.c
|
|
@@ -124,6 +124,8 @@ static const struct hid_device_id hid_quirks[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_T609A), HID_QUIRK_MULTI_INPUT },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE), HID_QUIRK_ALWAYS_POLL },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL },
|
|
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
|
|
index dd44373ba930e2..42bc8f05e26358 100644
|
|
--- a/drivers/hid/wacom_wac.c
|
|
+++ b/drivers/hid/wacom_wac.c
|
|
@@ -684,6 +684,7 @@ static bool wacom_is_art_pen(int tool_id)
|
|
case 0x885: /* Intuos3 Marker Pen */
|
|
case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
|
|
case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */
|
|
+ case 0x204: /* Art Pen 2 */
|
|
is_art_pen = true;
|
|
break;
|
|
}
|
|
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
|
|
index fad5a72d3b1671..f1208591ed67e3 100644
|
|
--- a/drivers/net/ethernet/dlink/dl2k.c
|
|
+++ b/drivers/net/ethernet/dlink/dl2k.c
|
|
@@ -1092,7 +1092,7 @@ get_stats (struct net_device *dev)
|
|
dev->stats.rx_bytes += dr32(OctetRcvOk);
|
|
dev->stats.tx_bytes += dr32(OctetXmtOk);
|
|
|
|
- dev->stats.multicast = dr32(McstFramesRcvdOk);
|
|
+ dev->stats.multicast += dr32(McstFramesRcvdOk);
|
|
dev->stats.collisions += dr32(SingleColFrames)
|
|
+ dr32(MultiColFrames);
|
|
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
|
|
index f5023ac9ab8323..eae4376c685952 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
|
|
@@ -527,14 +527,14 @@ int ice_setup_rx_ring(struct ice_rx_ring *rx_ring)
|
|
* @xdp: xdp_buff used as input to the XDP program
|
|
* @xdp_prog: XDP program to run
|
|
* @xdp_ring: ring to be used for XDP_TX action
|
|
- * @rx_buf: Rx buffer to store the XDP action
|
|
+ * @eop_desc: Last descriptor in packet to read metadata from
|
|
*
|
|
* Returns any of ICE_XDP_{PASS, CONSUMED, TX, REDIR}
|
|
*/
|
|
-static void
|
|
+static u32
|
|
ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
|
|
struct bpf_prog *xdp_prog, struct ice_tx_ring *xdp_ring,
|
|
- struct ice_rx_buf *rx_buf)
|
|
+ union ice_32b_rx_flex_desc *eop_desc)
|
|
{
|
|
unsigned int ret = ICE_XDP_PASS;
|
|
u32 act;
|
|
@@ -542,6 +542,8 @@ ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
|
|
if (!xdp_prog)
|
|
goto exit;
|
|
|
|
+ ice_xdp_meta_set_desc(xdp, eop_desc);
|
|
+
|
|
act = bpf_prog_run_xdp(xdp_prog, xdp);
|
|
switch (act) {
|
|
case XDP_PASS:
|
|
@@ -571,7 +573,7 @@ ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
|
|
ret = ICE_XDP_CONSUMED;
|
|
}
|
|
exit:
|
|
- ice_set_rx_bufs_act(xdp, rx_ring, ret);
|
|
+ return ret;
|
|
}
|
|
|
|
/**
|
|
@@ -857,10 +859,8 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
|
|
xdp_buff_set_frags_flag(xdp);
|
|
}
|
|
|
|
- if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) {
|
|
- ice_set_rx_bufs_act(xdp, rx_ring, ICE_XDP_CONSUMED);
|
|
+ if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS))
|
|
return -ENOMEM;
|
|
- }
|
|
|
|
__skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page,
|
|
rx_buf->page_offset, size);
|
|
@@ -921,7 +921,6 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
|
|
struct ice_rx_buf *rx_buf;
|
|
|
|
rx_buf = &rx_ring->rx_buf[ntc];
|
|
- rx_buf->pgcnt = page_count(rx_buf->page);
|
|
prefetchw(rx_buf->page);
|
|
|
|
if (!size)
|
|
@@ -937,6 +936,31 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
|
|
return rx_buf;
|
|
}
|
|
|
|
+/**
|
|
+ * ice_get_pgcnts - grab page_count() for gathered fragments
|
|
+ * @rx_ring: Rx descriptor ring to store the page counts on
|
|
+ *
|
|
+ * This function is intended to be called right before running XDP
|
|
+ * program so that the page recycling mechanism will be able to take
|
|
+ * a correct decision regarding underlying pages; this is done in such
|
|
+ * way as XDP program can change the refcount of page
|
|
+ */
|
|
+static void ice_get_pgcnts(struct ice_rx_ring *rx_ring)
|
|
+{
|
|
+ u32 nr_frags = rx_ring->nr_frags + 1;
|
|
+ u32 idx = rx_ring->first_desc;
|
|
+ struct ice_rx_buf *rx_buf;
|
|
+ u32 cnt = rx_ring->count;
|
|
+
|
|
+ for (int i = 0; i < nr_frags; i++) {
|
|
+ rx_buf = &rx_ring->rx_buf[idx];
|
|
+ rx_buf->pgcnt = page_count(rx_buf->page);
|
|
+
|
|
+ if (++idx == cnt)
|
|
+ idx = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* ice_build_skb - Build skb around an existing buffer
|
|
* @rx_ring: Rx descriptor ring to transact packets on
|
|
@@ -1049,12 +1073,12 @@ ice_construct_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
|
|
rx_buf->page_offset + headlen, size,
|
|
xdp->frame_sz);
|
|
} else {
|
|
- /* buffer is unused, change the act that should be taken later
|
|
- * on; data was copied onto skb's linear part so there's no
|
|
+ /* buffer is unused, restore biased page count in Rx buffer;
|
|
+ * data was copied onto skb's linear part so there's no
|
|
* need for adjusting page offset and we can reuse this buffer
|
|
* as-is
|
|
*/
|
|
- rx_buf->act = ICE_SKB_CONSUMED;
|
|
+ rx_buf->pagecnt_bias++;
|
|
}
|
|
|
|
if (unlikely(xdp_buff_has_frags(xdp))) {
|
|
@@ -1107,29 +1131,34 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf)
|
|
* @xdp: XDP buffer carrying linear + frags part
|
|
* @xdp_xmit: XDP_TX/XDP_REDIRECT verdict storage
|
|
* @ntc: a current next_to_clean value to be stored at rx_ring
|
|
+ * @verdict: return code from XDP program execution
|
|
*
|
|
* Walk through gathered fragments and satisfy internal page
|
|
* recycle mechanism; we take here an action related to verdict
|
|
* returned by XDP program;
|
|
*/
|
|
static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
|
|
- u32 *xdp_xmit, u32 ntc)
|
|
+ u32 *xdp_xmit, u32 ntc, u32 verdict)
|
|
{
|
|
u32 nr_frags = rx_ring->nr_frags + 1;
|
|
u32 idx = rx_ring->first_desc;
|
|
u32 cnt = rx_ring->count;
|
|
+ u32 post_xdp_frags = 1;
|
|
struct ice_rx_buf *buf;
|
|
int i;
|
|
|
|
- for (i = 0; i < nr_frags; i++) {
|
|
+ if (unlikely(xdp_buff_has_frags(xdp)))
|
|
+ post_xdp_frags += xdp_get_shared_info_from_buff(xdp)->nr_frags;
|
|
+
|
|
+ for (i = 0; i < post_xdp_frags; i++) {
|
|
buf = &rx_ring->rx_buf[idx];
|
|
|
|
- if (buf->act & (ICE_XDP_TX | ICE_XDP_REDIR)) {
|
|
+ if (verdict & (ICE_XDP_TX | ICE_XDP_REDIR)) {
|
|
ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz);
|
|
- *xdp_xmit |= buf->act;
|
|
- } else if (buf->act & ICE_XDP_CONSUMED) {
|
|
+ *xdp_xmit |= verdict;
|
|
+ } else if (verdict & ICE_XDP_CONSUMED) {
|
|
buf->pagecnt_bias++;
|
|
- } else if (buf->act == ICE_XDP_PASS) {
|
|
+ } else if (verdict == ICE_XDP_PASS) {
|
|
ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz);
|
|
}
|
|
|
|
@@ -1138,6 +1167,17 @@ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
|
|
if (++idx == cnt)
|
|
idx = 0;
|
|
}
|
|
+ /* handle buffers that represented frags released by XDP prog;
|
|
+ * for these we keep pagecnt_bias as-is; refcount from struct page
|
|
+ * has been decremented within XDP prog and we do not have to increase
|
|
+ * the biased refcnt
|
|
+ */
|
|
+ for (; i < nr_frags; i++) {
|
|
+ buf = &rx_ring->rx_buf[idx];
|
|
+ ice_put_rx_buf(rx_ring, buf);
|
|
+ if (++idx == cnt)
|
|
+ idx = 0;
|
|
+ }
|
|
|
|
xdp->data = NULL;
|
|
rx_ring->first_desc = ntc;
|
|
@@ -1164,9 +1204,9 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
|
|
struct ice_tx_ring *xdp_ring = NULL;
|
|
struct bpf_prog *xdp_prog = NULL;
|
|
u32 ntc = rx_ring->next_to_clean;
|
|
+ u32 cached_ntu, xdp_verdict;
|
|
u32 cnt = rx_ring->count;
|
|
u32 xdp_xmit = 0;
|
|
- u32 cached_ntu;
|
|
bool failure;
|
|
|
|
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
|
|
@@ -1230,7 +1270,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
|
|
xdp_prepare_buff(xdp, hard_start, offset, size, !!offset);
|
|
xdp_buff_clear_frags_flag(xdp);
|
|
} else if (ice_add_xdp_frag(rx_ring, xdp, rx_buf, size)) {
|
|
- ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc);
|
|
+ ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc, ICE_XDP_CONSUMED);
|
|
break;
|
|
}
|
|
if (++ntc == cnt)
|
|
@@ -1240,13 +1280,14 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
|
|
if (ice_is_non_eop(rx_ring, rx_desc))
|
|
continue;
|
|
|
|
- ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_buf);
|
|
- if (rx_buf->act == ICE_XDP_PASS)
|
|
+ ice_get_pgcnts(rx_ring);
|
|
+ xdp_verdict = ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_desc);
|
|
+ if (xdp_verdict == ICE_XDP_PASS)
|
|
goto construct_skb;
|
|
total_rx_bytes += xdp_get_buff_len(xdp);
|
|
total_rx_pkts++;
|
|
|
|
- ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc);
|
|
+ ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict);
|
|
|
|
continue;
|
|
construct_skb:
|
|
@@ -1256,13 +1297,10 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
|
|
skb = ice_construct_skb(rx_ring, xdp);
|
|
/* exit if we failed to retrieve a buffer */
|
|
if (!skb) {
|
|
- rx_ring->ring_stats->rx_stats.alloc_page_failed++;
|
|
- rx_buf->act = ICE_XDP_CONSUMED;
|
|
- if (unlikely(xdp_buff_has_frags(xdp)))
|
|
- ice_set_rx_bufs_act(xdp, rx_ring,
|
|
- ICE_XDP_CONSUMED);
|
|
+ rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
|
|
+ xdp_verdict = ICE_XDP_CONSUMED;
|
|
}
|
|
- ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc);
|
|
+ ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict);
|
|
|
|
if (!skb)
|
|
break;
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
|
|
index 407d4c320097f6..53a155dde3e320 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
|
|
@@ -201,7 +201,6 @@ struct ice_rx_buf {
|
|
struct page *page;
|
|
unsigned int page_offset;
|
|
unsigned int pgcnt;
|
|
- unsigned int act;
|
|
unsigned int pagecnt_bias;
|
|
};
|
|
|
|
@@ -257,6 +256,14 @@ enum ice_rx_dtype {
|
|
ICE_RX_DTYPE_SPLIT_ALWAYS = 2,
|
|
};
|
|
|
|
+struct ice_xdp_buff {
|
|
+ struct xdp_buff xdp_buff;
|
|
+ const union ice_32b_rx_flex_desc *eop_desc;
|
|
+};
|
|
+
|
|
+/* Required for compatibility with xdp_buffs from xsk_pool */
|
|
+static_assert(offsetof(struct ice_xdp_buff, xdp_buff) == 0);
|
|
+
|
|
/* indices into GLINT_ITR registers */
|
|
#define ICE_RX_ITR ICE_IDX_ITR0
|
|
#define ICE_TX_ITR ICE_IDX_ITR1
|
|
@@ -298,7 +305,6 @@ enum ice_dynamic_itr {
|
|
/* descriptor ring, associated with a VSI */
|
|
struct ice_rx_ring {
|
|
/* CL1 - 1st cacheline starts here */
|
|
- struct ice_rx_ring *next; /* pointer to next ring in q_vector */
|
|
void *desc; /* Descriptor ring memory */
|
|
struct device *dev; /* Used for DMA mapping */
|
|
struct net_device *netdev; /* netdev ring maps to */
|
|
@@ -310,12 +316,16 @@ struct ice_rx_ring {
|
|
u16 count; /* Number of descriptors */
|
|
u16 reg_idx; /* HW register index of the ring */
|
|
u16 next_to_alloc;
|
|
- /* CL2 - 2nd cacheline starts here */
|
|
+
|
|
union {
|
|
struct ice_rx_buf *rx_buf;
|
|
struct xdp_buff **xdp_buf;
|
|
};
|
|
- struct xdp_buff xdp;
|
|
+ /* CL2 - 2nd cacheline starts here */
|
|
+ union {
|
|
+ struct ice_xdp_buff xdp_ext;
|
|
+ struct xdp_buff xdp;
|
|
+ };
|
|
/* CL3 - 3rd cacheline starts here */
|
|
struct bpf_prog *xdp_prog;
|
|
u16 rx_offset;
|
|
@@ -332,6 +342,7 @@ struct ice_rx_ring {
|
|
/* CL4 - 4th cacheline starts here */
|
|
struct ice_channel *ch;
|
|
struct ice_tx_ring *xdp_ring;
|
|
+ struct ice_rx_ring *next; /* pointer to next ring in q_vector */
|
|
struct xsk_buff_pool *xsk_pool;
|
|
u32 nr_frags;
|
|
dma_addr_t dma; /* physical address of ring */
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
|
|
index b0e56675f98b2a..41efafc5eb386a 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
|
|
@@ -5,49 +5,6 @@
|
|
#define _ICE_TXRX_LIB_H_
|
|
#include "ice.h"
|
|
|
|
-/**
|
|
- * ice_set_rx_bufs_act - propagate Rx buffer action to frags
|
|
- * @xdp: XDP buffer representing frame (linear and frags part)
|
|
- * @rx_ring: Rx ring struct
|
|
- * act: action to store onto Rx buffers related to XDP buffer parts
|
|
- *
|
|
- * Set action that should be taken before putting Rx buffer from first frag
|
|
- * to the last.
|
|
- */
|
|
-static inline void
|
|
-ice_set_rx_bufs_act(struct xdp_buff *xdp, const struct ice_rx_ring *rx_ring,
|
|
- const unsigned int act)
|
|
-{
|
|
- u32 sinfo_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags;
|
|
- u32 nr_frags = rx_ring->nr_frags + 1;
|
|
- u32 idx = rx_ring->first_desc;
|
|
- u32 cnt = rx_ring->count;
|
|
- struct ice_rx_buf *buf;
|
|
-
|
|
- for (int i = 0; i < nr_frags; i++) {
|
|
- buf = &rx_ring->rx_buf[idx];
|
|
- buf->act = act;
|
|
-
|
|
- if (++idx == cnt)
|
|
- idx = 0;
|
|
- }
|
|
-
|
|
- /* adjust pagecnt_bias on frags freed by XDP prog */
|
|
- if (sinfo_frags < rx_ring->nr_frags && act == ICE_XDP_CONSUMED) {
|
|
- u32 delta = rx_ring->nr_frags - sinfo_frags;
|
|
-
|
|
- while (delta) {
|
|
- if (idx == 0)
|
|
- idx = cnt - 1;
|
|
- else
|
|
- idx--;
|
|
- buf = &rx_ring->rx_buf[idx];
|
|
- buf->pagecnt_bias--;
|
|
- delta--;
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
/**
|
|
* ice_test_staterr - tests bits in Rx descriptor status and error fields
|
|
* @status_err_n: Rx descriptor status_error0 or status_error1 bits
|
|
@@ -164,4 +121,14 @@ ice_process_skb_fields(struct ice_rx_ring *rx_ring,
|
|
struct sk_buff *skb, u16 ptype);
|
|
void
|
|
ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag);
|
|
+
|
|
+static inline void
|
|
+ice_xdp_meta_set_desc(struct xdp_buff *xdp,
|
|
+ union ice_32b_rx_flex_desc *eop_desc)
|
|
+{
|
|
+ struct ice_xdp_buff *xdp_ext = container_of(xdp, struct ice_xdp_buff,
|
|
+ xdp_buff);
|
|
+
|
|
+ xdp_ext->eop_desc = eop_desc;
|
|
+}
|
|
#endif /* !_ICE_TXRX_LIB_H_ */
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
|
|
index f66788a2ed77ec..8489b5087d9c60 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
|
|
@@ -107,7 +107,7 @@ static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netli
|
|
if (err)
|
|
return err;
|
|
|
|
- mlx5_unload_one_devl_locked(dev, true);
|
|
+ mlx5_sync_reset_unload_flow(dev, true);
|
|
err = mlx5_health_wait_pci_up(dev);
|
|
if (err)
|
|
NL_SET_ERR_MSG_MOD(extack, "FW activate aborted, PCI reads fail after reset");
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
|
|
index 3efa8bf1d14ef4..4720523813b976 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
|
|
@@ -575,7 +575,6 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
|
|
if (err)
|
|
return err;
|
|
}
|
|
- priv->dcbx.xoff = xoff;
|
|
|
|
/* Apply the settings */
|
|
if (update_buffer) {
|
|
@@ -584,6 +583,8 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
|
|
return err;
|
|
}
|
|
|
|
+ priv->dcbx.xoff = xoff;
|
|
+
|
|
if (update_prio2buffer)
|
|
err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer);
|
|
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h
|
|
index f4a19ffbb641c0..66d276a1be836a 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h
|
|
@@ -66,11 +66,23 @@ struct mlx5e_port_buffer {
|
|
struct mlx5e_bufferx_reg buffer[MLX5E_MAX_NETWORK_BUFFER];
|
|
};
|
|
|
|
+#ifdef CONFIG_MLX5_CORE_EN_DCB
|
|
int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
|
|
u32 change, unsigned int mtu,
|
|
struct ieee_pfc *pfc,
|
|
u32 *buffer_size,
|
|
u8 *prio2buffer);
|
|
+#else
|
|
+static inline int
|
|
+mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
|
|
+ u32 change, unsigned int mtu,
|
|
+ void *pfc,
|
|
+ u32 *buffer_size,
|
|
+ u8 *prio2buffer)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
|
|
int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
|
|
struct mlx5e_port_buffer *port_buffer);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
index 5c6f01abdcb91d..d378aa55f22f90 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
@@ -44,6 +44,7 @@
|
|
#include "eswitch.h"
|
|
#include "en.h"
|
|
#include "en/txrx.h"
|
|
+#include "en/port_buffer.h"
|
|
#include "en_tc.h"
|
|
#include "en_rep.h"
|
|
#include "en_accel/ipsec.h"
|
|
@@ -108,6 +109,8 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv)
|
|
if (up) {
|
|
netdev_info(priv->netdev, "Link up\n");
|
|
netif_carrier_on(priv->netdev);
|
|
+ mlx5e_port_manual_buffer_config(priv, 0, priv->netdev->mtu,
|
|
+ NULL, NULL, NULL);
|
|
} else {
|
|
netdev_info(priv->netdev, "Link down\n");
|
|
netif_carrier_off(priv->netdev);
|
|
@@ -2722,9 +2725,11 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv)
|
|
struct mlx5e_params *params = &priv->channels.params;
|
|
struct net_device *netdev = priv->netdev;
|
|
struct mlx5_core_dev *mdev = priv->mdev;
|
|
- u16 mtu;
|
|
+ u16 mtu, prev_mtu;
|
|
int err;
|
|
|
|
+ mlx5e_query_mtu(mdev, params, &prev_mtu);
|
|
+
|
|
err = mlx5e_set_mtu(mdev, params, params->sw_mtu);
|
|
if (err)
|
|
return err;
|
|
@@ -2734,6 +2739,18 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv)
|
|
netdev_warn(netdev, "%s: VPort MTU %d is different than netdev mtu %d\n",
|
|
__func__, mtu, params->sw_mtu);
|
|
|
|
+ if (mtu != prev_mtu && MLX5_BUFFER_SUPPORTED(mdev)) {
|
|
+ err = mlx5e_port_manual_buffer_config(priv, 0, mtu,
|
|
+ NULL, NULL, NULL);
|
|
+ if (err) {
|
|
+ netdev_warn(netdev, "%s: Failed to set Xon/Xoff values with MTU %d (err %d), setting back to previous MTU %d\n",
|
|
+ __func__, mtu, err, prev_mtu);
|
|
+
|
|
+ mlx5e_set_mtu(mdev, params, prev_mtu);
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
params->sw_mtu = mtu;
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
|
|
index 6b17346aa4cef2..1547704c89767f 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
|
|
@@ -6,13 +6,15 @@
|
|
#include "fw_reset.h"
|
|
#include "diag/fw_tracer.h"
|
|
#include "lib/tout.h"
|
|
+#include "sf/sf.h"
|
|
|
|
enum {
|
|
MLX5_FW_RESET_FLAGS_RESET_REQUESTED,
|
|
MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST,
|
|
MLX5_FW_RESET_FLAGS_PENDING_COMP,
|
|
MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS,
|
|
- MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED
|
|
+ MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED,
|
|
+ MLX5_FW_RESET_FLAGS_UNLOAD_EVENT,
|
|
};
|
|
|
|
struct mlx5_fw_reset {
|
|
@@ -26,6 +28,7 @@ struct mlx5_fw_reset {
|
|
struct work_struct reset_now_work;
|
|
struct work_struct reset_abort_work;
|
|
unsigned long reset_flags;
|
|
+ u8 reset_method;
|
|
struct timer_list timer;
|
|
struct completion done;
|
|
int ret;
|
|
@@ -94,7 +97,7 @@ static int mlx5_reg_mfrl_set(struct mlx5_core_dev *dev, u8 reset_level,
|
|
}
|
|
|
|
static int mlx5_reg_mfrl_query(struct mlx5_core_dev *dev, u8 *reset_level,
|
|
- u8 *reset_type, u8 *reset_state)
|
|
+ u8 *reset_type, u8 *reset_state, u8 *reset_method)
|
|
{
|
|
u32 out[MLX5_ST_SZ_DW(mfrl_reg)] = {};
|
|
u32 in[MLX5_ST_SZ_DW(mfrl_reg)] = {};
|
|
@@ -110,13 +113,26 @@ static int mlx5_reg_mfrl_query(struct mlx5_core_dev *dev, u8 *reset_level,
|
|
*reset_type = MLX5_GET(mfrl_reg, out, reset_type);
|
|
if (reset_state)
|
|
*reset_state = MLX5_GET(mfrl_reg, out, reset_state);
|
|
+ if (reset_method)
|
|
+ *reset_method = MLX5_GET(mfrl_reg, out, pci_reset_req_method);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_type)
|
|
{
|
|
- return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL);
|
|
+ return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL, NULL);
|
|
+}
|
|
+
|
|
+static int mlx5_fw_reset_get_reset_method(struct mlx5_core_dev *dev,
|
|
+ u8 *reset_method)
|
|
+{
|
|
+ if (!MLX5_CAP_GEN(dev, pcie_reset_using_hotreset_method)) {
|
|
+ *reset_method = MLX5_MFRL_REG_PCI_RESET_METHOD_LINK_TOGGLE;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return mlx5_reg_mfrl_query(dev, NULL, NULL, NULL, reset_method);
|
|
}
|
|
|
|
static int mlx5_fw_reset_get_reset_state_err(struct mlx5_core_dev *dev,
|
|
@@ -124,7 +140,7 @@ static int mlx5_fw_reset_get_reset_state_err(struct mlx5_core_dev *dev,
|
|
{
|
|
u8 reset_state;
|
|
|
|
- if (mlx5_reg_mfrl_query(dev, NULL, NULL, &reset_state))
|
|
+ if (mlx5_reg_mfrl_query(dev, NULL, NULL, &reset_state, NULL))
|
|
goto out;
|
|
|
|
if (!reset_state)
|
|
@@ -203,7 +219,7 @@ int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev)
|
|
return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL0, 0, 0, false);
|
|
}
|
|
|
|
-static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unloaded)
|
|
+static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev)
|
|
{
|
|
struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
|
|
struct devlink *devlink = priv_to_devlink(dev);
|
|
@@ -212,8 +228,7 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unload
|
|
if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) {
|
|
complete(&fw_reset->done);
|
|
} else {
|
|
- if (!unloaded)
|
|
- mlx5_unload_one(dev, false);
|
|
+ mlx5_sync_reset_unload_flow(dev, false);
|
|
if (mlx5_health_wait_pci_up(dev))
|
|
mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n");
|
|
else
|
|
@@ -256,7 +271,7 @@ static void mlx5_sync_reset_reload_work(struct work_struct *work)
|
|
|
|
mlx5_sync_reset_clear_reset_requested(dev, false);
|
|
mlx5_enter_error_state(dev, true);
|
|
- mlx5_fw_reset_complete_reload(dev, false);
|
|
+ mlx5_fw_reset_complete_reload(dev);
|
|
}
|
|
|
|
#define MLX5_RESET_POLL_INTERVAL (HZ / 10)
|
|
@@ -383,6 +398,11 @@ static bool mlx5_is_reset_now_capable(struct mlx5_core_dev *dev)
|
|
return false;
|
|
}
|
|
|
|
+ if (!mlx5_core_is_ecpf(dev) && !mlx5_sf_table_empty(dev)) {
|
|
+ mlx5_core_warn(dev, "SFs should be removed before reset\n");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
#if IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)
|
|
err = mlx5_check_hotplug_interrupt(dev);
|
|
if (err)
|
|
@@ -402,7 +422,11 @@ static void mlx5_sync_reset_request_event(struct work_struct *work)
|
|
struct mlx5_core_dev *dev = fw_reset->dev;
|
|
int err;
|
|
|
|
- if (test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) ||
|
|
+ err = mlx5_fw_reset_get_reset_method(dev, &fw_reset->reset_method);
|
|
+ if (err)
|
|
+ mlx5_core_warn(dev, "Failed reading MFRL, err %d\n", err);
|
|
+
|
|
+ if (err || test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) ||
|
|
!mlx5_is_reset_now_capable(dev)) {
|
|
err = mlx5_fw_reset_set_reset_sync_nack(dev);
|
|
mlx5_core_warn(dev, "PCI Sync FW Update Reset Nack %s",
|
|
@@ -419,21 +443,15 @@ static void mlx5_sync_reset_request_event(struct work_struct *work)
|
|
mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack. Device reset is expected.\n");
|
|
}
|
|
|
|
-static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
|
|
+static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev, u16 dev_id)
|
|
{
|
|
struct pci_bus *bridge_bus = dev->pdev->bus;
|
|
struct pci_dev *bridge = bridge_bus->self;
|
|
unsigned long timeout;
|
|
struct pci_dev *sdev;
|
|
- u16 reg16, dev_id;
|
|
int cap, err;
|
|
+ u16 reg16;
|
|
|
|
- err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id);
|
|
- if (err)
|
|
- return pcibios_err_to_errno(err);
|
|
- err = mlx5_check_dev_ids(dev, dev_id);
|
|
- if (err)
|
|
- return err;
|
|
cap = pci_find_capability(bridge, PCI_CAP_ID_EXP);
|
|
if (!cap)
|
|
return -EOPNOTSUPP;
|
|
@@ -503,64 +521,60 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
|
|
return err;
|
|
}
|
|
|
|
-static void mlx5_sync_reset_now_event(struct work_struct *work)
|
|
+static int mlx5_pci_reset_bus(struct mlx5_core_dev *dev)
|
|
{
|
|
- struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
|
|
- reset_now_work);
|
|
- struct mlx5_core_dev *dev = fw_reset->dev;
|
|
- int err;
|
|
+ if (!MLX5_CAP_GEN(dev, pcie_reset_using_hotreset_method))
|
|
+ return -EOPNOTSUPP;
|
|
|
|
- if (mlx5_sync_reset_clear_reset_requested(dev, false))
|
|
- return;
|
|
+ return pci_reset_bus(dev->pdev);
|
|
+}
|
|
|
|
- mlx5_core_warn(dev, "Sync Reset now. Device is going to reset.\n");
|
|
+static int mlx5_sync_pci_reset(struct mlx5_core_dev *dev, u8 reset_method)
|
|
+{
|
|
+ u16 dev_id;
|
|
+ int err;
|
|
|
|
- err = mlx5_cmd_fast_teardown_hca(dev);
|
|
- if (err) {
|
|
- mlx5_core_warn(dev, "Fast teardown failed, no reset done, err %d\n", err);
|
|
- goto done;
|
|
- }
|
|
+ err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id);
|
|
+ if (err)
|
|
+ return pcibios_err_to_errno(err);
|
|
+ err = mlx5_check_dev_ids(dev, dev_id);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
- err = mlx5_pci_link_toggle(dev);
|
|
- if (err) {
|
|
- mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, no reset done, err %d\n", err);
|
|
- set_bit(MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, &fw_reset->reset_flags);
|
|
+ switch (reset_method) {
|
|
+ case MLX5_MFRL_REG_PCI_RESET_METHOD_LINK_TOGGLE:
|
|
+ err = mlx5_pci_link_toggle(dev, dev_id);
|
|
+ if (err)
|
|
+ mlx5_core_warn(dev, "mlx5_pci_link_toggle failed\n");
|
|
+ break;
|
|
+ case MLX5_MFRL_REG_PCI_RESET_METHOD_HOT_RESET:
|
|
+ err = mlx5_pci_reset_bus(dev);
|
|
+ if (err)
|
|
+ mlx5_core_warn(dev, "mlx5_pci_reset_bus failed\n");
|
|
+ break;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
}
|
|
|
|
- mlx5_enter_error_state(dev, true);
|
|
-done:
|
|
- fw_reset->ret = err;
|
|
- mlx5_fw_reset_complete_reload(dev, false);
|
|
+ return err;
|
|
}
|
|
|
|
-static void mlx5_sync_reset_unload_event(struct work_struct *work)
|
|
+void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked)
|
|
{
|
|
- struct mlx5_fw_reset *fw_reset;
|
|
- struct mlx5_core_dev *dev;
|
|
+ struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
|
|
unsigned long timeout;
|
|
bool reset_action;
|
|
u8 rst_state;
|
|
int err;
|
|
|
|
- fw_reset = container_of(work, struct mlx5_fw_reset, reset_unload_work);
|
|
- dev = fw_reset->dev;
|
|
-
|
|
- if (mlx5_sync_reset_clear_reset_requested(dev, false))
|
|
- return;
|
|
-
|
|
- mlx5_core_warn(dev, "Sync Reset Unload. Function is forced down.\n");
|
|
-
|
|
- err = mlx5_cmd_fast_teardown_hca(dev);
|
|
- if (err)
|
|
- mlx5_core_warn(dev, "Fast teardown failed, unloading, err %d\n", err);
|
|
- else
|
|
- mlx5_enter_error_state(dev, true);
|
|
-
|
|
- if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags))
|
|
+ if (locked)
|
|
mlx5_unload_one_devl_locked(dev, false);
|
|
else
|
|
mlx5_unload_one(dev, false);
|
|
|
|
+ if (!test_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags))
|
|
+ return;
|
|
+
|
|
mlx5_set_fw_rst_ack(dev);
|
|
mlx5_core_warn(dev, "Sync Reset Unload done, device reset expected\n");
|
|
|
|
@@ -583,17 +597,73 @@ static void mlx5_sync_reset_unload_event(struct work_struct *work)
|
|
goto done;
|
|
}
|
|
|
|
- mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n", rst_state);
|
|
+ mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n",
|
|
+ rst_state);
|
|
if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ) {
|
|
- err = mlx5_pci_link_toggle(dev);
|
|
+ err = mlx5_sync_pci_reset(dev, fw_reset->reset_method);
|
|
if (err) {
|
|
- mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, err %d\n", err);
|
|
+ mlx5_core_warn(dev, "mlx5_sync_pci_reset failed, err %d\n",
|
|
+ err);
|
|
fw_reset->ret = err;
|
|
}
|
|
}
|
|
|
|
done:
|
|
- mlx5_fw_reset_complete_reload(dev, true);
|
|
+ clear_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags);
|
|
+}
|
|
+
|
|
+static void mlx5_sync_reset_now_event(struct work_struct *work)
|
|
+{
|
|
+ struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
|
|
+ reset_now_work);
|
|
+ struct mlx5_core_dev *dev = fw_reset->dev;
|
|
+ int err;
|
|
+
|
|
+ if (mlx5_sync_reset_clear_reset_requested(dev, false))
|
|
+ return;
|
|
+
|
|
+ mlx5_core_warn(dev, "Sync Reset now. Device is going to reset.\n");
|
|
+
|
|
+ err = mlx5_cmd_fast_teardown_hca(dev);
|
|
+ if (err) {
|
|
+ mlx5_core_warn(dev, "Fast teardown failed, no reset done, err %d\n", err);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ err = mlx5_sync_pci_reset(dev, fw_reset->reset_method);
|
|
+ if (err) {
|
|
+ mlx5_core_warn(dev, "mlx5_sync_pci_reset failed, no reset done, err %d\n", err);
|
|
+ set_bit(MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, &fw_reset->reset_flags);
|
|
+ }
|
|
+
|
|
+ mlx5_enter_error_state(dev, true);
|
|
+done:
|
|
+ fw_reset->ret = err;
|
|
+ mlx5_fw_reset_complete_reload(dev);
|
|
+}
|
|
+
|
|
+static void mlx5_sync_reset_unload_event(struct work_struct *work)
|
|
+{
|
|
+ struct mlx5_fw_reset *fw_reset;
|
|
+ struct mlx5_core_dev *dev;
|
|
+ int err;
|
|
+
|
|
+ fw_reset = container_of(work, struct mlx5_fw_reset, reset_unload_work);
|
|
+ dev = fw_reset->dev;
|
|
+
|
|
+ if (mlx5_sync_reset_clear_reset_requested(dev, false))
|
|
+ return;
|
|
+
|
|
+ set_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags);
|
|
+ mlx5_core_warn(dev, "Sync Reset Unload. Function is forced down.\n");
|
|
+
|
|
+ err = mlx5_cmd_fast_teardown_hca(dev);
|
|
+ if (err)
|
|
+ mlx5_core_warn(dev, "Fast teardown failed, unloading, err %d\n", err);
|
|
+ else
|
|
+ mlx5_enter_error_state(dev, true);
|
|
+
|
|
+ mlx5_fw_reset_complete_reload(dev);
|
|
}
|
|
|
|
static void mlx5_sync_reset_abort_event(struct work_struct *work)
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h
|
|
index ea527d06a85f07..d5b28525c960dc 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h
|
|
@@ -12,6 +12,7 @@ int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel,
|
|
int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev);
|
|
|
|
int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev);
|
|
+void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked);
|
|
int mlx5_fw_reset_verify_fw_complete(struct mlx5_core_dev *dev,
|
|
struct netlink_ext_ack *extack);
|
|
void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
|
|
index 62a85f09b52fd7..8a11e410f7c135 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
|
|
@@ -627,6 +627,9 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
|
|
if (MLX5_CAP_GEN_MAX(dev, pci_sync_for_fw_update_with_driver_unload))
|
|
MLX5_SET(cmd_hca_cap, set_hca_cap,
|
|
pci_sync_for_fw_update_with_driver_unload, 1);
|
|
+ if (MLX5_CAP_GEN_MAX(dev, pcie_reset_using_hotreset_method))
|
|
+ MLX5_SET(cmd_hca_cap, set_hca_cap,
|
|
+ pcie_reset_using_hotreset_method, 1);
|
|
|
|
if (MLX5_CAP_GEN_MAX(dev, num_vhca_ports))
|
|
MLX5_SET(cmd_hca_cap,
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
|
|
index e34a8f88c518c1..d5b2b6cfc8d21d 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
|
|
@@ -20,9 +20,16 @@ struct mlx5_sf {
|
|
u16 hw_state;
|
|
};
|
|
|
|
+static void *mlx5_sf_by_dl_port(struct devlink_port *dl_port)
|
|
+{
|
|
+ struct mlx5_devlink_port *mlx5_dl_port = mlx5_devlink_port_get(dl_port);
|
|
+
|
|
+ return container_of(mlx5_dl_port, struct mlx5_sf, dl_port);
|
|
+}
|
|
+
|
|
struct mlx5_sf_table {
|
|
struct mlx5_core_dev *dev; /* To refer from notifier context. */
|
|
- struct xarray port_indices; /* port index based lookup. */
|
|
+ struct xarray function_ids; /* function id based lookup. */
|
|
refcount_t refcount;
|
|
struct completion disable_complete;
|
|
struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */
|
|
@@ -30,33 +37,20 @@ struct mlx5_sf_table {
|
|
struct notifier_block vhca_nb;
|
|
};
|
|
|
|
-static struct mlx5_sf *
|
|
-mlx5_sf_lookup_by_index(struct mlx5_sf_table *table, unsigned int port_index)
|
|
-{
|
|
- return xa_load(&table->port_indices, port_index);
|
|
-}
|
|
-
|
|
static struct mlx5_sf *
|
|
mlx5_sf_lookup_by_function_id(struct mlx5_sf_table *table, unsigned int fn_id)
|
|
{
|
|
- unsigned long index;
|
|
- struct mlx5_sf *sf;
|
|
-
|
|
- xa_for_each(&table->port_indices, index, sf) {
|
|
- if (sf->hw_fn_id == fn_id)
|
|
- return sf;
|
|
- }
|
|
- return NULL;
|
|
+ return xa_load(&table->function_ids, fn_id);
|
|
}
|
|
|
|
-static int mlx5_sf_id_insert(struct mlx5_sf_table *table, struct mlx5_sf *sf)
|
|
+static int mlx5_sf_function_id_insert(struct mlx5_sf_table *table, struct mlx5_sf *sf)
|
|
{
|
|
- return xa_insert(&table->port_indices, sf->port_index, sf, GFP_KERNEL);
|
|
+ return xa_insert(&table->function_ids, sf->hw_fn_id, sf, GFP_KERNEL);
|
|
}
|
|
|
|
-static void mlx5_sf_id_erase(struct mlx5_sf_table *table, struct mlx5_sf *sf)
|
|
+static void mlx5_sf_function_id_erase(struct mlx5_sf_table *table, struct mlx5_sf *sf)
|
|
{
|
|
- xa_erase(&table->port_indices, sf->port_index);
|
|
+ xa_erase(&table->function_ids, sf->hw_fn_id);
|
|
}
|
|
|
|
static struct mlx5_sf *
|
|
@@ -93,7 +87,7 @@ mlx5_sf_alloc(struct mlx5_sf_table *table, struct mlx5_eswitch *esw,
|
|
sf->hw_state = MLX5_VHCA_STATE_ALLOCATED;
|
|
sf->controller = controller;
|
|
|
|
- err = mlx5_sf_id_insert(table, sf);
|
|
+ err = mlx5_sf_function_id_insert(table, sf);
|
|
if (err)
|
|
goto insert_err;
|
|
|
|
@@ -111,7 +105,6 @@ mlx5_sf_alloc(struct mlx5_sf_table *table, struct mlx5_eswitch *esw,
|
|
|
|
static void mlx5_sf_free(struct mlx5_sf_table *table, struct mlx5_sf *sf)
|
|
{
|
|
- mlx5_sf_id_erase(table, sf);
|
|
mlx5_sf_hw_table_sf_free(table->dev, sf->controller, sf->id);
|
|
trace_mlx5_sf_free(table->dev, sf->port_index, sf->controller, sf->hw_fn_id);
|
|
kfree(sf);
|
|
@@ -172,26 +165,19 @@ int mlx5_devlink_sf_port_fn_state_get(struct devlink_port *dl_port,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
struct mlx5_core_dev *dev = devlink_priv(dl_port->devlink);
|
|
+ struct mlx5_sf *sf = mlx5_sf_by_dl_port(dl_port);
|
|
struct mlx5_sf_table *table;
|
|
- struct mlx5_sf *sf;
|
|
- int err = 0;
|
|
|
|
table = mlx5_sf_table_try_get(dev);
|
|
if (!table)
|
|
return -EOPNOTSUPP;
|
|
|
|
- sf = mlx5_sf_lookup_by_index(table, dl_port->index);
|
|
- if (!sf) {
|
|
- err = -EOPNOTSUPP;
|
|
- goto sf_err;
|
|
- }
|
|
mutex_lock(&table->sf_state_lock);
|
|
*state = mlx5_sf_to_devlink_state(sf->hw_state);
|
|
*opstate = mlx5_sf_to_devlink_opstate(sf->hw_state);
|
|
mutex_unlock(&table->sf_state_lock);
|
|
-sf_err:
|
|
mlx5_sf_table_put(table);
|
|
- return err;
|
|
+ return 0;
|
|
}
|
|
|
|
static int mlx5_sf_activate(struct mlx5_core_dev *dev, struct mlx5_sf *sf,
|
|
@@ -257,8 +243,8 @@ int mlx5_devlink_sf_port_fn_state_set(struct devlink_port *dl_port,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
struct mlx5_core_dev *dev = devlink_priv(dl_port->devlink);
|
|
+ struct mlx5_sf *sf = mlx5_sf_by_dl_port(dl_port);
|
|
struct mlx5_sf_table *table;
|
|
- struct mlx5_sf *sf;
|
|
int err;
|
|
|
|
table = mlx5_sf_table_try_get(dev);
|
|
@@ -267,14 +253,7 @@ int mlx5_devlink_sf_port_fn_state_set(struct devlink_port *dl_port,
|
|
"Port state set is only supported in eswitch switchdev mode or SF ports are disabled.");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
- sf = mlx5_sf_lookup_by_index(table, dl_port->index);
|
|
- if (!sf) {
|
|
- err = -ENODEV;
|
|
- goto out;
|
|
- }
|
|
-
|
|
err = mlx5_sf_state_set(dev, table, sf, state, extack);
|
|
-out:
|
|
mlx5_sf_table_put(table);
|
|
return err;
|
|
}
|
|
@@ -301,6 +280,7 @@ static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table,
|
|
return 0;
|
|
|
|
esw_err:
|
|
+ mlx5_sf_function_id_erase(table, sf);
|
|
mlx5_sf_free(table, sf);
|
|
return err;
|
|
}
|
|
@@ -361,6 +341,8 @@ int mlx5_devlink_sf_port_new(struct devlink *devlink,
|
|
|
|
static void mlx5_sf_dealloc(struct mlx5_sf_table *table, struct mlx5_sf *sf)
|
|
{
|
|
+ mlx5_sf_function_id_erase(table, sf);
|
|
+
|
|
if (sf->hw_state == MLX5_VHCA_STATE_ALLOCATED) {
|
|
mlx5_sf_free(table, sf);
|
|
} else if (mlx5_sf_is_active(sf)) {
|
|
@@ -383,10 +365,9 @@ int mlx5_devlink_sf_port_del(struct devlink *devlink,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
struct mlx5_core_dev *dev = devlink_priv(devlink);
|
|
+ struct mlx5_sf *sf = mlx5_sf_by_dl_port(dl_port);
|
|
struct mlx5_eswitch *esw = dev->priv.eswitch;
|
|
struct mlx5_sf_table *table;
|
|
- struct mlx5_sf *sf;
|
|
- int err = 0;
|
|
|
|
table = mlx5_sf_table_try_get(dev);
|
|
if (!table) {
|
|
@@ -394,21 +375,14 @@ int mlx5_devlink_sf_port_del(struct devlink *devlink,
|
|
"Port del is only supported in eswitch switchdev mode or SF ports are disabled.");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
- sf = mlx5_sf_lookup_by_index(table, dl_port->index);
|
|
- if (!sf) {
|
|
- err = -ENODEV;
|
|
- goto sf_err;
|
|
- }
|
|
|
|
mlx5_eswitch_unload_sf_vport(esw, sf->hw_fn_id);
|
|
- mlx5_sf_id_erase(table, sf);
|
|
|
|
mutex_lock(&table->sf_state_lock);
|
|
mlx5_sf_dealloc(table, sf);
|
|
mutex_unlock(&table->sf_state_lock);
|
|
-sf_err:
|
|
mlx5_sf_table_put(table);
|
|
- return err;
|
|
+ return 0;
|
|
}
|
|
|
|
static bool mlx5_sf_state_update_check(const struct mlx5_sf *sf, u8 new_state)
|
|
@@ -471,9 +445,8 @@ static void mlx5_sf_deactivate_all(struct mlx5_sf_table *table)
|
|
/* At this point, no new user commands can start and no vhca event can
|
|
* arrive. It is safe to destroy all user created SFs.
|
|
*/
|
|
- xa_for_each(&table->port_indices, index, sf) {
|
|
+ xa_for_each(&table->function_ids, index, sf) {
|
|
mlx5_eswitch_unload_sf_vport(esw, sf->hw_fn_id);
|
|
- mlx5_sf_id_erase(table, sf);
|
|
mlx5_sf_dealloc(table, sf);
|
|
}
|
|
}
|
|
@@ -531,7 +504,7 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev)
|
|
|
|
mutex_init(&table->sf_state_lock);
|
|
table->dev = dev;
|
|
- xa_init(&table->port_indices);
|
|
+ xa_init(&table->function_ids);
|
|
dev->priv.sf_table = table;
|
|
refcount_set(&table->refcount, 0);
|
|
table->esw_nb.notifier_call = mlx5_sf_esw_event;
|
|
@@ -566,6 +539,16 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev)
|
|
mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb);
|
|
WARN_ON(refcount_read(&table->refcount));
|
|
mutex_destroy(&table->sf_state_lock);
|
|
- WARN_ON(!xa_empty(&table->port_indices));
|
|
+ WARN_ON(!xa_empty(&table->function_ids));
|
|
kfree(table);
|
|
}
|
|
+
|
|
+bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev)
|
|
+{
|
|
+ struct mlx5_sf_table *table = dev->priv.sf_table;
|
|
+
|
|
+ if (!table)
|
|
+ return true;
|
|
+
|
|
+ return xa_empty(&table->function_ids);
|
|
+}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
|
|
index 860f9ddb7107b8..89559a37997ad6 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
|
|
@@ -17,6 +17,7 @@ void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev);
|
|
|
|
int mlx5_sf_table_init(struct mlx5_core_dev *dev);
|
|
void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev);
|
|
+bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev);
|
|
|
|
int mlx5_devlink_sf_port_new(struct devlink *devlink,
|
|
const struct devlink_port_new_attrs *add_attr,
|
|
@@ -61,6 +62,11 @@ static inline void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev)
|
|
{
|
|
}
|
|
|
|
+static inline bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev)
|
|
+{
|
|
+ return true;
|
|
+}
|
|
+
|
|
#endif
|
|
|
|
#endif
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
|
index a9837985a483d8..bdb4f527289d2d 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
|
@@ -69,7 +69,7 @@ static void dwmac4_core_init(struct mac_device_info *hw,
|
|
init_waitqueue_head(&priv->tstamp_busy_wait);
|
|
}
|
|
|
|
-static void dwmac4_phylink_get_caps(struct stmmac_priv *priv)
|
|
+static void dwmac4_update_caps(struct stmmac_priv *priv)
|
|
{
|
|
if (priv->plat->tx_queues_to_use > 1)
|
|
priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD | MAC_1000HD);
|
|
@@ -1161,7 +1161,7 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
|
|
|
|
const struct stmmac_ops dwmac4_ops = {
|
|
.core_init = dwmac4_core_init,
|
|
- .phylink_get_caps = dwmac4_phylink_get_caps,
|
|
+ .update_caps = dwmac4_update_caps,
|
|
.set_mac = stmmac_set_mac,
|
|
.rx_ipc = dwmac4_rx_ipc_enable,
|
|
.rx_queue_enable = dwmac4_rx_queue_enable,
|
|
@@ -1204,7 +1204,7 @@ const struct stmmac_ops dwmac4_ops = {
|
|
|
|
const struct stmmac_ops dwmac410_ops = {
|
|
.core_init = dwmac4_core_init,
|
|
- .phylink_get_caps = dwmac4_phylink_get_caps,
|
|
+ .update_caps = dwmac4_update_caps,
|
|
.set_mac = stmmac_dwmac4_set_mac,
|
|
.rx_ipc = dwmac4_rx_ipc_enable,
|
|
.rx_queue_enable = dwmac4_rx_queue_enable,
|
|
@@ -1253,7 +1253,7 @@ const struct stmmac_ops dwmac410_ops = {
|
|
|
|
const struct stmmac_ops dwmac510_ops = {
|
|
.core_init = dwmac4_core_init,
|
|
- .phylink_get_caps = dwmac4_phylink_get_caps,
|
|
+ .update_caps = dwmac4_update_caps,
|
|
.set_mac = stmmac_dwmac4_set_mac,
|
|
.rx_ipc = dwmac4_rx_ipc_enable,
|
|
.rx_queue_enable = dwmac4_rx_queue_enable,
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
index 052566f5b7f361..0bcb378fa0bc91 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
@@ -47,6 +47,14 @@ static void dwxgmac2_core_init(struct mac_device_info *hw,
|
|
writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN);
|
|
}
|
|
|
|
+static void dwxgmac2_update_caps(struct stmmac_priv *priv)
|
|
+{
|
|
+ if (!priv->dma_cap.mbps_10_100)
|
|
+ priv->hw->link.caps &= ~(MAC_10 | MAC_100);
|
|
+ else if (!priv->dma_cap.half_duplex)
|
|
+ priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD);
|
|
+}
|
|
+
|
|
static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable)
|
|
{
|
|
u32 tx = readl(ioaddr + XGMAC_TX_CONFIG);
|
|
@@ -1583,6 +1591,7 @@ static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *
|
|
|
|
const struct stmmac_ops dwxgmac210_ops = {
|
|
.core_init = dwxgmac2_core_init,
|
|
+ .update_caps = dwxgmac2_update_caps,
|
|
.set_mac = dwxgmac2_set_mac,
|
|
.rx_ipc = dwxgmac2_rx_ipc,
|
|
.rx_queue_enable = dwxgmac2_rx_queue_enable,
|
|
@@ -1705,8 +1714,8 @@ int dwxgmac2_setup(struct stmmac_priv *priv)
|
|
mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
|
|
|
|
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
|
- MAC_1000FD | MAC_2500FD | MAC_5000FD |
|
|
- MAC_10000FD;
|
|
+ MAC_10 | MAC_100 | MAC_1000FD |
|
|
+ MAC_2500FD | MAC_5000FD | MAC_10000FD;
|
|
mac->link.duplex = 0;
|
|
mac->link.speed10 = XGMAC_CONFIG_SS_10_MII;
|
|
mac->link.speed100 = XGMAC_CONFIG_SS_100_MII;
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
|
|
index 05ea74e9379399..b2c03cb65c7cc8 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
|
|
@@ -203,10 +203,6 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
|
}
|
|
|
|
writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
|
|
-
|
|
- /* Enable MTL RX overflow */
|
|
- value = readl(ioaddr + XGMAC_MTL_QINTEN(channel));
|
|
- writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel));
|
|
}
|
|
|
|
static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
|
@@ -386,8 +382,11 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
|
|
static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
|
struct dma_features *dma_cap)
|
|
{
|
|
+ struct stmmac_priv *priv;
|
|
u32 hw_cap;
|
|
|
|
+ priv = container_of(dma_cap, struct stmmac_priv, dma_cap);
|
|
+
|
|
/* MAC HW feature 0 */
|
|
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0);
|
|
dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31;
|
|
@@ -410,6 +409,8 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
|
dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4;
|
|
dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3;
|
|
dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1;
|
|
+ if (dma_cap->mbps_1000 && priv->synopsys_id >= DWXGMAC_CORE_2_20)
|
|
+ dma_cap->mbps_10_100 = 1;
|
|
|
|
/* MAC HW feature 1 */
|
|
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
|
|
index 47fb8e1646c2e9..ee9a7d98648b01 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
|
|
@@ -300,8 +300,8 @@ struct stmmac_est;
|
|
struct stmmac_ops {
|
|
/* MAC core initialization */
|
|
void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
|
|
- /* Get phylink capabilities */
|
|
- void (*phylink_get_caps)(struct stmmac_priv *priv);
|
|
+ /* Update MAC capabilities */
|
|
+ void (*update_caps)(struct stmmac_priv *priv);
|
|
/* Enable the MAC RX/TX */
|
|
void (*set_mac)(void __iomem *ioaddr, bool enable);
|
|
/* Enable and verify that the IPC module is supported */
|
|
@@ -423,8 +423,8 @@ struct stmmac_ops {
|
|
|
|
#define stmmac_core_init(__priv, __args...) \
|
|
stmmac_do_void_callback(__priv, mac, core_init, __args)
|
|
-#define stmmac_mac_phylink_get_caps(__priv) \
|
|
- stmmac_do_void_callback(__priv, mac, phylink_get_caps, __priv)
|
|
+#define stmmac_mac_update_caps(__priv) \
|
|
+ stmmac_do_void_callback(__priv, mac, update_caps, __priv)
|
|
#define stmmac_mac_set(__priv, __args...) \
|
|
stmmac_do_void_callback(__priv, mac, set_mac, __args)
|
|
#define stmmac_rx_ipc(__priv, __args...) \
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
index 615d25a0e46be5..ff5389a8efc33a 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
@@ -1230,8 +1230,8 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
|
|
xpcs_get_interfaces(priv->hw->xpcs,
|
|
priv->phylink_config.supported_interfaces);
|
|
|
|
- /* Get the MAC specific capabilities */
|
|
- stmmac_mac_phylink_get_caps(priv);
|
|
+ /* Refresh the MAC-specific capabilities */
|
|
+ stmmac_mac_update_caps(priv);
|
|
|
|
priv->phylink_config.mac_capabilities = priv->hw->link.caps;
|
|
|
|
@@ -2426,6 +2426,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
|
|
struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue);
|
|
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
|
|
struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
|
|
+ bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported;
|
|
struct xsk_buff_pool *pool = tx_q->xsk_pool;
|
|
unsigned int entry = tx_q->cur_tx;
|
|
struct dma_desc *tx_desc = NULL;
|
|
@@ -2496,7 +2497,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
|
|
}
|
|
|
|
stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len,
|
|
- true, priv->mode, true, true,
|
|
+ csum, priv->mode, true, true,
|
|
xdp_desc.len);
|
|
|
|
stmmac_enable_dma_transmission(priv, priv->ioaddr);
|
|
@@ -4789,6 +4790,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
|
|
{
|
|
struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
|
|
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
|
|
+ bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported;
|
|
unsigned int entry = tx_q->cur_tx;
|
|
struct dma_desc *tx_desc;
|
|
dma_addr_t dma_addr;
|
|
@@ -4833,7 +4835,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
|
|
stmmac_set_desc_addr(priv, tx_desc, dma_addr);
|
|
|
|
stmmac_prepare_tx_desc(priv, tx_desc, 1, xdpf->len,
|
|
- true, priv->mode, true, true,
|
|
+ csum, priv->mode, true, true,
|
|
xdpf->len);
|
|
|
|
tx_q->tx_count_frames++;
|
|
@@ -7232,7 +7234,7 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt)
|
|
priv->rss.table[i] = ethtool_rxfh_indir_default(i,
|
|
rx_cnt);
|
|
|
|
- stmmac_mac_phylink_get_caps(priv);
|
|
+ stmmac_mac_update_caps(priv);
|
|
|
|
priv->phylink_config.mac_capabilities = priv->hw->link.caps;
|
|
|
|
diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h
|
|
index cdb343779a8fb5..4ba6e32cf6d8d1 100644
|
|
--- a/drivers/net/phy/mscc/mscc.h
|
|
+++ b/drivers/net/phy/mscc/mscc.h
|
|
@@ -476,6 +476,7 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev)
|
|
void vsc85xx_link_change_notify(struct phy_device *phydev);
|
|
void vsc8584_config_ts_intr(struct phy_device *phydev);
|
|
int vsc8584_ptp_init(struct phy_device *phydev);
|
|
+void vsc8584_ptp_deinit(struct phy_device *phydev);
|
|
int vsc8584_ptp_probe_once(struct phy_device *phydev);
|
|
int vsc8584_ptp_probe(struct phy_device *phydev);
|
|
irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev);
|
|
@@ -490,6 +491,9 @@ static inline int vsc8584_ptp_init(struct phy_device *phydev)
|
|
{
|
|
return 0;
|
|
}
|
|
+static inline void vsc8584_ptp_deinit(struct phy_device *phydev)
|
|
+{
|
|
+}
|
|
static inline int vsc8584_ptp_probe_once(struct phy_device *phydev)
|
|
{
|
|
return 0;
|
|
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
|
|
index 3de72d9cc22bd0..3a932b30f4358f 100644
|
|
--- a/drivers/net/phy/mscc/mscc_main.c
|
|
+++ b/drivers/net/phy/mscc/mscc_main.c
|
|
@@ -2337,9 +2337,7 @@ static int vsc85xx_probe(struct phy_device *phydev)
|
|
|
|
static void vsc85xx_remove(struct phy_device *phydev)
|
|
{
|
|
- struct vsc8531_private *priv = phydev->priv;
|
|
-
|
|
- skb_queue_purge(&priv->rx_skbs_list);
|
|
+ vsc8584_ptp_deinit(phydev);
|
|
}
|
|
|
|
/* Microsemi VSC85xx PHYs */
|
|
diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c
|
|
index add1a9ee721afa..1f6237705b44b7 100644
|
|
--- a/drivers/net/phy/mscc/mscc_ptp.c
|
|
+++ b/drivers/net/phy/mscc/mscc_ptp.c
|
|
@@ -1297,7 +1297,6 @@ static void vsc8584_set_input_clk_configured(struct phy_device *phydev)
|
|
|
|
static int __vsc8584_init_ptp(struct phy_device *phydev)
|
|
{
|
|
- struct vsc8531_private *vsc8531 = phydev->priv;
|
|
static const u32 ltc_seq_e[] = { 0, 400000, 0, 0, 0 };
|
|
static const u8 ltc_seq_a[] = { 8, 6, 5, 4, 2 };
|
|
u32 val;
|
|
@@ -1514,17 +1513,7 @@ static int __vsc8584_init_ptp(struct phy_device *phydev)
|
|
|
|
vsc85xx_ts_eth_cmp1_sig(phydev);
|
|
|
|
- vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp;
|
|
- vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp;
|
|
- vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp;
|
|
- vsc8531->mii_ts.ts_info = vsc85xx_ts_info;
|
|
- phydev->mii_ts = &vsc8531->mii_ts;
|
|
-
|
|
- memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps));
|
|
-
|
|
- vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps,
|
|
- &phydev->mdio.dev);
|
|
- return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock);
|
|
+ return 0;
|
|
}
|
|
|
|
void vsc8584_config_ts_intr(struct phy_device *phydev)
|
|
@@ -1551,6 +1540,16 @@ int vsc8584_ptp_init(struct phy_device *phydev)
|
|
return 0;
|
|
}
|
|
|
|
+void vsc8584_ptp_deinit(struct phy_device *phydev)
|
|
+{
|
|
+ struct vsc8531_private *vsc8531 = phydev->priv;
|
|
+
|
|
+ if (vsc8531->ptp->ptp_clock) {
|
|
+ ptp_clock_unregister(vsc8531->ptp->ptp_clock);
|
|
+ skb_queue_purge(&vsc8531->rx_skbs_list);
|
|
+ }
|
|
+}
|
|
+
|
|
irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev)
|
|
{
|
|
struct vsc8531_private *priv = phydev->priv;
|
|
@@ -1608,7 +1607,16 @@ int vsc8584_ptp_probe(struct phy_device *phydev)
|
|
|
|
vsc8531->ptp->phydev = phydev;
|
|
|
|
- return 0;
|
|
+ vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp;
|
|
+ vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp;
|
|
+ vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp;
|
|
+ vsc8531->mii_ts.ts_info = vsc85xx_ts_info;
|
|
+ phydev->mii_ts = &vsc8531->mii_ts;
|
|
+
|
|
+ memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps));
|
|
+ vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps,
|
|
+ &phydev->mdio.dev);
|
|
+ return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock);
|
|
}
|
|
|
|
int vsc8584_ptp_probe_once(struct phy_device *phydev)
|
|
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
|
index 3976bc4295dd19..eba755b584a459 100644
|
|
--- a/drivers/net/usb/qmi_wwan.c
|
|
+++ b/drivers/net/usb/qmi_wwan.c
|
|
@@ -1363,6 +1363,9 @@ static const struct usb_device_id products[] = {
|
|
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
|
|
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
|
|
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */
|
|
+ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1034, 2)}, /* Telit LE910C4-WWX */
|
|
+ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1037, 4)}, /* Telit LE910C4-WWX */
|
|
+ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1038, 3)}, /* Telit LE910C4-WWX */
|
|
{QMI_QUIRK_SET_DTR(0x1bc7, 0x103a, 0)}, /* Telit LE910C4-WWX */
|
|
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */
|
|
{QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */
|
|
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
|
|
index 4d57a4e3410546..18393800546c11 100644
|
|
--- a/drivers/of/dynamic.c
|
|
+++ b/drivers/of/dynamic.c
|
|
@@ -306,15 +306,20 @@ int of_detach_node(struct device_node *np)
|
|
}
|
|
EXPORT_SYMBOL_GPL(of_detach_node);
|
|
|
|
+void __of_prop_free(struct property *prop)
|
|
+{
|
|
+ kfree(prop->name);
|
|
+ kfree(prop->value);
|
|
+ kfree(prop);
|
|
+}
|
|
+
|
|
static void property_list_free(struct property *prop_list)
|
|
{
|
|
struct property *prop, *next;
|
|
|
|
for (prop = prop_list; prop != NULL; prop = next) {
|
|
next = prop->next;
|
|
- kfree(prop->name);
|
|
- kfree(prop->value);
|
|
- kfree(prop);
|
|
+ __of_prop_free(prop);
|
|
}
|
|
}
|
|
|
|
@@ -427,9 +432,7 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
|
|
return new;
|
|
|
|
err_free:
|
|
- kfree(new->name);
|
|
- kfree(new->value);
|
|
- kfree(new);
|
|
+ __of_prop_free(new);
|
|
return NULL;
|
|
}
|
|
|
|
@@ -471,9 +474,7 @@ struct device_node *__of_node_dup(const struct device_node *np,
|
|
if (!new_pp)
|
|
goto err_prop;
|
|
if (__of_add_property(node, new_pp)) {
|
|
- kfree(new_pp->name);
|
|
- kfree(new_pp->value);
|
|
- kfree(new_pp);
|
|
+ __of_prop_free(new_pp);
|
|
goto err_prop;
|
|
}
|
|
}
|
|
@@ -934,12 +935,14 @@ static int of_changeset_add_prop_helper(struct of_changeset *ocs,
|
|
|
|
ret = of_changeset_add_property(ocs, np, new_pp);
|
|
if (ret) {
|
|
- kfree(new_pp->name);
|
|
- kfree(new_pp->value);
|
|
- kfree(new_pp);
|
|
+ __of_prop_free(new_pp);
|
|
+ return ret;
|
|
}
|
|
|
|
- return ret;
|
|
+ new_pp->next = np->deadprops;
|
|
+ np->deadprops = new_pp;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
|
|
index 21f8f5e80917d1..73b55f4f84a3cc 100644
|
|
--- a/drivers/of/of_private.h
|
|
+++ b/drivers/of/of_private.h
|
|
@@ -123,6 +123,7 @@ extern void *__unflatten_device_tree(const void *blob,
|
|
* own the devtree lock or work on detached trees only.
|
|
*/
|
|
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
|
|
+void __of_prop_free(struct property *prop);
|
|
struct device_node *__of_node_dup(const struct device_node *np,
|
|
const char *full_name);
|
|
|
|
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
|
|
index a9a292d6d59b26..dc13299586414f 100644
|
|
--- a/drivers/of/overlay.c
|
|
+++ b/drivers/of/overlay.c
|
|
@@ -262,9 +262,7 @@ static struct property *dup_and_fixup_symbol_prop(
|
|
return new_prop;
|
|
|
|
err_free_new_prop:
|
|
- kfree(new_prop->name);
|
|
- kfree(new_prop->value);
|
|
- kfree(new_prop);
|
|
+ __of_prop_free(new_prop);
|
|
err_free_target_path:
|
|
kfree(target_path);
|
|
|
|
@@ -361,11 +359,8 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
|
|
pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n",
|
|
target->np, new_prop->name);
|
|
|
|
- if (ret) {
|
|
- kfree(new_prop->name);
|
|
- kfree(new_prop->value);
|
|
- kfree(new_prop);
|
|
- }
|
|
+ if (ret)
|
|
+ __of_prop_free(new_prop);
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
|
|
index 3b22c36bfb0b7c..5bfec440b4fd70 100644
|
|
--- a/drivers/of/unittest.c
|
|
+++ b/drivers/of/unittest.c
|
|
@@ -800,15 +800,11 @@ static void __init of_unittest_property_copy(void)
|
|
|
|
new = __of_prop_dup(&p1, GFP_KERNEL);
|
|
unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
|
|
- kfree(new->value);
|
|
- kfree(new->name);
|
|
- kfree(new);
|
|
+ __of_prop_free(new);
|
|
|
|
new = __of_prop_dup(&p2, GFP_KERNEL);
|
|
unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
|
|
- kfree(new->value);
|
|
- kfree(new->name);
|
|
- kfree(new);
|
|
+ __of_prop_free(new);
|
|
#endif
|
|
}
|
|
|
|
@@ -3665,9 +3661,7 @@ static __init void of_unittest_overlay_high_level(void)
|
|
goto err_unlock;
|
|
}
|
|
if (__of_add_property(of_symbols, new_prop)) {
|
|
- kfree(new_prop->name);
|
|
- kfree(new_prop->value);
|
|
- kfree(new_prop);
|
|
+ __of_prop_free(new_prop);
|
|
/* "name" auto-generated by unflatten */
|
|
if (!strcmp(prop->name, "name"))
|
|
continue;
|
|
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
|
|
index 7dfb7190580efa..ab3908a923e3a0 100644
|
|
--- a/drivers/pinctrl/Kconfig
|
|
+++ b/drivers/pinctrl/Kconfig
|
|
@@ -438,6 +438,7 @@ config PINCTRL_STMFX
|
|
tristate "STMicroelectronics STMFX GPIO expander pinctrl driver"
|
|
depends on I2C
|
|
depends on OF_GPIO
|
|
+ depends on HAS_IOMEM
|
|
select GENERIC_PINCONF
|
|
select GPIOLIB_IRQCHIP
|
|
select MFD_STMFX
|
|
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
|
|
index 24f6eefb68030d..df37ac81620e62 100644
|
|
--- a/drivers/scsi/scsi_sysfs.c
|
|
+++ b/drivers/scsi/scsi_sysfs.c
|
|
@@ -265,7 +265,7 @@ show_shost_supported_mode(struct device *dev, struct device_attribute *attr,
|
|
return show_shost_mode(supported_mode, buf);
|
|
}
|
|
|
|
-static DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL);
|
|
+static DEVICE_ATTR(supported_mode, S_IRUGO, show_shost_supported_mode, NULL);
|
|
|
|
static ssize_t
|
|
show_shost_active_mode(struct device *dev,
|
|
@@ -279,7 +279,7 @@ show_shost_active_mode(struct device *dev,
|
|
return show_shost_mode(shost->active_mode, buf);
|
|
}
|
|
|
|
-static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL);
|
|
+static DEVICE_ATTR(active_mode, S_IRUGO, show_shost_active_mode, NULL);
|
|
|
|
static int check_reset_type(const char *str)
|
|
{
|
|
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
|
|
index f2ed7167c84809..5ad237d77a9a9f 100644
|
|
--- a/drivers/vhost/net.c
|
|
+++ b/drivers/vhost/net.c
|
|
@@ -96,6 +96,7 @@ struct vhost_net_ubuf_ref {
|
|
atomic_t refcount;
|
|
wait_queue_head_t wait;
|
|
struct vhost_virtqueue *vq;
|
|
+ struct rcu_head rcu;
|
|
};
|
|
|
|
#define VHOST_NET_BATCH 64
|
|
@@ -249,9 +250,13 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy)
|
|
|
|
static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs)
|
|
{
|
|
- int r = atomic_sub_return(1, &ubufs->refcount);
|
|
+ int r;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ r = atomic_sub_return(1, &ubufs->refcount);
|
|
if (unlikely(!r))
|
|
wake_up(&ubufs->wait);
|
|
+ rcu_read_unlock();
|
|
return r;
|
|
}
|
|
|
|
@@ -264,7 +269,7 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
|
|
static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
|
|
{
|
|
vhost_net_ubuf_put_and_wait(ubufs);
|
|
- kfree(ubufs);
|
|
+ kfree_rcu(ubufs, rcu);
|
|
}
|
|
|
|
static void vhost_net_clear_ubuf_info(struct vhost_net *n)
|
|
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
|
|
index 586c5709dfb554..34438981ddd805 100644
|
|
--- a/fs/efivarfs/super.c
|
|
+++ b/fs/efivarfs/super.c
|
|
@@ -90,6 +90,10 @@ static int efivarfs_d_compare(const struct dentry *dentry,
|
|
{
|
|
int guid = len - EFI_VARIABLE_GUID_LEN;
|
|
|
|
+ /* Parallel lookups may produce a temporary invalid filename */
|
|
+ if (guid <= 0)
|
|
+ return 1;
|
|
+
|
|
if (name->len != len)
|
|
return 1;
|
|
|
|
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
|
|
index d852b43ac43e32..c1f802ecc47b2c 100644
|
|
--- a/fs/erofs/zdata.c
|
|
+++ b/fs/erofs/zdata.c
|
|
@@ -1401,6 +1401,16 @@ static void z_erofs_decompressqueue_kthread_work(struct kthread_work *work)
|
|
}
|
|
#endif
|
|
|
|
+/* Use (kthread_)work in atomic contexts to minimize scheduling overhead */
|
|
+static inline bool z_erofs_in_atomic(void)
|
|
+{
|
|
+ if (IS_ENABLED(CONFIG_PREEMPTION) && rcu_preempt_depth())
|
|
+ return true;
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
|
|
+ return true;
|
|
+ return !preemptible();
|
|
+}
|
|
+
|
|
static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
|
|
int bios)
|
|
{
|
|
@@ -1415,8 +1425,7 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
|
|
|
|
if (atomic_add_return(bios, &io->pending_bios))
|
|
return;
|
|
- /* Use (kthread_)work and sync decompression for atomic contexts only */
|
|
- if (!in_task() || irqs_disabled() || rcu_read_lock_any_held()) {
|
|
+ if (z_erofs_in_atomic()) {
|
|
#ifdef CONFIG_EROFS_FS_PCPU_KTHREAD
|
|
struct kthread_worker *worker;
|
|
|
|
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
|
|
index 040b6b79c75e59..0ea3916ed1dcb1 100644
|
|
--- a/fs/nfs/pagelist.c
|
|
+++ b/fs/nfs/pagelist.c
|
|
@@ -206,83 +206,6 @@ nfs_page_group_lock_head(struct nfs_page *req)
|
|
return head;
|
|
}
|
|
|
|
-/*
|
|
- * nfs_unroll_locks - unlock all newly locked reqs and wait on @req
|
|
- * @head: head request of page group, must be holding head lock
|
|
- * @req: request that couldn't lock and needs to wait on the req bit lock
|
|
- *
|
|
- * This is a helper function for nfs_lock_and_join_requests
|
|
- * returns 0 on success, < 0 on error.
|
|
- */
|
|
-static void
|
|
-nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
|
|
-{
|
|
- struct nfs_page *tmp;
|
|
-
|
|
- /* relinquish all the locks successfully grabbed this run */
|
|
- for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
|
|
- if (!kref_read(&tmp->wb_kref))
|
|
- continue;
|
|
- nfs_unlock_and_release_request(tmp);
|
|
- }
|
|
-}
|
|
-
|
|
-/*
|
|
- * nfs_page_group_lock_subreq - try to lock a subrequest
|
|
- * @head: head request of page group
|
|
- * @subreq: request to lock
|
|
- *
|
|
- * This is a helper function for nfs_lock_and_join_requests which
|
|
- * must be called with the head request and page group both locked.
|
|
- * On error, it returns with the page group unlocked.
|
|
- */
|
|
-static int
|
|
-nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- if (!kref_get_unless_zero(&subreq->wb_kref))
|
|
- return 0;
|
|
- while (!nfs_lock_request(subreq)) {
|
|
- nfs_page_group_unlock(head);
|
|
- ret = nfs_wait_on_request(subreq);
|
|
- if (!ret)
|
|
- ret = nfs_page_group_lock(head);
|
|
- if (ret < 0) {
|
|
- nfs_unroll_locks(head, subreq);
|
|
- nfs_release_request(subreq);
|
|
- return ret;
|
|
- }
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * nfs_page_group_lock_subrequests - try to lock the subrequests
|
|
- * @head: head request of page group
|
|
- *
|
|
- * This is a helper function for nfs_lock_and_join_requests which
|
|
- * must be called with the head request locked.
|
|
- */
|
|
-int nfs_page_group_lock_subrequests(struct nfs_page *head)
|
|
-{
|
|
- struct nfs_page *subreq;
|
|
- int ret;
|
|
-
|
|
- ret = nfs_page_group_lock(head);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
- /* lock each request in the page group */
|
|
- for (subreq = head->wb_this_page; subreq != head;
|
|
- subreq = subreq->wb_this_page) {
|
|
- ret = nfs_page_group_lock_subreq(head, subreq);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
- }
|
|
- nfs_page_group_unlock(head);
|
|
- return 0;
|
|
-}
|
|
-
|
|
/*
|
|
* nfs_page_set_headlock - set the request PG_HEADLOCK
|
|
* @req: request that is to be locked
|
|
@@ -349,13 +272,14 @@ nfs_page_group_unlock(struct nfs_page *req)
|
|
nfs_page_clear_headlock(req);
|
|
}
|
|
|
|
-/*
|
|
- * nfs_page_group_sync_on_bit_locked
|
|
+/**
|
|
+ * nfs_page_group_sync_on_bit_locked - Test if all requests have @bit set
|
|
+ * @req: request in page group
|
|
+ * @bit: PG_* bit that is used to sync page group
|
|
*
|
|
* must be called with page group lock held
|
|
*/
|
|
-static bool
|
|
-nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
|
|
+bool nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
|
|
{
|
|
struct nfs_page *head = req->wb_head;
|
|
struct nfs_page *tmp;
|
|
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
|
|
index 7d03811f44a4bb..cb1e9996fcc8ec 100644
|
|
--- a/fs/nfs/write.c
|
|
+++ b/fs/nfs/write.c
|
|
@@ -156,20 +156,10 @@ nfs_page_set_inode_ref(struct nfs_page *req, struct inode *inode)
|
|
}
|
|
}
|
|
|
|
-static int
|
|
-nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode)
|
|
+static void nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode)
|
|
{
|
|
- int ret;
|
|
-
|
|
- if (!test_bit(PG_REMOVE, &req->wb_flags))
|
|
- return 0;
|
|
- ret = nfs_page_group_lock(req);
|
|
- if (ret)
|
|
- return ret;
|
|
if (test_and_clear_bit(PG_REMOVE, &req->wb_flags))
|
|
nfs_page_set_inode_ref(req, inode);
|
|
- nfs_page_group_unlock(req);
|
|
- return 0;
|
|
}
|
|
|
|
static struct nfs_page *nfs_folio_private_request(struct folio *folio)
|
|
@@ -238,36 +228,6 @@ static struct nfs_page *nfs_folio_find_head_request(struct folio *folio)
|
|
return req;
|
|
}
|
|
|
|
-static struct nfs_page *nfs_folio_find_and_lock_request(struct folio *folio)
|
|
-{
|
|
- struct inode *inode = folio_file_mapping(folio)->host;
|
|
- struct nfs_page *req, *head;
|
|
- int ret;
|
|
-
|
|
- for (;;) {
|
|
- req = nfs_folio_find_head_request(folio);
|
|
- if (!req)
|
|
- return req;
|
|
- head = nfs_page_group_lock_head(req);
|
|
- if (head != req)
|
|
- nfs_release_request(req);
|
|
- if (IS_ERR(head))
|
|
- return head;
|
|
- ret = nfs_cancel_remove_inode(head, inode);
|
|
- if (ret < 0) {
|
|
- nfs_unlock_and_release_request(head);
|
|
- return ERR_PTR(ret);
|
|
- }
|
|
- /* Ensure that nobody removed the request before we locked it */
|
|
- if (head == nfs_folio_private_request(folio))
|
|
- break;
|
|
- if (folio_test_swapcache(folio))
|
|
- break;
|
|
- nfs_unlock_and_release_request(head);
|
|
- }
|
|
- return head;
|
|
-}
|
|
-
|
|
/* Adjust the file length if we're writing beyond the end */
|
|
static void nfs_grow_file(struct folio *folio, unsigned int offset,
|
|
unsigned int count)
|
|
@@ -548,6 +508,57 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
|
|
nfs_destroy_unlinked_subrequests(destroy_list, head, inode);
|
|
}
|
|
|
|
+/*
|
|
+ * nfs_unroll_locks - unlock all newly locked reqs and wait on @req
|
|
+ * @head: head request of page group, must be holding head lock
|
|
+ * @req: request that couldn't lock and needs to wait on the req bit lock
|
|
+ *
|
|
+ * This is a helper function for nfs_lock_and_join_requests
|
|
+ * returns 0 on success, < 0 on error.
|
|
+ */
|
|
+static void
|
|
+nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
|
|
+{
|
|
+ struct nfs_page *tmp;
|
|
+
|
|
+ /* relinquish all the locks successfully grabbed this run */
|
|
+ for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
|
|
+ if (!kref_read(&tmp->wb_kref))
|
|
+ continue;
|
|
+ nfs_unlock_and_release_request(tmp);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nfs_page_group_lock_subreq - try to lock a subrequest
|
|
+ * @head: head request of page group
|
|
+ * @subreq: request to lock
|
|
+ *
|
|
+ * This is a helper function for nfs_lock_and_join_requests which
|
|
+ * must be called with the head request and page group both locked.
|
|
+ * On error, it returns with the page group unlocked.
|
|
+ */
|
|
+static int
|
|
+nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (!kref_get_unless_zero(&subreq->wb_kref))
|
|
+ return 0;
|
|
+ while (!nfs_lock_request(subreq)) {
|
|
+ nfs_page_group_unlock(head);
|
|
+ ret = nfs_wait_on_request(subreq);
|
|
+ if (!ret)
|
|
+ ret = nfs_page_group_lock(head);
|
|
+ if (ret < 0) {
|
|
+ nfs_unroll_locks(head, subreq);
|
|
+ nfs_release_request(subreq);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
* nfs_lock_and_join_requests - join all subreqs to the head req
|
|
* @folio: the folio used to lookup the "page group" of nfs_page structures
|
|
@@ -566,30 +577,59 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
|
|
static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
|
|
{
|
|
struct inode *inode = folio_file_mapping(folio)->host;
|
|
- struct nfs_page *head;
|
|
+ struct nfs_page *head, *subreq;
|
|
struct nfs_commit_info cinfo;
|
|
int ret;
|
|
|
|
- nfs_init_cinfo_from_inode(&cinfo, inode);
|
|
/*
|
|
* A reference is taken only on the head request which acts as a
|
|
* reference to the whole page group - the group will not be destroyed
|
|
* until the head reference is released.
|
|
*/
|
|
- head = nfs_folio_find_and_lock_request(folio);
|
|
- if (IS_ERR_OR_NULL(head))
|
|
- return head;
|
|
+retry:
|
|
+ head = nfs_folio_find_head_request(folio);
|
|
+ if (!head)
|
|
+ return NULL;
|
|
|
|
- /* lock each request in the page group */
|
|
- ret = nfs_page_group_lock_subrequests(head);
|
|
- if (ret < 0) {
|
|
+ while (!nfs_lock_request(head)) {
|
|
+ ret = nfs_wait_on_request(head);
|
|
+ if (ret < 0) {
|
|
+ nfs_release_request(head);
|
|
+ return ERR_PTR(ret);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = nfs_page_group_lock(head);
|
|
+ if (ret < 0)
|
|
+ goto out_unlock;
|
|
+
|
|
+ /* Ensure that nobody removed the request before we locked it */
|
|
+ if (head != folio->private && !folio_test_swapcache(folio)) {
|
|
+ nfs_page_group_unlock(head);
|
|
nfs_unlock_and_release_request(head);
|
|
- return ERR_PTR(ret);
|
|
+ goto retry;
|
|
}
|
|
|
|
- nfs_join_page_group(head, &cinfo, inode);
|
|
+ nfs_cancel_remove_inode(head, inode);
|
|
+
|
|
+ /* lock each request in the page group */
|
|
+ for (subreq = head->wb_this_page;
|
|
+ subreq != head;
|
|
+ subreq = subreq->wb_this_page) {
|
|
+ ret = nfs_page_group_lock_subreq(head, subreq);
|
|
+ if (ret < 0)
|
|
+ goto out_unlock;
|
|
+ }
|
|
|
|
+ nfs_page_group_unlock(head);
|
|
+
|
|
+ nfs_init_cinfo_from_inode(&cinfo, inode);
|
|
+ nfs_join_page_group(head, &cinfo, inode);
|
|
return head;
|
|
+
|
|
+out_unlock:
|
|
+ nfs_unlock_and_release_request(head);
|
|
+ return ERR_PTR(ret);
|
|
}
|
|
|
|
static void nfs_write_error(struct nfs_page *req, int error)
|
|
@@ -792,7 +832,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
|
{
|
|
struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req));
|
|
|
|
- if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) {
|
|
+ nfs_page_group_lock(req);
|
|
+ if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) {
|
|
struct folio *folio = nfs_page_to_folio(req->wb_head);
|
|
struct address_space *mapping = folio_file_mapping(folio);
|
|
|
|
@@ -804,6 +845,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
|
}
|
|
spin_unlock(&mapping->private_lock);
|
|
}
|
|
+ nfs_page_group_unlock(req);
|
|
|
|
if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
|
|
atomic_long_dec(&nfsi->nrequests);
|
|
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
|
|
index a1ab95f382d566..2744d5580d195f 100644
|
|
--- a/fs/smb/client/cifsfs.c
|
|
+++ b/fs/smb/client/cifsfs.c
|
|
@@ -1371,6 +1371,20 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
|
|
netfs_resize_file(&target_cifsi->netfs, new_size);
|
|
fscache_resize_cookie(cifs_inode_cookie(target_inode),
|
|
new_size);
|
|
+ } else if (rc == -EOPNOTSUPP) {
|
|
+ /*
|
|
+ * copy_file_range syscall man page indicates EINVAL
|
|
+ * is returned e.g when "fd_in and fd_out refer to the
|
|
+ * same file and the source and target ranges overlap."
|
|
+ * Test generic/157 was what showed these cases where
|
|
+ * we need to remap EOPNOTSUPP to EINVAL
|
|
+ */
|
|
+ if (off >= src_inode->i_size) {
|
|
+ rc = -EINVAL;
|
|
+ } else if (src_inode == target_inode) {
|
|
+ if (off + len > destoff)
|
|
+ rc = -EINVAL;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
|
|
index d93ebd58ecae16..6c16c4f34d8824 100644
|
|
--- a/fs/smb/client/inode.c
|
|
+++ b/fs/smb/client/inode.c
|
|
@@ -1856,15 +1856,24 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
|
struct tcon_link *tlink;
|
|
struct cifs_tcon *tcon;
|
|
+ __u32 dosattr = 0, origattr = 0;
|
|
struct TCP_Server_Info *server;
|
|
struct iattr *attrs = NULL;
|
|
- __u32 dosattr = 0, origattr = 0;
|
|
+ bool rehash = false;
|
|
|
|
cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
|
|
|
|
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
|
return -EIO;
|
|
|
|
+ /* Unhash dentry in advance to prevent any concurrent opens */
|
|
+ spin_lock(&dentry->d_lock);
|
|
+ if (!d_unhashed(dentry)) {
|
|
+ __d_drop(dentry);
|
|
+ rehash = true;
|
|
+ }
|
|
+ spin_unlock(&dentry->d_lock);
|
|
+
|
|
tlink = cifs_sb_tlink(cifs_sb);
|
|
if (IS_ERR(tlink))
|
|
return PTR_ERR(tlink);
|
|
@@ -1915,7 +1924,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
cifs_drop_nlink(inode);
|
|
}
|
|
} else if (rc == -ENOENT) {
|
|
- d_drop(dentry);
|
|
+ if (simple_positive(dentry))
|
|
+ d_delete(dentry);
|
|
} else if (rc == -EBUSY) {
|
|
if (server->ops->rename_pending_delete) {
|
|
rc = server->ops->rename_pending_delete(full_path,
|
|
@@ -1968,6 +1978,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
kfree(attrs);
|
|
free_xid(xid);
|
|
cifs_put_tlink(tlink);
|
|
+ if (rehash)
|
|
+ d_rehash(dentry);
|
|
return rc;
|
|
}
|
|
|
|
@@ -2367,6 +2379,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct tcon_link *tlink;
|
|
struct cifs_tcon *tcon;
|
|
+ bool rehash = false;
|
|
unsigned int xid;
|
|
int rc, tmprc;
|
|
int retry_count = 0;
|
|
@@ -2382,6 +2395,17 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
|
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
|
return -EIO;
|
|
|
|
+ /*
|
|
+ * Prevent any concurrent opens on the target by unhashing the dentry.
|
|
+ * VFS already unhashes the target when renaming directories.
|
|
+ */
|
|
+ if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) {
|
|
+ if (!d_unhashed(target_dentry)) {
|
|
+ d_drop(target_dentry);
|
|
+ rehash = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
tlink = cifs_sb_tlink(cifs_sb);
|
|
if (IS_ERR(tlink))
|
|
return PTR_ERR(tlink);
|
|
@@ -2421,6 +2445,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
|
}
|
|
}
|
|
|
|
+ if (!rc)
|
|
+ rehash = false;
|
|
/*
|
|
* No-replace is the natural behavior for CIFS, so skip unlink hacks.
|
|
*/
|
|
@@ -2479,12 +2505,16 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
|
goto cifs_rename_exit;
|
|
rc = cifs_do_rename(xid, source_dentry, from_name,
|
|
target_dentry, to_name);
|
|
+ if (!rc)
|
|
+ rehash = false;
|
|
}
|
|
|
|
/* force revalidate to go get info when needed */
|
|
CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
|
|
|
|
cifs_rename_exit:
|
|
+ if (rehash)
|
|
+ d_rehash(target_dentry);
|
|
kfree(info_buf_source);
|
|
free_dentry_path(page2);
|
|
free_dentry_path(page1);
|
|
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
|
|
index e1078a1decdfa3..0cc80f472432ad 100644
|
|
--- a/fs/smb/client/smb2inode.c
|
|
+++ b/fs/smb/client/smb2inode.c
|
|
@@ -206,8 +206,10 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|
server = cifs_pick_channel(ses);
|
|
|
|
vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
|
|
- if (vars == NULL)
|
|
- return -ENOMEM;
|
|
+ if (vars == NULL) {
|
|
+ rc = -ENOMEM;
|
|
+ goto out;
|
|
+ }
|
|
rqst = &vars->rqst[0];
|
|
rsp_iov = &vars->rsp_iov[0];
|
|
|
|
@@ -828,6 +830,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|
smb2_should_replay(tcon, &retries, &cur_sleep))
|
|
goto replay_again;
|
|
|
|
+out:
|
|
if (cfile)
|
|
cifsFileInfo_put(cfile);
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
|
|
index 54de405cbab5ac..4d369876487bde 100644
|
|
--- a/fs/xfs/libxfs/xfs_attr_remote.c
|
|
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
|
|
@@ -418,6 +418,13 @@ xfs_attr_rmtval_get(
|
|
dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
|
|
error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
|
|
0, &bp, &xfs_attr3_rmt_buf_ops);
|
|
+ /*
|
|
+ * ENODATA from disk implies a disk medium failure;
|
|
+ * ENODATA for xattrs means attribute not found, so
|
|
+ * disambiguate that here.
|
|
+ */
|
|
+ if (error == -ENODATA)
|
|
+ error = -EIO;
|
|
if (error)
|
|
return error;
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
|
|
index 28bbfc31039c0e..1efd45076ee2ae 100644
|
|
--- a/fs/xfs/libxfs/xfs_da_btree.c
|
|
+++ b/fs/xfs/libxfs/xfs_da_btree.c
|
|
@@ -2649,6 +2649,12 @@ xfs_da_read_buf(
|
|
|
|
error = xfs_trans_read_buf_map(mp, tp, mp->m_ddev_targp, mapp, nmap, 0,
|
|
&bp, ops);
|
|
+ /*
|
|
+ * ENODATA from disk implies a disk medium failure; ENODATA for
|
|
+ * xattrs means attribute not found, so disambiguate that here.
|
|
+ */
|
|
+ if (error == -ENODATA && whichfork == XFS_ATTR_FORK)
|
|
+ error = -EIO;
|
|
if (error)
|
|
goto out_free;
|
|
|
|
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
|
|
index 45f2f278b50a8a..70807c679f1abc 100644
|
|
--- a/include/linux/atmdev.h
|
|
+++ b/include/linux/atmdev.h
|
|
@@ -185,6 +185,7 @@ struct atmdev_ops { /* only send is required */
|
|
int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd,
|
|
void __user *arg);
|
|
#endif
|
|
+ int (*pre_send)(struct atm_vcc *vcc, struct sk_buff *skb);
|
|
int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
|
|
int (*send_bh)(struct atm_vcc *vcc, struct sk_buff *skb);
|
|
int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags);
|
|
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
|
|
index 9106771bb92f01..4913d364e97747 100644
|
|
--- a/include/linux/mlx5/mlx5_ifc.h
|
|
+++ b/include/linux/mlx5/mlx5_ifc.h
|
|
@@ -1731,7 +1731,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
|
|
u8 reserved_at_328[0x2];
|
|
u8 relaxed_ordering_read[0x1];
|
|
u8 log_max_pd[0x5];
|
|
- u8 reserved_at_330[0x6];
|
|
+ u8 reserved_at_330[0x5];
|
|
+ u8 pcie_reset_using_hotreset_method[0x1];
|
|
u8 pci_sync_for_fw_update_with_driver_unload[0x1];
|
|
u8 vnic_env_cnt_steering_fail[0x1];
|
|
u8 vport_counter_local_loopback[0x1];
|
|
@@ -10824,6 +10825,11 @@ struct mlx5_ifc_mcda_reg_bits {
|
|
u8 data[][0x20];
|
|
};
|
|
|
|
+enum {
|
|
+ MLX5_MFRL_REG_PCI_RESET_METHOD_LINK_TOGGLE = 0,
|
|
+ MLX5_MFRL_REG_PCI_RESET_METHOD_HOT_RESET = 1,
|
|
+};
|
|
+
|
|
enum {
|
|
MLX5_MFRL_REG_RESET_STATE_IDLE = 0,
|
|
MLX5_MFRL_REG_RESET_STATE_IN_NEGOTIATION = 1,
|
|
@@ -10851,7 +10857,8 @@ struct mlx5_ifc_mfrl_reg_bits {
|
|
u8 pci_sync_for_fw_update_start[0x1];
|
|
u8 pci_sync_for_fw_update_resp[0x2];
|
|
u8 rst_type_sel[0x3];
|
|
- u8 reserved_at_28[0x4];
|
|
+ u8 pci_reset_req_method[0x3];
|
|
+ u8 reserved_at_2b[0x1];
|
|
u8 reset_state[0x4];
|
|
u8 reset_type[0x8];
|
|
u8 reset_level[0x8];
|
|
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
|
|
index 1c315f854ea801..6a46069c5a3689 100644
|
|
--- a/include/linux/nfs_page.h
|
|
+++ b/include/linux/nfs_page.h
|
|
@@ -156,13 +156,13 @@ extern int nfs_wait_on_request(struct nfs_page *);
|
|
extern void nfs_unlock_request(struct nfs_page *req);
|
|
extern void nfs_unlock_and_release_request(struct nfs_page *);
|
|
extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req);
|
|
-extern int nfs_page_group_lock_subrequests(struct nfs_page *head);
|
|
extern void nfs_join_page_group(struct nfs_page *head,
|
|
struct nfs_commit_info *cinfo,
|
|
struct inode *inode);
|
|
extern int nfs_page_group_lock(struct nfs_page *);
|
|
extern void nfs_page_group_unlock(struct nfs_page *);
|
|
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
|
|
+extern bool nfs_page_group_sync_on_bit_locked(struct nfs_page *, unsigned int);
|
|
extern int nfs_page_set_headlock(struct nfs_page *req);
|
|
extern void nfs_page_clear_headlock(struct nfs_page *req);
|
|
extern bool nfs_async_iocounter_wait(struct rpc_task *, struct nfs_lock_context *);
|
|
diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
|
|
index 3cb2d10cac930b..e2e588b08fe90a 100644
|
|
--- a/include/net/bluetooth/hci_sync.h
|
|
+++ b/include/net/bluetooth/hci_sync.h
|
|
@@ -72,7 +72,7 @@ int hci_update_class_sync(struct hci_dev *hdev);
|
|
|
|
int hci_update_eir_sync(struct hci_dev *hdev);
|
|
int hci_update_class_sync(struct hci_dev *hdev);
|
|
-int hci_update_name_sync(struct hci_dev *hdev);
|
|
+int hci_update_name_sync(struct hci_dev *hdev, const u8 *name);
|
|
int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
|
|
|
|
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
|
|
diff --git a/include/net/rose.h b/include/net/rose.h
|
|
index 23267b4efcfa32..2b5491bbf39ab5 100644
|
|
--- a/include/net/rose.h
|
|
+++ b/include/net/rose.h
|
|
@@ -8,6 +8,7 @@
|
|
#ifndef _ROSE_H
|
|
#define _ROSE_H
|
|
|
|
+#include <linux/refcount.h>
|
|
#include <linux/rose.h>
|
|
#include <net/ax25.h>
|
|
#include <net/sock.h>
|
|
@@ -96,7 +97,7 @@ struct rose_neigh {
|
|
ax25_cb *ax25;
|
|
struct net_device *dev;
|
|
unsigned short count;
|
|
- unsigned short use;
|
|
+ refcount_t use;
|
|
unsigned int number;
|
|
char restarted;
|
|
char dce_mode;
|
|
@@ -151,6 +152,21 @@ struct rose_sock {
|
|
|
|
#define rose_sk(sk) ((struct rose_sock *)(sk))
|
|
|
|
+static inline void rose_neigh_hold(struct rose_neigh *rose_neigh)
|
|
+{
|
|
+ refcount_inc(&rose_neigh->use);
|
|
+}
|
|
+
|
|
+static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
|
|
+{
|
|
+ if (refcount_dec_and_test(&rose_neigh->use)) {
|
|
+ if (rose_neigh->ax25)
|
|
+ ax25_cb_put(rose_neigh->ax25);
|
|
+ kfree(rose_neigh->digipeat);
|
|
+ kfree(rose_neigh);
|
|
+ }
|
|
+}
|
|
+
|
|
/* af_rose.c */
|
|
extern ax25_address rose_callsign;
|
|
extern int sysctl_rose_restart_request_timeout;
|
|
diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
|
|
index b481c48a31a630..6b0be9598a973f 100644
|
|
--- a/kernel/dma/pool.c
|
|
+++ b/kernel/dma/pool.c
|
|
@@ -102,8 +102,8 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
|
|
|
|
#ifdef CONFIG_DMA_DIRECT_REMAP
|
|
addr = dma_common_contiguous_remap(page, pool_size,
|
|
- pgprot_dmacoherent(PAGE_KERNEL),
|
|
- __builtin_return_address(0));
|
|
+ pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)),
|
|
+ __builtin_return_address(0));
|
|
if (!addr)
|
|
goto free_page;
|
|
#else
|
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
|
index 907e45361939be..a32c8637503d14 100644
|
|
--- a/kernel/trace/trace.c
|
|
+++ b/kernel/trace/trace.c
|
|
@@ -10162,10 +10162,10 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
|
|
ret = print_trace_line(&iter);
|
|
if (ret != TRACE_TYPE_NO_CONSUME)
|
|
trace_consume(&iter);
|
|
+
|
|
+ trace_printk_seq(&iter.seq);
|
|
}
|
|
touch_nmi_watchdog();
|
|
-
|
|
- trace_printk_seq(&iter.seq);
|
|
}
|
|
|
|
if (!cnt)
|
|
diff --git a/net/atm/common.c b/net/atm/common.c
|
|
index 9cc82acbc73588..48bb3f66a3f2ab 100644
|
|
--- a/net/atm/common.c
|
|
+++ b/net/atm/common.c
|
|
@@ -635,18 +635,27 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
|
|
|
|
skb->dev = NULL; /* for paths shared with net_device interfaces */
|
|
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
|
|
- atm_return_tx(vcc, skb);
|
|
- kfree_skb(skb);
|
|
error = -EFAULT;
|
|
- goto out;
|
|
+ goto free_skb;
|
|
}
|
|
if (eff != size)
|
|
memset(skb->data + size, 0, eff-size);
|
|
+
|
|
+ if (vcc->dev->ops->pre_send) {
|
|
+ error = vcc->dev->ops->pre_send(vcc, skb);
|
|
+ if (error)
|
|
+ goto free_skb;
|
|
+ }
|
|
+
|
|
error = vcc->dev->ops->send(vcc, skb);
|
|
error = error ? error : size;
|
|
out:
|
|
release_sock(sk);
|
|
return error;
|
|
+free_skb:
|
|
+ atm_return_tx(vcc, skb);
|
|
+ kfree_skb(skb);
|
|
+ goto out;
|
|
}
|
|
|
|
__poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
|
|
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
|
|
index c06010c0d88293..5eed23b8d6c332 100644
|
|
--- a/net/bluetooth/hci_event.c
|
|
+++ b/net/bluetooth/hci_event.c
|
|
@@ -2692,7 +2692,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
|
|
if (!conn)
|
|
goto unlock;
|
|
|
|
- if (status) {
|
|
+ if (status && status != HCI_ERROR_UNKNOWN_CONN_ID) {
|
|
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
|
|
conn->dst_type, status);
|
|
|
|
@@ -2707,6 +2707,12 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
|
|
goto done;
|
|
}
|
|
|
|
+ /* During suspend, mark connection as closed immediately
|
|
+ * since we might not receive HCI_EV_DISCONN_COMPLETE
|
|
+ */
|
|
+ if (hdev->suspended)
|
|
+ conn->state = BT_CLOSED;
|
|
+
|
|
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
|
|
|
|
if (conn->type == ACL_LINK) {
|
|
@@ -4386,7 +4392,17 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
|
|
if (!conn)
|
|
continue;
|
|
|
|
- conn->sent -= count;
|
|
+ /* Check if there is really enough packets outstanding before
|
|
+ * attempting to decrease the sent counter otherwise it could
|
|
+ * underflow..
|
|
+ */
|
|
+ if (conn->sent >= count) {
|
|
+ conn->sent -= count;
|
|
+ } else {
|
|
+ bt_dev_warn(hdev, "hcon %p sent %u < count %u",
|
|
+ conn, conn->sent, count);
|
|
+ conn->sent = 0;
|
|
+ }
|
|
|
|
switch (conn->type) {
|
|
case ACL_LINK:
|
|
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
|
|
index 01aca077071174..020f1809fc9946 100644
|
|
--- a/net/bluetooth/hci_sync.c
|
|
+++ b/net/bluetooth/hci_sync.c
|
|
@@ -3491,13 +3491,13 @@ int hci_update_scan_sync(struct hci_dev *hdev)
|
|
return hci_write_scan_enable_sync(hdev, scan);
|
|
}
|
|
|
|
-int hci_update_name_sync(struct hci_dev *hdev)
|
|
+int hci_update_name_sync(struct hci_dev *hdev, const u8 *name)
|
|
{
|
|
struct hci_cp_write_local_name cp;
|
|
|
|
memset(&cp, 0, sizeof(cp));
|
|
|
|
- memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
|
|
+ memcpy(cp.name, name, sizeof(cp.name));
|
|
|
|
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME,
|
|
sizeof(cp), &cp,
|
|
@@ -3550,7 +3550,7 @@ int hci_powered_update_sync(struct hci_dev *hdev)
|
|
hci_write_fast_connectable_sync(hdev, false);
|
|
hci_update_scan_sync(hdev);
|
|
hci_update_class_sync(hdev);
|
|
- hci_update_name_sync(hdev);
|
|
+ hci_update_name_sync(hdev, hdev->dev_name);
|
|
hci_update_eir_sync(hdev);
|
|
}
|
|
|
|
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
|
|
index 82fa8c28438f25..9b01eaaa0eb2d6 100644
|
|
--- a/net/bluetooth/mgmt.c
|
|
+++ b/net/bluetooth/mgmt.c
|
|
@@ -3819,8 +3819,11 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
|
|
|
|
static int set_name_sync(struct hci_dev *hdev, void *data)
|
|
{
|
|
+ struct mgmt_pending_cmd *cmd = data;
|
|
+ struct mgmt_cp_set_local_name *cp = cmd->param;
|
|
+
|
|
if (lmp_bredr_capable(hdev)) {
|
|
- hci_update_name_sync(hdev);
|
|
+ hci_update_name_sync(hdev, cp->name);
|
|
hci_update_eir_sync(hdev);
|
|
}
|
|
|
|
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
|
|
index 8672ebbace980b..20f5c8307443d3 100644
|
|
--- a/net/ipv4/route.c
|
|
+++ b/net/ipv4/route.c
|
|
@@ -2547,12 +2547,16 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
|
|
!netif_is_l3_master(dev_out))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
- if (ipv4_is_lbcast(fl4->daddr))
|
|
+ if (ipv4_is_lbcast(fl4->daddr)) {
|
|
type = RTN_BROADCAST;
|
|
- else if (ipv4_is_multicast(fl4->daddr))
|
|
+
|
|
+ /* reset fi to prevent gateway resolution */
|
|
+ fi = NULL;
|
|
+ } else if (ipv4_is_multicast(fl4->daddr)) {
|
|
type = RTN_MULTICAST;
|
|
- else if (ipv4_is_zeronet(fl4->daddr))
|
|
+ } else if (ipv4_is_zeronet(fl4->daddr)) {
|
|
return ERR_PTR(-EINVAL);
|
|
+ }
|
|
|
|
if (dev_out->flags & IFF_LOOPBACK)
|
|
flags |= RTCF_LOCAL;
|
|
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
|
|
index 66e9ceaaa43a14..614695444b6acb 100644
|
|
--- a/net/rose/af_rose.c
|
|
+++ b/net/rose/af_rose.c
|
|
@@ -170,7 +170,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
|
|
|
|
if (rose->neighbour == neigh) {
|
|
rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
rose->neighbour = NULL;
|
|
}
|
|
}
|
|
@@ -212,7 +212,7 @@ static void rose_kill_by_device(struct net_device *dev)
|
|
if (rose->device == dev) {
|
|
rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
|
|
if (rose->neighbour)
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
netdev_put(rose->device, &rose->dev_tracker);
|
|
rose->device = NULL;
|
|
}
|
|
@@ -655,7 +655,7 @@ static int rose_release(struct socket *sock)
|
|
break;
|
|
|
|
case ROSE_STATE_2:
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
release_sock(sk);
|
|
rose_disconnect(sk, 0, -1, -1);
|
|
lock_sock(sk);
|
|
@@ -823,6 +823,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
|
|
rose->lci = rose_new_lci(rose->neighbour);
|
|
if (!rose->lci) {
|
|
err = -ENETUNREACH;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
goto out_release;
|
|
}
|
|
|
|
@@ -834,12 +835,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
|
|
dev = rose_dev_first();
|
|
if (!dev) {
|
|
err = -ENETUNREACH;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
goto out_release;
|
|
}
|
|
|
|
user = ax25_findbyuid(current_euid());
|
|
if (!user) {
|
|
err = -EINVAL;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
dev_put(dev);
|
|
goto out_release;
|
|
}
|
|
@@ -874,8 +877,6 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
|
|
|
|
rose->state = ROSE_STATE_1;
|
|
|
|
- rose->neighbour->use++;
|
|
-
|
|
rose_write_internal(sk, ROSE_CALL_REQUEST);
|
|
rose_start_heartbeat(sk);
|
|
rose_start_t1timer(sk);
|
|
@@ -1077,7 +1078,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
|
|
GFP_ATOMIC);
|
|
make_rose->facilities = facilities;
|
|
|
|
- make_rose->neighbour->use++;
|
|
+ rose_neigh_hold(make_rose->neighbour);
|
|
|
|
if (rose_sk(sk)->defer) {
|
|
make_rose->state = ROSE_STATE_5;
|
|
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
|
|
index 4d67f36dce1b49..7caae93937ee9b 100644
|
|
--- a/net/rose/rose_in.c
|
|
+++ b/net/rose/rose_in.c
|
|
@@ -56,7 +56,7 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
|
|
case ROSE_CLEAR_REQUEST:
|
|
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
|
|
rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
break;
|
|
|
|
default:
|
|
@@ -79,12 +79,12 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
|
|
case ROSE_CLEAR_REQUEST:
|
|
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
|
|
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
break;
|
|
|
|
case ROSE_CLEAR_CONFIRMATION:
|
|
rose_disconnect(sk, 0, -1, -1);
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
break;
|
|
|
|
default:
|
|
@@ -120,7 +120,7 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
|
|
case ROSE_CLEAR_REQUEST:
|
|
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
|
|
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
break;
|
|
|
|
case ROSE_RR:
|
|
@@ -233,7 +233,7 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
|
|
case ROSE_CLEAR_REQUEST:
|
|
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
|
|
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
break;
|
|
|
|
default:
|
|
@@ -253,7 +253,7 @@ static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int framety
|
|
if (frametype == ROSE_CLEAR_REQUEST) {
|
|
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
|
|
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
|
|
- rose_sk(sk)->neighbour->use--;
|
|
+ rose_neigh_put(rose_sk(sk)->neighbour);
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
|
|
index a7054546f52dfa..28746ae5a25828 100644
|
|
--- a/net/rose/rose_route.c
|
|
+++ b/net/rose/rose_route.c
|
|
@@ -93,11 +93,11 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
|
|
rose_neigh->ax25 = NULL;
|
|
rose_neigh->dev = dev;
|
|
rose_neigh->count = 0;
|
|
- rose_neigh->use = 0;
|
|
rose_neigh->dce_mode = 0;
|
|
rose_neigh->loopback = 0;
|
|
rose_neigh->number = rose_neigh_no++;
|
|
rose_neigh->restarted = 0;
|
|
+ refcount_set(&rose_neigh->use, 1);
|
|
|
|
skb_queue_head_init(&rose_neigh->queue);
|
|
|
|
@@ -178,6 +178,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
|
|
}
|
|
}
|
|
rose_neigh->count++;
|
|
+ rose_neigh_hold(rose_neigh);
|
|
|
|
goto out;
|
|
}
|
|
@@ -187,6 +188,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
|
|
rose_node->neighbour[rose_node->count] = rose_neigh;
|
|
rose_node->count++;
|
|
rose_neigh->count++;
|
|
+ rose_neigh_hold(rose_neigh);
|
|
}
|
|
|
|
out:
|
|
@@ -234,20 +236,12 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
|
|
|
|
if ((s = rose_neigh_list) == rose_neigh) {
|
|
rose_neigh_list = rose_neigh->next;
|
|
- if (rose_neigh->ax25)
|
|
- ax25_cb_put(rose_neigh->ax25);
|
|
- kfree(rose_neigh->digipeat);
|
|
- kfree(rose_neigh);
|
|
return;
|
|
}
|
|
|
|
while (s != NULL && s->next != NULL) {
|
|
if (s->next == rose_neigh) {
|
|
s->next = rose_neigh->next;
|
|
- if (rose_neigh->ax25)
|
|
- ax25_cb_put(rose_neigh->ax25);
|
|
- kfree(rose_neigh->digipeat);
|
|
- kfree(rose_neigh);
|
|
return;
|
|
}
|
|
|
|
@@ -263,10 +257,10 @@ static void rose_remove_route(struct rose_route *rose_route)
|
|
struct rose_route *s;
|
|
|
|
if (rose_route->neigh1 != NULL)
|
|
- rose_route->neigh1->use--;
|
|
+ rose_neigh_put(rose_route->neigh1);
|
|
|
|
if (rose_route->neigh2 != NULL)
|
|
- rose_route->neigh2->use--;
|
|
+ rose_neigh_put(rose_route->neigh2);
|
|
|
|
if ((s = rose_route_list) == rose_route) {
|
|
rose_route_list = rose_route->next;
|
|
@@ -330,9 +324,12 @@ static int rose_del_node(struct rose_route_struct *rose_route,
|
|
for (i = 0; i < rose_node->count; i++) {
|
|
if (rose_node->neighbour[i] == rose_neigh) {
|
|
rose_neigh->count--;
|
|
+ rose_neigh_put(rose_neigh);
|
|
|
|
- if (rose_neigh->count == 0 && rose_neigh->use == 0)
|
|
+ if (rose_neigh->count == 0) {
|
|
rose_remove_neigh(rose_neigh);
|
|
+ rose_neigh_put(rose_neigh);
|
|
+ }
|
|
|
|
rose_node->count--;
|
|
|
|
@@ -381,11 +378,11 @@ void rose_add_loopback_neigh(void)
|
|
sn->ax25 = NULL;
|
|
sn->dev = NULL;
|
|
sn->count = 0;
|
|
- sn->use = 0;
|
|
sn->dce_mode = 1;
|
|
sn->loopback = 1;
|
|
sn->number = rose_neigh_no++;
|
|
sn->restarted = 1;
|
|
+ refcount_set(&sn->use, 1);
|
|
|
|
skb_queue_head_init(&sn->queue);
|
|
|
|
@@ -436,6 +433,7 @@ int rose_add_loopback_node(const rose_address *address)
|
|
rose_node_list = rose_node;
|
|
|
|
rose_loopback_neigh->count++;
|
|
+ rose_neigh_hold(rose_loopback_neigh);
|
|
|
|
out:
|
|
spin_unlock_bh(&rose_node_list_lock);
|
|
@@ -467,6 +465,7 @@ void rose_del_loopback_node(const rose_address *address)
|
|
rose_remove_node(rose_node);
|
|
|
|
rose_loopback_neigh->count--;
|
|
+ rose_neigh_put(rose_loopback_neigh);
|
|
|
|
out:
|
|
spin_unlock_bh(&rose_node_list_lock);
|
|
@@ -506,6 +505,7 @@ void rose_rt_device_down(struct net_device *dev)
|
|
memmove(&t->neighbour[i], &t->neighbour[i + 1],
|
|
sizeof(t->neighbour[0]) *
|
|
(t->count - i));
|
|
+ rose_neigh_put(s);
|
|
}
|
|
|
|
if (t->count <= 0)
|
|
@@ -513,6 +513,7 @@ void rose_rt_device_down(struct net_device *dev)
|
|
}
|
|
|
|
rose_remove_neigh(s);
|
|
+ rose_neigh_put(s);
|
|
}
|
|
spin_unlock_bh(&rose_neigh_list_lock);
|
|
spin_unlock_bh(&rose_node_list_lock);
|
|
@@ -548,6 +549,7 @@ static int rose_clear_routes(void)
|
|
{
|
|
struct rose_neigh *s, *rose_neigh;
|
|
struct rose_node *t, *rose_node;
|
|
+ int i;
|
|
|
|
spin_lock_bh(&rose_node_list_lock);
|
|
spin_lock_bh(&rose_neigh_list_lock);
|
|
@@ -558,17 +560,21 @@ static int rose_clear_routes(void)
|
|
while (rose_node != NULL) {
|
|
t = rose_node;
|
|
rose_node = rose_node->next;
|
|
- if (!t->loopback)
|
|
+
|
|
+ if (!t->loopback) {
|
|
+ for (i = 0; i < t->count; i++)
|
|
+ rose_neigh_put(t->neighbour[i]);
|
|
rose_remove_node(t);
|
|
+ }
|
|
}
|
|
|
|
while (rose_neigh != NULL) {
|
|
s = rose_neigh;
|
|
rose_neigh = rose_neigh->next;
|
|
|
|
- if (s->use == 0 && !s->loopback) {
|
|
- s->count = 0;
|
|
+ if (!s->loopback) {
|
|
rose_remove_neigh(s);
|
|
+ rose_neigh_put(s);
|
|
}
|
|
}
|
|
|
|
@@ -684,6 +690,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
|
|
for (i = 0; i < node->count; i++) {
|
|
if (node->neighbour[i]->restarted) {
|
|
res = node->neighbour[i];
|
|
+ rose_neigh_hold(node->neighbour[i]);
|
|
goto out;
|
|
}
|
|
}
|
|
@@ -695,6 +702,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
|
|
for (i = 0; i < node->count; i++) {
|
|
if (!rose_ftimer_running(node->neighbour[i])) {
|
|
res = node->neighbour[i];
|
|
+ rose_neigh_hold(node->neighbour[i]);
|
|
goto out;
|
|
}
|
|
failed = 1;
|
|
@@ -784,13 +792,13 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
|
|
}
|
|
|
|
if (rose_route->neigh1 == rose_neigh) {
|
|
- rose_route->neigh1->use--;
|
|
+ rose_neigh_put(rose_route->neigh1);
|
|
rose_route->neigh1 = NULL;
|
|
rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0);
|
|
}
|
|
|
|
if (rose_route->neigh2 == rose_neigh) {
|
|
- rose_route->neigh2->use--;
|
|
+ rose_neigh_put(rose_route->neigh2);
|
|
rose_route->neigh2 = NULL;
|
|
rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0);
|
|
}
|
|
@@ -919,7 +927,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
|
|
rose_clear_queues(sk);
|
|
rose->cause = ROSE_NETWORK_CONGESTION;
|
|
rose->diagnostic = 0;
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
rose->neighbour = NULL;
|
|
rose->lci = 0;
|
|
rose->state = ROSE_STATE_0;
|
|
@@ -1044,12 +1052,12 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
|
|
|
|
if ((new_lci = rose_new_lci(new_neigh)) == 0) {
|
|
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
|
|
- goto out;
|
|
+ goto put_neigh;
|
|
}
|
|
|
|
if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
|
|
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
|
|
- goto out;
|
|
+ goto put_neigh;
|
|
}
|
|
|
|
rose_route->lci1 = lci;
|
|
@@ -1062,8 +1070,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
|
|
rose_route->lci2 = new_lci;
|
|
rose_route->neigh2 = new_neigh;
|
|
|
|
- rose_route->neigh1->use++;
|
|
- rose_route->neigh2->use++;
|
|
+ rose_neigh_hold(rose_route->neigh1);
|
|
+ rose_neigh_hold(rose_route->neigh2);
|
|
|
|
rose_route->next = rose_route_list;
|
|
rose_route_list = rose_route;
|
|
@@ -1075,6 +1083,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
|
|
rose_transmit_link(skb, rose_route->neigh2);
|
|
res = 1;
|
|
|
|
+put_neigh:
|
|
+ rose_neigh_put(new_neigh);
|
|
out:
|
|
spin_unlock_bh(&rose_route_list_lock);
|
|
spin_unlock_bh(&rose_neigh_list_lock);
|
|
@@ -1190,7 +1200,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
|
|
(rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
|
|
rose_neigh->dev ? rose_neigh->dev->name : "???",
|
|
rose_neigh->count,
|
|
- rose_neigh->use,
|
|
+ refcount_read(&rose_neigh->use) - rose_neigh->count - 1,
|
|
(rose_neigh->dce_mode) ? "DCE" : "DTE",
|
|
(rose_neigh->restarted) ? "yes" : "no",
|
|
ax25_display_timer(&rose_neigh->t0timer) / HZ,
|
|
@@ -1295,18 +1305,22 @@ void __exit rose_rt_free(void)
|
|
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
|
|
struct rose_node *t, *rose_node = rose_node_list;
|
|
struct rose_route *u, *rose_route = rose_route_list;
|
|
+ int i;
|
|
|
|
while (rose_neigh != NULL) {
|
|
s = rose_neigh;
|
|
rose_neigh = rose_neigh->next;
|
|
|
|
rose_remove_neigh(s);
|
|
+ rose_neigh_put(s);
|
|
}
|
|
|
|
while (rose_node != NULL) {
|
|
t = rose_node;
|
|
rose_node = rose_node->next;
|
|
|
|
+ for (i = 0; i < t->count; i++)
|
|
+ rose_neigh_put(t->neighbour[i]);
|
|
rose_remove_node(t);
|
|
}
|
|
|
|
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
|
|
index 1525773e94aa17..c52d7d20c5199b 100644
|
|
--- a/net/rose/rose_timer.c
|
|
+++ b/net/rose/rose_timer.c
|
|
@@ -180,7 +180,7 @@ static void rose_timer_expiry(struct timer_list *t)
|
|
break;
|
|
|
|
case ROSE_STATE_2: /* T3 */
|
|
- rose->neighbour->use--;
|
|
+ rose_neigh_put(rose->neighbour);
|
|
rose_disconnect(sk, ETIMEDOUT, -1, -1);
|
|
break;
|
|
|
|
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
|
|
index 717828e531621a..0673857cb3d8b1 100644
|
|
--- a/net/sctp/ipv6.c
|
|
+++ b/net/sctp/ipv6.c
|
|
@@ -547,7 +547,9 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
|
|
{
|
|
addr->v6.sin6_family = AF_INET6;
|
|
addr->v6.sin6_port = 0;
|
|
+ addr->v6.sin6_flowinfo = 0;
|
|
addr->v6.sin6_addr = sk->sk_v6_rcv_saddr;
|
|
+ addr->v6.sin6_scope_id = 0;
|
|
}
|
|
|
|
/* Initialize sk->sk_rcv_saddr from sctp_addr. */
|
|
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
|
|
index ebddfa74ce0a07..150ed10c8377ab 100644
|
|
--- a/sound/soc/codecs/lpass-tx-macro.c
|
|
+++ b/sound/soc/codecs/lpass-tx-macro.c
|
|
@@ -1940,7 +1940,7 @@ static int tx_macro_register_mclk_output(struct tx_macro *tx)
|
|
}
|
|
|
|
static const struct snd_soc_component_driver tx_macro_component_drv = {
|
|
- .name = "RX-MACRO",
|
|
+ .name = "TX-MACRO",
|
|
.probe = tx_macro_component_probe,
|
|
.controls = tx_macro_snd_controls,
|
|
.num_controls = ARRAY_SIZE(tx_macro_snd_controls),
|