summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/riscv/cpus.yaml26
-rw-r--r--MAINTAINERS10
-rw-r--r--Makefile4
-rw-r--r--arch/arc/Makefile4
-rw-r--r--arch/arc/plat-hsdk/platform.c161
-rw-r--r--arch/arm/boot/dts/gemini-dlink-dir-685.dts2
-rw-r--r--arch/arm/boot/dts/gemini-dlink-dns-313.dts2
-rw-r--r--arch/arm/boot/dts/imx6ul.dtsi8
-rw-r--r--arch/arm/boot/dts/meson8.dtsi5
-rw-r--r--arch/arm/boot/dts/meson8b.dtsi11
-rw-r--r--arch/arm/mach-omap2/prm3xxx.c2
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi18
-rw-r--r--arch/arm64/configs/defconfig1
-rw-r--r--arch/csky/kernel/signal.c5
-rw-r--r--arch/mips/include/asm/mips-gic.h30
-rw-r--r--arch/parisc/kernel/module.c4
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S2
-rw-r--r--arch/powerpc/mm/book3s64/mmu_context.c55
-rw-r--r--arch/riscv/boot/dts/sifive/fu540-c000.dtsi6
-rw-r--r--arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts13
-rw-r--r--arch/riscv/configs/defconfig5
-rw-r--r--arch/riscv/mm/fault.c3
-rw-r--r--arch/x86/events/core.c16
-rw-r--r--arch/x86/events/intel/ds.c9
-rw-r--r--arch/x86/events/perf_event.h21
-rw-r--r--arch/x86/include/uapi/asm/perf_regs.h3
-rw-r--r--arch/x86/kernel/apic/apic.c3
-rw-r--r--arch/x86/kernel/cpu/bugs.c11
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c15
-rw-r--r--arch/x86/kernel/cpu/resctrl/rdtgroup.c35
-rw-r--r--arch/x86/kernel/head64.c20
-rw-r--r--arch/x86/kernel/perf_regs.c7
-rw-r--r--arch/x86/kernel/unwind_orc.c26
-rw-r--r--arch/x86/mm/init_64.c24
-rw-r--r--arch/x86/platform/efi/quirks.c2
-rw-r--r--block/bfq-iosched.c2
-rw-r--r--drivers/auxdisplay/cfag12864bfb.c5
-rw-r--r--drivers/auxdisplay/ht16k33.c4
-rw-r--r--drivers/clk/clk.c2
-rw-r--r--drivers/clk/meson/g12a.c4
-rw-r--r--drivers/clk/meson/g12a.h2
-rw-r--r--drivers/clk/meson/meson8b.c10
-rw-r--r--drivers/clk/socfpga/clk-s10.c4
-rw-r--r--drivers/clk/tegra/clk-tegra210.c2
-rw-r--r--drivers/clk/ti/clkctrl.c7
-rw-r--r--drivers/firmware/efi/efi-bgrt.c5
-rw-r--r--drivers/firmware/efi/efi.c12
-rw-r--r--drivers/firmware/efi/efibc.c12
-rw-r--r--drivers/hid/hid-ids.h3
-rw-r--r--drivers/hid/hid-logitech-dj.c4
-rw-r--r--drivers/hid/hid-multitouch.c4
-rw-r--r--drivers/hid/hid-quirks.c1
-rw-r--r--drivers/hid/hid-uclogic-core.c2
-rw-r--r--drivers/hid/hid-uclogic-params.c2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-fw-loader.c2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid-client.c4
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c15
-rw-r--r--drivers/irqchip/irq-csky-mpintc.c15
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c35
-rw-r--r--drivers/irqchip/irq-mips-gic.c4
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c4
-rw-r--r--drivers/md/dm-init.c10
-rw-r--r--drivers/md/dm-log-writes.c23
-rw-r--r--drivers/md/dm-table.c2
-rw-r--r--drivers/md/dm-verity-target.c4
-rw-r--r--drivers/mfd/stmfx.c12
-rw-r--r--drivers/mtd/nand/raw/nand_base.c3
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c119
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c6
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_filters.c10
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_nic.c1
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_nic.h1
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c19
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c28
-rw-r--r--drivers/net/ethernet/sis/sis900.c16
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c22
-rw-r--r--drivers/net/ppp/ppp_mppe.c1
-rw-r--r--drivers/net/team/team.c2
-rw-r--r--drivers/net/usb/qmi_wwan.c2
-rw-r--r--drivers/net/vrf.c2
-rw-r--r--drivers/pci/pci-driver.c8
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.c34
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c8
-rw-r--r--drivers/pinctrl/pinctrl-ocelot.c18
-rw-r--r--drivers/scsi/vmw_pvscsi.c6
-rw-r--r--fs/afs/callback.c4
-rw-r--r--fs/afs/inode.c31
-rw-r--r--fs/afs/internal.h8
-rw-r--r--fs/afs/volume.c1
-rw-r--r--fs/aio.c28
-rw-r--r--fs/binfmt_flat.c23
-rw-r--r--fs/ceph/mds_client.c3
-rw-r--r--fs/eventpoll.c4
-rw-r--r--fs/inode.c2
-rw-r--r--fs/io_uring.c12
-rw-r--r--fs/nfs/flexfilelayout/flexfilelayoutdev.c2
-rw-r--r--fs/proc/array.c2
-rw-r--r--fs/proc/base.c3
-rw-r--r--fs/select.c18
-rw-r--r--include/dt-bindings/clock/g12a-clkc.h2
-rw-r--r--include/dt-bindings/clock/sifive-fu540-prci.h2
-rw-r--r--include/linux/intel-ish-client-if.h1
-rw-r--r--include/linux/kernel.h3
-rw-r--r--include/linux/mtd/spi-nor.h3
-rw-r--r--include/linux/perf_event.h1
-rw-r--r--include/linux/perf_regs.h8
-rw-r--r--include/linux/pfn_t.h2
-rw-r--r--include/linux/signal.h2
-rw-r--r--include/linux/suspend.h26
-rw-r--r--include/linux/xarray.h1
-rw-r--r--include/net/ip6_route.h4
-rw-r--r--include/net/route.h1
-rw-r--r--include/net/tls.h15
-rw-r--r--include/sound/compress_driver.h5
-rw-r--r--include/sound/hda_codec.h5
-rw-r--r--include/sound/hdaudio.h5
-rw-r--r--include/uapi/linux/usb/audio.h37
-rw-r--r--init/initramfs.c4
-rw-r--r--kernel/cpu.c6
-rw-r--r--kernel/events/core.c23
-rw-r--r--kernel/fork.c64
-rw-r--r--kernel/power/suspend.c3
-rw-r--r--kernel/signal.c5
-rw-r--r--lib/idr.c14
-rw-r--r--lib/test_xarray.c38
-rw-r--r--lib/xarray.c12
-rw-r--r--mm/hugetlb.c29
-rw-r--r--mm/memory-failure.c7
-rw-r--r--mm/mempolicy.c2
-rw-r--r--mm/oom_kill.c12
-rw-r--r--mm/page_idle.c4
-rw-r--r--mm/page_io.c7
-rw-r--r--mm/vmalloc.c4
-rw-r--r--net/bluetooth/6lowpan.c4
-rw-r--r--net/ipv4/ip_output.c12
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c33
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/route.c5
-rw-r--r--net/netfilter/nf_flow_table_ip.c2
-rw-r--r--net/packet/af_packet.c23
-rw-r--r--net/packet/internal.h1
-rw-r--r--net/sched/sch_cbs.c9
-rw-r--r--net/sctp/endpointola.c8
-rw-r--r--net/smc/af_smc.c5
-rw-r--r--net/smc/smc_core.c3
-rw-r--r--net/sunrpc/xprtsock.c16
-rw-r--r--net/tipc/core.c12
-rw-r--r--net/tipc/netlink_compat.c18
-rw-r--r--net/tls/tls_main.c3
-rw-r--r--samples/pidfd/pidfd-metadata.c8
-rw-r--r--sound/ac97/bus.c13
-rw-r--r--sound/core/compress_offload.c60
-rw-r--r--sound/core/control.c6
-rw-r--r--sound/core/oss/rate.c4
-rw-r--r--sound/core/pcm_native.c12
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c2
-rw-r--r--sound/core/seq/oss/seq_oss_rw.c2
-rw-r--r--sound/core/seq/seq_clientmgr.c11
-rw-r--r--sound/firewire/amdtp-am824.c4
-rw-r--r--sound/firewire/amdtp-stream-trace.h163
-rw-r--r--sound/firewire/amdtp-stream.c536
-rw-r--r--sound/firewire/amdtp-stream.h38
-rw-r--r--sound/firewire/bebob/bebob.h5
-rw-r--r--sound/firewire/bebob/bebob_midi.c55
-rw-r--r--sound/firewire/bebob/bebob_pcm.c70
-rw-r--r--sound/firewire/bebob/bebob_stream.c362
-rw-r--r--sound/firewire/cmp.c74
-rw-r--r--sound/firewire/cmp.h7
-rw-r--r--sound/firewire/dice/Makefile2
-rw-r--r--sound/firewire/dice/dice-midi.c11
-rw-r--r--sound/firewire/dice/dice-pcm.c61
-rw-r--r--sound/firewire/dice/dice-presonus.c62
-rw-r--r--sound/firewire/dice/dice-stream.c344
-rw-r--r--sound/firewire/dice/dice.c9
-rw-r--r--sound/firewire/dice/dice.h4
-rw-r--r--sound/firewire/digi00x/amdtp-dot.c2
-rw-r--r--sound/firewire/digi00x/digi00x-midi.c11
-rw-r--r--sound/firewire/digi00x/digi00x-pcm.c64
-rw-r--r--sound/firewire/digi00x/digi00x-stream.c183
-rw-r--r--sound/firewire/digi00x/digi00x.h3
-rw-r--r--sound/firewire/fireface/ff-pcm.c56
-rw-r--r--sound/firewire/fireface/ff-protocol-former.c112
-rw-r--r--sound/firewire/fireface/ff-protocol-latter.c114
-rw-r--r--sound/firewire/fireface/ff-stream.c79
-rw-r--r--sound/firewire/fireface/ff.h2
-rw-r--r--sound/firewire/fireworks/fireworks.h6
-rw-r--r--sound/firewire/fireworks/fireworks_midi.c56
-rw-r--r--sound/firewire/fireworks/fireworks_pcm.c66
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c178
-rw-r--r--sound/firewire/motu/amdtp-motu-trace.h70
-rw-r--r--sound/firewire/motu/amdtp-motu.c10
-rw-r--r--sound/firewire/motu/motu-midi.c60
-rw-r--r--sound/firewire/motu/motu-pcm.c61
-rw-r--r--sound/firewire/motu/motu-stream.c197
-rw-r--r--sound/firewire/motu/motu.h6
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c24
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c34
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c351
-rw-r--r--sound/firewire/oxfw/oxfw.c17
-rw-r--r--sound/firewire/oxfw/oxfw.h22
-rw-r--r--sound/firewire/tascam/amdtp-tascam.c2
-rw-r--r--sound/firewire/tascam/tascam-pcm.c58
-rw-r--r--sound/firewire/tascam/tascam-stream.c203
-rw-r--r--sound/firewire/tascam/tascam.h1
-rw-r--r--sound/hda/hdac_controller.c7
-rw-r--r--sound/hda/hdac_device.c29
-rw-r--r--sound/hda/hdac_i915.c10
-rw-r--r--sound/hda/hdac_sysfs.c2
-rw-r--r--sound/pci/asihpi/asihpi.c7
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c15
-rw-r--r--sound/pci/cs4281.c5
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c7
-rw-r--r--sound/pci/emu10k1/emu10k1x.c3
-rw-r--r--sound/pci/hda/hda_codec.c12
-rw-r--r--sound/pci/hda/hda_controller.c12
-rw-r--r--sound/pci/hda/hda_controller.h2
-rw-r--r--sound/pci/hda/hda_intel.c16
-rw-r--r--sound/pci/hda/hda_jack.c2
-rw-r--r--sound/pci/hda/patch_ca0132.c4
-rw-r--r--sound/pci/hda/patch_conexant.c1
-rw-r--r--sound/pci/hda/patch_hdmi.c34
-rw-r--r--sound/pci/hda/patch_realtek.c20
-rw-r--r--sound/pci/lx6464es/lx6464es.c3
-rw-r--r--sound/pci/lx6464es/lx_core.c5
-rw-r--r--sound/pci/rme9652/hdspm.c61
-rw-r--r--sound/pci/rme9652/rme9652.c3
-rw-r--r--sound/ppc/snd_ps3.c3
-rw-r--r--sound/soc/codecs/ad193x.c6
-rw-r--r--sound/soc/codecs/hdac_hdmi.c33
-rw-r--r--sound/soc/codecs/nau8825.c4
-rw-r--r--sound/soc/codecs/nau8825.h2
-rw-r--r--sound/soc/generic/audio-graph-card.c6
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c2
-rw-r--r--sound/soc/intel/skylake/skl.c21
-rw-r--r--sound/soc/intel/skylake/skl.h1
-rw-r--r--sound/soc/meson/axg-tdm.h2
-rw-r--r--sound/soc/meson/axg-tdmin.c1
-rw-r--r--sound/soc/meson/axg-tdmout.c1
-rw-r--r--sound/soc/qcom/common.c1
-rw-r--r--sound/soc/soc-core.c20
-rw-r--r--sound/soc/soc-dapm.c18
-rw-r--r--sound/soc/sof/intel/hda.c8
-rw-r--r--sound/soc/ti/davinci-mcasp.c2
-rw-r--r--sound/soc/ti/omap-mcbsp.c2
-rw-r--r--sound/usb/format.c46
-rw-r--r--sound/usb/helper.c17
-rw-r--r--sound/usb/helper.h1
-rw-r--r--sound/usb/line6/driver.c11
-rw-r--r--sound/usb/line6/driver.h9
-rw-r--r--sound/usb/line6/pcm.c5
-rw-r--r--sound/usb/line6/pod.c108
-rw-r--r--sound/usb/line6/podhd.c82
-rw-r--r--sound/usb/line6/toneport.c14
-rw-r--r--sound/usb/line6/variax.c140
-rw-r--r--sound/usb/mixer.c16
-rw-r--r--sound/usb/mixer_quirks.c4
-rw-r--r--sound/usb/quirks-table.h2
-rw-r--r--sound/usb/quirks.c18
-rw-r--r--sound/xen/xen_snd_front_alsa.c4
-rw-r--r--tools/arch/x86/include/uapi/asm/perf_regs.h3
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h1
-rw-r--r--tools/perf/arch/x86/util/perf_regs.c4
-rw-r--r--tools/testing/radix-tree/idr-test.c46
-rw-r--r--tools/testing/selftests/powerpc/mm/.gitignore3
-rw-r--r--tools/testing/selftests/powerpc/mm/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c87
270 files changed, 3741 insertions, 3004 deletions
diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index 27f02ec4bb45..f97a4ecd7b91 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -152,17 +152,19 @@ examples:
- |
// Example 2: Spike ISA Simulator with 1 Hart
cpus {
- cpu@0 {
- device_type = "cpu";
- reg = <0>;
- compatible = "riscv";
- riscv,isa = "rv64imafdc";
- mmu-type = "riscv,sv48";
- interrupt-controller {
- #interrupt-cells = <1>;
- interrupt-controller;
- compatible = "riscv,cpu-intc";
- };
- };
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ device_type = "cpu";
+ reg = <0>;
+ compatible = "riscv";
+ riscv,isa = "rv64imafdc";
+ mmu-type = "riscv,sv48";
+ interrupt-controller {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ };
+ };
};
...
diff --git a/MAINTAINERS b/MAINTAINERS
index 92829ca37459..f227f7e04fbd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3122,6 +3122,7 @@ F: arch/arm/mach-bcm/
BROADCOM BCM2835 ARM ARCHITECTURE
M: Eric Anholt <eric@anholt.net>
M: Stefan Wahren <wahrenst@gmx.net>
+L: bcm-kernel-feedback-list@broadcom.com
L: linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
T: git git://github.com/anholt/linux
@@ -3151,6 +3152,7 @@ F: arch/arm/boot/dts/bcm953012*
BROADCOM BCM53573 ARM ARCHITECTURE
M: Rafał Miłecki <rafal@milecki.pl>
+L: bcm-kernel-feedback-list@broadcom.com
L: linux-arm-kernel@lists.infradead.org
S: Maintained
F: arch/arm/boot/dts/bcm53573*
@@ -3945,6 +3947,14 @@ M: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
S: Maintained
F: .clang-format
+CLANG/LLVM BUILD SUPPORT
+L: clang-built-linux@googlegroups.com
+W: https://clangbuiltlinux.github.io/
+B: https://github.com/ClangBuiltLinux/linux/issues
+C: irc://chat.freenode.net/clangbuiltlinux
+S: Supported
+K: \b(?i:clang|llvm)\b
+
CLEANCACHE API
M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
L: linux-kernel@vger.kernel.org
diff --git a/Makefile b/Makefile
index 7a7c17eb0cbf..fabc127d127f 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@
VERSION = 5
PATCHLEVEL = 2
SUBLEVEL = 0
-EXTRAVERSION = -rc6
-NAME = Golden Lions
+EXTRAVERSION = -rc7
+NAME = Bobtail Squid
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index 480af1af9e63..03a0b19c92cd 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -5,6 +5,10 @@
KBUILD_DEFCONFIG := nsim_hs_defconfig
+ifeq ($(CROSS_COMPILE),)
+CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux-)
+endif
+
cflags-y += -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__
cflags-$(CONFIG_ISA_ARCOMPACT) += -mA7
cflags-$(CONFIG_ISA_ARCV2) += -mcpu=hs38
diff --git a/arch/arc/plat-hsdk/platform.c b/arch/arc/plat-hsdk/platform.c
index 6a91a742ab3d..7dd2dd335cf6 100644
--- a/arch/arc/plat-hsdk/platform.c
+++ b/arch/arc/plat-hsdk/platform.c
@@ -32,8 +32,6 @@ static void __init hsdk_init_per_cpu(unsigned int cpu)
#define ARC_PERIPHERAL_BASE 0xf0000000
#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000)
-#define CREG_PAE (CREG_BASE + 0x180)
-#define CREG_PAE_UPDATE (CREG_BASE + 0x194)
#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000)
#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108)
@@ -99,20 +97,167 @@ static void __init hsdk_enable_gpio_intc_wire(void)
iowrite32(GPIO_INT_CONNECTED_MASK, (void __iomem *) GPIO_INTEN);
}
-static void __init hsdk_init_early(void)
+enum hsdk_axi_masters {
+ M_HS_CORE = 0,
+ M_HS_RTT,
+ M_AXI_TUN,
+ M_HDMI_VIDEO,
+ M_HDMI_AUDIO,
+ M_USB_HOST,
+ M_ETHERNET,
+ M_SDIO,
+ M_GPU,
+ M_DMAC_0,
+ M_DMAC_1,
+ M_DVFS
+};
+
+#define UPDATE_VAL 1
+
+/*
+ * This is modified configuration of AXI bridge. Default settings
+ * are specified in "Table 111 CREG Address Decoder register reset values".
+ *
+ * AXI_M_m_SLV{0|1} - Slave Select register for master 'm'.
+ * Possible slaves are:
+ * - 0 => no slave selected
+ * - 1 => DDR controller port #1
+ * - 2 => SRAM controller
+ * - 3 => AXI tunnel
+ * - 4 => EBI controller
+ * - 5 => ROM controller
+ * - 6 => AXI2APB bridge
+ * - 7 => DDR controller port #2
+ * - 8 => DDR controller port #3
+ * - 9 => HS38x4 IOC
+ * - 10 => HS38x4 DMI
+ * AXI_M_m_OFFSET{0|1} - Addr Offset register for master 'm'
+ *
+ * Please read ARC HS Development IC Specification, section 17.2 for more
+ * information about apertures configuration.
+ *
+ * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
+ * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210
+ * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210
+ * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
+ * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
+ * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
+ * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000
+ */
+
+#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x20 * (m)))
+#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x04))
+#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x08))
+#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x0C))
+#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x14))
+
+#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010))
+
+#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180))
+#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194))
+
+static void __init hsdk_init_memory_bridge(void)
{
+ u32 reg;
+
+ /*
+ * M_HS_CORE has one unique register - BOOT.
+ * We need to clean boot mirror (BOOT[1:0]) bits in them to avoid first
+ * aperture to be masked by 'boot mirror'.
+ */
+ reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3);
+ writel(reg, CREG_AXI_M_HS_CORE_BOOT);
+ writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE));
+ writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE));
+ writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT));
+
+ writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN));
+ writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST));
+ writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST));
+ writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET));
+ writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET));
+ writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO));
+ writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO));
+ writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_GPU));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_GPU));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
+
+ writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
+ writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
+ writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
+ writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
+
/*
* PAE remapping for DMA clients does not work due to an RTL bug, so
* CREG_PAE register must be programmed to all zeroes, otherwise it
* will cause problems with DMA to/from peripherals even if PAE40 is
* not used.
*/
+ writel(0x00000000, CREG_PAE);
+ writel(UPDATE_VAL, CREG_PAE_UPDT);
+}
- /* Default is 1, which means "PAE offset = 4GByte" */
- writel_relaxed(0, (void __iomem *) CREG_PAE);
-
- /* Really apply settings made above */
- writel(1, (void __iomem *) CREG_PAE_UPDATE);
+static void __init hsdk_init_early(void)
+{
+ hsdk_init_memory_bridge();
/*
* Switch SDIO external ciu clock divider from default div-by-8 to
diff --git a/arch/arm/boot/dts/gemini-dlink-dir-685.dts b/arch/arm/boot/dts/gemini-dlink-dir-685.dts
index cfbfbc91a1e1..3613f05f8a80 100644
--- a/arch/arm/boot/dts/gemini-dlink-dir-685.dts
+++ b/arch/arm/boot/dts/gemini-dlink-dir-685.dts
@@ -20,7 +20,7 @@
};
chosen {
- bootargs = "console=ttyS0,19200n8 root=/dev/sda1 rw rootwait";
+ bootargs = "console=ttyS0,19200n8 root=/dev/sda1 rw rootwait consoleblank=300";
stdout-path = "uart0:19200n8";
};
diff --git a/arch/arm/boot/dts/gemini-dlink-dns-313.dts b/arch/arm/boot/dts/gemini-dlink-dns-313.dts
index b12504e10f0b..360642a02a48 100644
--- a/arch/arm/boot/dts/gemini-dlink-dns-313.dts
+++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts
@@ -11,7 +11,7 @@
/ {
model = "D-Link DNS-313 1-Bay Network Storage Enclosure";
- compatible = "dlink,dir-313", "cortina,gemini";
+ compatible = "dlink,dns-313", "cortina,gemini";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index bbf010c73336..a7f6d1d58e20 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -358,7 +358,7 @@
pwm1: pwm@2080000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02080000 0x4000>;
- interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM1>,
<&clks IMX6UL_CLK_PWM1>;
clock-names = "ipg", "per";
@@ -369,7 +369,7 @@
pwm2: pwm@2084000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02084000 0x4000>;
- interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM2>,
<&clks IMX6UL_CLK_PWM2>;
clock-names = "ipg", "per";
@@ -380,7 +380,7 @@
pwm3: pwm@2088000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02088000 0x4000>;
- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM3>,
<&clks IMX6UL_CLK_PWM3>;
clock-names = "ipg", "per";
@@ -391,7 +391,7 @@
pwm4: pwm@208c000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x0208c000 0x4000>;
- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM4>,
<&clks IMX6UL_CLK_PWM4>;
clock-names = "ipg", "per";
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 7ef442462ea4..40c11b6b217a 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -248,8 +248,8 @@
<GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
@@ -264,7 +264,6 @@
clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
clock-names = "bus", "core";
operating-points-v2 = <&gpu_opp_table>;
- switch-delay = <0xffff>;
};
};
}; /* end of / */
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 800cd65fc50a..ec67f49116d9 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -163,23 +163,23 @@
opp-255000000 {
opp-hz = /bits/ 64 <255000000>;
- opp-microvolt = <1150000>;
+ opp-microvolt = <1100000>;
};
opp-364300000 {
opp-hz = /bits/ 64 <364300000>;
- opp-microvolt = <1150000>;
+ opp-microvolt = <1100000>;
};
opp-425000000 {
opp-hz = /bits/ 64 <425000000>;
- opp-microvolt = <1150000>;
+ opp-microvolt = <1100000>;
};
opp-510000000 {
opp-hz = /bits/ 64 <510000000>;
- opp-microvolt = <1150000>;
+ opp-microvolt = <1100000>;
};
opp-637500000 {
opp-hz = /bits/ 64 <637500000>;
- opp-microvolt = <1150000>;
+ opp-microvolt = <1100000>;
turbo-mode;
};
};
@@ -229,7 +229,6 @@
clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
clock-names = "bus", "core";
operating-points-v2 = <&gpu_opp_table>;
- switch-delay = <0xffff>;
};
};
}; /* end of / */
diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c
index fd4a3bf27993..1b442b128569 100644
--- a/arch/arm/mach-omap2/prm3xxx.c
+++ b/arch/arm/mach-omap2/prm3xxx.c
@@ -430,7 +430,7 @@ static void omap3_prm_reconfigure_io_chain(void)
* registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
* No return value.
*/
-static void __init omap3xxx_prm_enable_io_wakeup(void)
+static void omap3xxx_prm_enable_io_wakeup(void)
{
if (prm_features & PRM_HAS_IO_WAKEUP)
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
index b04581249f0b..bf7f845447ed 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
@@ -28,7 +28,7 @@
enable-method = "psci";
clocks = <&clockgen 1 0>;
next-level-cache = <&l2>;
- cpu-idle-states = <&CPU_PH20>;
+ cpu-idle-states = <&CPU_PW20>;
};
cpu1: cpu@1 {
@@ -38,7 +38,7 @@
enable-method = "psci";
clocks = <&clockgen 1 0>;
next-level-cache = <&l2>;
- cpu-idle-states = <&CPU_PH20>;
+ cpu-idle-states = <&CPU_PW20>;
};
l2: l2-cache {
@@ -53,13 +53,13 @@
*/
entry-method = "arm,psci";
- CPU_PH20: cpu-ph20 {
- compatible = "arm,idle-state";
- idle-state-name = "PH20";
- arm,psci-suspend-param = <0x00010000>;
- entry-latency-us = <1000>;
- exit-latency-us = <1000>;
- min-residency-us = <3000>;
+ CPU_PW20: cpu-pw20 {
+ compatible = "arm,idle-state";
+ idle-state-name = "PW20";
+ arm,psci-suspend-param = <0x0>;
+ entry-latency-us = <2000>;
+ exit-latency-us = <2000>;
+ min-residency-us = <6000>;
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 4d583514258c..6bca5b082ea4 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -613,6 +613,7 @@ CONFIG_RTC_DRV_TEGRA=y
CONFIG_RTC_DRV_IMX_SC=m
CONFIG_RTC_DRV_XGENE=y
CONFIG_DMADEVICES=y
+CONFIG_FSL_EDMA=y
CONFIG_DMA_BCM2835=m
CONFIG_K3_DMA=y
CONFIG_MV_XOR=y
diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c
index 04a43cfd4e09..d47a3381aad8 100644
--- a/arch/csky/kernel/signal.c
+++ b/arch/csky/kernel/signal.c
@@ -39,6 +39,11 @@ static int save_fpu_state(struct sigcontext __user *sc)
#endif
struct rt_sigframe {
+ /*
+ * pad[3] is compatible with the same struct defined in
+ * gcc/libgcc/config/csky/linux-unwind.h
+ */
+ int pad[3];
struct siginfo info;
struct ucontext uc;
};
diff --git a/arch/mips/include/asm/mips-gic.h b/arch/mips/include/asm/mips-gic.h
index 75a1cdee1331..084cac1c5ea2 100644
--- a/arch/mips/include/asm/mips-gic.h
+++ b/arch/mips/include/asm/mips-gic.h
@@ -311,6 +311,36 @@ static inline bool mips_gic_present(void)
}
/**
+ * mips_gic_vx_map_reg() - Return GIC_Vx_<intr>_MAP register offset
+ * @intr: A GIC local interrupt
+ *
+ * Determine the index of the GIC_VL_<intr>_MAP or GIC_VO_<intr>_MAP register
+ * within the block of GIC map registers. This is almost the same as the order
+ * of interrupts in the pending & mask registers, as used by enum
+ * mips_gic_local_interrupt, but moves the FDC interrupt & thus offsets the
+ * interrupts after it...
+ *
+ * Return: The map register index corresponding to @intr.
+ *
+ * The return value is suitable for use with the (read|write)_gic_v[lo]_map
+ * accessor functions.
+ */
+static inline unsigned int
+mips_gic_vx_map_reg(enum mips_gic_local_interrupt intr)
+{
+ /* WD, Compare & Timer are 1:1 */
+ if (intr <= GIC_LOCAL_INT_TIMER)
+ return intr;
+
+ /* FDC moves to after Timer... */
+ if (intr == GIC_LOCAL_INT_FDC)
+ return GIC_LOCAL_INT_TIMER + 1;
+
+ /* As a result everything else is offset by 1 */
+ return intr + 1;
+}
+
+/**
* gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq
*
* Determine the virq number to use for the coprocessor 0 count/compare
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index f241ded9239b..1f0f29a289d3 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -786,6 +786,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
/* 32-bit PC relative address */
*loc = val - dot - 8 + addend;
break;
+ case R_PARISC_PCREL64:
+ /* 64-bit PC relative address */
+ *loc64 = val - dot - 8 + addend;
+ break;
case R_PARISC_DIR64:
/* 64-bit effective address */
*loc64 = val + addend;
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 6b86055e5251..73ba246ca11d 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -315,7 +315,7 @@ TRAMP_REAL_BEGIN(machine_check_common_early)
mfspr r11,SPRN_DSISR /* Save DSISR */
std r11,_DSISR(r1)
std r9,_CCR(r1) /* Save CR in stackframe */
- kuap_save_amr_and_lock r9, r10, cr1
+ /* We don't touch AMR here, we never go to virtual mode */
/* Save r9 through r13 from EXMC save area to stack frame. */
EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
mfmsr r11 /* get MSR value */
diff --git a/arch/powerpc/mm/book3s64/mmu_context.c b/arch/powerpc/mm/book3s64/mmu_context.c
index bb70391401f7..794404d50a85 100644
--- a/arch/powerpc/mm/book3s64/mmu_context.c
+++ b/arch/powerpc/mm/book3s64/mmu_context.c
@@ -50,20 +50,52 @@ EXPORT_SYMBOL_GPL(hash__alloc_context_id);
void slb_setup_new_exec(void);
+static int realloc_context_ids(mm_context_t *ctx)
+{
+ int i, id;
+
+ /*
+ * id 0 (aka. ctx->id) is special, we always allocate a new one, even if
+ * there wasn't one allocated previously (which happens in the exec
+ * case where ctx is newly allocated).
+ *
+ * We have to be a bit careful here. We must keep the existing ids in
+ * the array, so that we can test if they're non-zero to decide if we
+ * need to allocate a new one. However in case of error we must free the
+ * ids we've allocated but *not* any of the existing ones (or risk a
+ * UAF). That's why we decrement i at the start of the error handling
+ * loop, to skip the id that we just tested but couldn't reallocate.
+ */
+ for (i = 0; i < ARRAY_SIZE(ctx->extended_id); i++) {
+ if (i == 0 || ctx->extended_id[i]) {
+ id = hash__alloc_context_id();
+ if (id < 0)
+ goto error;
+
+ ctx->extended_id[i] = id;
+ }
+ }
+
+ /* The caller expects us to return id */
+ return ctx->id;
+
+error:
+ for (i--; i >= 0; i--) {
+ if (ctx->extended_id[i])
+ ida_free(&mmu_context_ida, ctx->extended_id[i]);
+ }
+
+ return id;
+}
+
static int hash__init_new_context(struct mm_struct *mm)
{
int index;
- index = hash__alloc_context_id();
- if (index < 0)
- return index;
-
mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context),
GFP_KERNEL);
- if (!mm->context.hash_context) {
- ida_free(&mmu_context_ida, index);
+ if (!mm->context.hash_context)
return -ENOMEM;
- }
/*
* The old code would re-promote on fork, we don't do that when using
@@ -91,13 +123,20 @@ static int hash__init_new_context(struct mm_struct *mm)
mm->context.hash_context->spt = kmalloc(sizeof(struct subpage_prot_table),
GFP_KERNEL);
if (!mm->context.hash_context->spt) {
- ida_free(&mmu_context_ida, index);
kfree(mm->context.hash_context);
return -ENOMEM;
}
}
#endif
+ }
+ index = realloc_context_ids(&mm->context);
+ if (index < 0) {
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+ kfree(mm->context.hash_context->spt);
+#endif
+ kfree(mm->context.hash_context);
+ return index;
}
pkey_mm_init(mm);
diff --git a/arch/riscv/boot/dts/sifive/fu540-c000.dtsi b/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
index 3c06ee4b2b29..40983491b95f 100644
--- a/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
+++ b/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
@@ -163,6 +163,7 @@
interrupt-parent = <&plic0>;
interrupts = <4>;
clocks = <&prci PRCI_CLK_TLCLK>;
+ status = "disabled";
};
uart1: serial@10011000 {
compatible = "sifive,fu540-c000-uart", "sifive,uart0";
@@ -170,6 +171,7 @@
interrupt-parent = <&plic0>;
interrupts = <5>;
clocks = <&prci PRCI_CLK_TLCLK>;
+ status = "disabled";
};
i2c0: i2c@10030000 {
compatible = "sifive,fu540-c000-i2c", "sifive,i2c0";
@@ -181,6 +183,7 @@
reg-io-width = <1>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
qspi0: spi@10040000 {
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
@@ -191,6 +194,7 @@
clocks = <&prci PRCI_CLK_TLCLK>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
qspi1: spi@10041000 {
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
@@ -201,6 +205,7 @@
clocks = <&prci PRCI_CLK_TLCLK>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
qspi2: spi@10050000 {
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
@@ -210,6 +215,7 @@
clocks = <&prci PRCI_CLK_TLCLK>;
#address-cells = <1>;
#size-cells = <0>;
+ status = "disabled";
};
};
};
diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 4da88707e28f..0b55c53c08c7 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -42,7 +42,20 @@
};
};
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
&qspi0 {
+ status = "okay";
flash@0 {
compatible = "issi,is25wp256", "jedec,spi-nor";
reg = <0>;
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 4f02967e55de..04944fb4fa7a 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -69,6 +69,7 @@ CONFIG_VIRTIO_MMIO=y
CONFIG_CLK_SIFIVE=y
CONFIG_CLK_SIFIVE_FU540_PRCI=y
CONFIG_SIFIVE_PLIC=y
+CONFIG_SPI_SIFIVE=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_AUTOFS4_FS=y
@@ -84,4 +85,8 @@ CONFIG_ROOT_NFS=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_DEV_VIRTIO=y
CONFIG_PRINTK_TIME=y
+CONFIG_SPI=y
+CONFIG_MMC_SPI=y
+CONFIG_MMC=y
+CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_RCU_TRACE is not set
diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c
index 3e2708c626a8..f960c3f4ce47 100644
--- a/arch/riscv/mm/fault.c
+++ b/arch/riscv/mm/fault.c
@@ -272,9 +272,6 @@ vmalloc_fault:
* entries, but in RISC-V, SFENCE.VMA specifies an
* ordering constraint, not a cache flush; it is
* necessary even after writing invalid entries.
- * Relying on flush_tlb_fix_spurious_fault would
- * suffice, but the extra traps reduce
- * performance. So, eagerly SFENCE.VMA.
*/
local_flush_tlb_page(addr);
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index f315425d8468..3cd94a21bd53 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -561,14 +561,14 @@ int x86_pmu_hw_config(struct perf_event *event)
}
/* sample_regs_user never support XMM registers */
- if (unlikely(event->attr.sample_regs_user & PEBS_XMM_REGS))
+ if (unlikely(event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK))
return -EINVAL;
/*
* Besides the general purpose registers, XMM registers may
* be collected in PEBS on some platforms, e.g. Icelake
*/
- if (unlikely(event->attr.sample_regs_intr & PEBS_XMM_REGS)) {
- if (x86_pmu.pebs_no_xmm_regs)
+ if (unlikely(event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK)) {
+ if (!(event->pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS))
return -EINVAL;
if (!event->attr.precise_ip)
@@ -2402,13 +2402,13 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
return;
}
- if (perf_hw_regs(regs)) {
- if (perf_callchain_store(entry, regs->ip))
- return;
+ if (perf_callchain_store(entry, regs->ip))
+ return;
+
+ if (perf_hw_regs(regs))
unwind_start(&state, current, regs, NULL);
- } else {
+ else
unwind_start(&state, current, NULL, (void *)regs->sp);
- }
for (; !unwind_done(&state); unwind_next_frame(&state)) {
addr = unwind_get_return_address(&state);
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 7acc526b4ad2..505c73dc6a73 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -987,7 +987,7 @@ static u64 pebs_update_adaptive_cfg(struct perf_event *event)
pebs_data_cfg |= PEBS_DATACFG_GP;
if ((sample_type & PERF_SAMPLE_REGS_INTR) &&
- (attr->sample_regs_intr & PEBS_XMM_REGS))
+ (attr->sample_regs_intr & PERF_REG_EXTENDED_MASK))
pebs_data_cfg |= PEBS_DATACFG_XMMS;
if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
@@ -1964,10 +1964,9 @@ void __init intel_ds_init(void)
x86_pmu.bts = boot_cpu_has(X86_FEATURE_BTS);
x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS);
x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
- if (x86_pmu.version <= 4) {
+ if (x86_pmu.version <= 4)
x86_pmu.pebs_no_isolation = 1;
- x86_pmu.pebs_no_xmm_regs = 1;
- }
+
if (x86_pmu.pebs) {
char pebs_type = x86_pmu.intel_cap.pebs_trap ? '+' : '-';
char *pebs_qual = "";
@@ -2020,9 +2019,9 @@ void __init intel_ds_init(void)
PERF_SAMPLE_TIME;
x86_pmu.flags |= PMU_FL_PEBS_ALL;
pebs_qual = "-baseline";
+ x86_get_pmu()->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
} else {
/* Only basic record supported */
- x86_pmu.pebs_no_xmm_regs = 1;
x86_pmu.large_pebs_flags &=
~(PERF_SAMPLE_ADDR |
PERF_SAMPLE_TIME |
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index a6ac2f4f76fc..4e346856ee19 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -121,24 +121,6 @@ struct amd_nb {
(1ULL << PERF_REG_X86_R14) | \
(1ULL << PERF_REG_X86_R15))
-#define PEBS_XMM_REGS \
- ((1ULL << PERF_REG_X86_XMM0) | \
- (1ULL << PERF_REG_X86_XMM1) | \
- (1ULL << PERF_REG_X86_XMM2) | \
- (1ULL << PERF_REG_X86_XMM3) | \
- (1ULL << PERF_REG_X86_XMM4) | \
- (1ULL << PERF_REG_X86_XMM5) | \
- (1ULL << PERF_REG_X86_XMM6) | \
- (1ULL << PERF_REG_X86_XMM7) | \
- (1ULL << PERF_REG_X86_XMM8) | \
- (1ULL << PERF_REG_X86_XMM9) | \
- (1ULL << PERF_REG_X86_XMM10) | \
- (1ULL << PERF_REG_X86_XMM11) | \
- (1ULL << PERF_REG_X86_XMM12) | \
- (1ULL << PERF_REG_X86_XMM13) | \
- (1ULL << PERF_REG_X86_XMM14) | \
- (1ULL << PERF_REG_X86_XMM15))
-
/*
* Per register state.
*/
@@ -668,8 +650,7 @@ struct x86_pmu {
pebs_broken :1,
pebs_prec_dist :1,
pebs_no_tlb :1,
- pebs_no_isolation :1,
- pebs_no_xmm_regs :1;
+ pebs_no_isolation :1;
int pebs_record_size;
int pebs_buffer_size;
int max_pebs_events;
diff --git a/arch/x86/include/uapi/asm/perf_regs.h b/arch/x86/include/uapi/asm/perf_regs.h
index ac67bbea10ca..7c9d2bb3833b 100644
--- a/arch/x86/include/uapi/asm/perf_regs.h
+++ b/arch/x86/include/uapi/asm/perf_regs.h
@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
/* These include both GPRs and XMMX registers */
PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
};
+
+#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
+
#endif /* _ASM_X86_PERF_REGS_H */
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 177aa8ef2afa..85be316665b4 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1464,7 +1464,8 @@ static void apic_pending_intr_clear(void)
if (queued) {
if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
ntsc = rdtsc();
- max_loops = (cpu_khz << 10) - (ntsc - tsc);
+ max_loops = (long long)cpu_khz << 10;
+ max_loops -= ntsc - tsc;
} else {
max_loops--;
}
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 03b4cc0ec3a7..66ca906aa790 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -836,6 +836,16 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
}
/*
+ * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
+ * bit in the mask to allow guests to use the mitigation even in the
+ * case where the host does not enable it.
+ */
+ if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
+ static_cpu_has(X86_FEATURE_AMD_SSBD)) {
+ x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
+ }
+
+ /*
* We have three CPU feature flags that are in play here:
* - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
* - X86_FEATURE_SSBD - CPU is able to turn off speculative store bypass
@@ -852,7 +862,6 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
x86_amd_ssb_disable();
} else {
x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
- x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
}
}
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index a813987b5552..cb0fdcaf1415 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -789,13 +789,16 @@ static struct syscore_ops mc_syscore_ops = {
.resume = mc_bp_resume,
};
-static int mc_cpu_online(unsigned int cpu)
+static int mc_cpu_starting(unsigned int cpu)
{
- struct device *dev;
-
- dev = get_cpu_device(cpu);
microcode_update_cpu(cpu);
pr_debug("CPU%d added\n", cpu);
+ return 0;
+}
+
+static int mc_cpu_online(unsigned int cpu)
+{
+ struct device *dev = get_cpu_device(cpu);
if (sysfs_create_group(&dev->kobj, &mc_attr_group))
pr_err("Failed to create group for CPU%d\n", cpu);
@@ -872,7 +875,9 @@ int __init microcode_init(void)
goto out_ucode_group;
register_syscore_ops(&mc_syscore_ops);
- cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:online",
+ cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting",
+ mc_cpu_starting, NULL);
+ cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/microcode:online",
mc_cpu_online, mc_cpu_down_prep);
pr_info("Microcode Update Driver: v%s.", DRIVER_VERSION);
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index 2131b8bbaad7..2f4824793798 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -796,8 +796,12 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
struct seq_file *seq, void *v)
{
struct rdt_resource *r = of->kn->parent->priv;
- u32 sw_shareable = 0, hw_shareable = 0;
- u32 exclusive = 0, pseudo_locked = 0;
+ /*
+ * Use unsigned long even though only 32 bits are used to ensure
+ * test_bit() is used safely.
+ */
+ unsigned long sw_shareable = 0, hw_shareable = 0;
+ unsigned long exclusive = 0, pseudo_locked = 0;
struct rdt_domain *dom;
int i, hwb, swb, excl, psl;
enum rdtgrp_mode mode;
@@ -842,10 +846,10 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
}
for (i = r->cache.cbm_len - 1; i >= 0; i--) {
pseudo_locked = dom->plr ? dom->plr->cbm : 0;
- hwb = test_bit(i, (unsigned long *)&hw_shareable);
- swb = test_bit(i, (unsigned long *)&sw_shareable);
- excl = test_bit(i, (unsigned long *)&exclusive);
- psl = test_bit(i, (unsigned long *)&pseudo_locked);
+ hwb = test_bit(i, &hw_shareable);
+ swb = test_bit(i, &sw_shareable);
+ excl = test_bit(i, &exclusive);
+ psl = test_bit(i, &pseudo_locked);
if (hwb && swb)
seq_putc(seq, 'X');
else if (hwb && !swb)
@@ -2486,26 +2490,19 @@ out_destroy:
*/
static void cbm_ensure_valid(u32 *_val, struct rdt_resource *r)
{
- /*
- * Convert the u32 _val to an unsigned long required by all the bit
- * operations within this function. No more than 32 bits of this
- * converted value can be accessed because all bit operations are
- * additionally provided with cbm_len that is initialized during
- * hardware enumeration using five bits from the EAX register and
- * thus never can exceed 32 bits.
- */
- unsigned long *val = (unsigned long *)_val;
+ unsigned long val = *_val;
unsigned int cbm_len = r->cache.cbm_len;
unsigned long first_bit, zero_bit;
- if (*val == 0)
+ if (val == 0)
return;
- first_bit = find_first_bit(val, cbm_len);
- zero_bit = find_next_zero_bit(val, cbm_len, first_bit);
+ first_bit = find_first_bit(&val, cbm_len);
+ zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
/* Clear any remaining bits to ensure contiguous region */
- bitmap_clear(val, zero_bit, cbm_len - zero_bit);
+ bitmap_clear(&val, zero_bit, cbm_len - zero_bit);
+ *_val = (u32)val;
}
/*
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 16b1cbd3a61e..29ffa495bd1c 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -184,24 +184,25 @@ unsigned long __head __startup_64(unsigned long physaddr,
pgtable_flags = _KERNPG_TABLE_NOENC + sme_get_me_mask();
if (la57) {
- p4d = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
+ p4d = fixup_pointer(early_dynamic_pgts[(*next_pgt_ptr)++],
+ physaddr);
i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
pgd[i + 0] = (pgdval_t)p4d + pgtable_flags;
pgd[i + 1] = (pgdval_t)p4d + pgtable_flags;
- i = (physaddr >> P4D_SHIFT) % PTRS_PER_P4D;
- p4d[i + 0] = (pgdval_t)pud + pgtable_flags;
- p4d[i + 1] = (pgdval_t)pud + pgtable_flags;
+ i = physaddr >> P4D_SHIFT;
+ p4d[(i + 0) % PTRS_PER_P4D] = (pgdval_t)pud + pgtable_flags;
+ p4d[(i + 1) % PTRS_PER_P4D] = (pgdval_t)pud + pgtable_flags;
} else {
i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
pgd[i + 0] = (pgdval_t)pud + pgtable_flags;
pgd[i + 1] = (pgdval_t)pud + pgtable_flags;
}
- i = (physaddr >> PUD_SHIFT) % PTRS_PER_PUD;
- pud[i + 0] = (pudval_t)pmd + pgtable_flags;
- pud[i + 1] = (pudval_t)pmd + pgtable_flags;
+ i = physaddr >> PUD_SHIFT;
+ pud[(i + 0) % PTRS_PER_PUD] = (pudval_t)pmd + pgtable_flags;
+ pud[(i + 1) % PTRS_PER_PUD] = (pudval_t)pmd + pgtable_flags;
pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
/* Filter out unsupported __PAGE_KERNEL_* bits: */
@@ -211,8 +212,9 @@ unsigned long __head __startup_64(unsigned long physaddr,
pmd_entry += physaddr;
for (i = 0; i < DIV_ROUND_UP(_end - _text, PMD_SIZE); i++) {
- int idx = i + (physaddr >> PMD_SHIFT) % PTRS_PER_PMD;
- pmd[idx] = pmd_entry + i * PMD_SIZE;
+ int idx = i + (physaddr >> PMD_SHIFT);
+
+ pmd[idx % PTRS_PER_PMD] = pmd_entry + i * PMD_SIZE;
}
/*
diff --git a/arch/x86/kernel/perf_regs.c b/arch/x86/kernel/perf_regs.c
index 07c30ee17425..bb7e1132290b 100644
--- a/arch/x86/kernel/perf_regs.c
+++ b/arch/x86/kernel/perf_regs.c
@@ -74,6 +74,9 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
return regs_get_register(regs, pt_regs_offset[idx]);
}
+#define PERF_REG_X86_RESERVED (((1ULL << PERF_REG_X86_XMM0) - 1) & \
+ ~((1ULL << PERF_REG_X86_MAX) - 1))
+
#ifdef CONFIG_X86_32
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
(1ULL << PERF_REG_X86_R9) | \
@@ -86,7 +89,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
int perf_reg_validate(u64 mask)
{
- if (!mask || (mask & REG_NOSUPPORT))
+ if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
return -EINVAL;
return 0;
@@ -112,7 +115,7 @@ void perf_get_regs_user(struct perf_regs *regs_user,
int perf_reg_validate(u64 mask)
{
- if (!mask || (mask & REG_NOSUPPORT))
+ if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
return -EINVAL;
return 0;
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
index 33b66b5c5aec..72b997eaa1fc 100644
--- a/arch/x86/kernel/unwind_orc.c
+++ b/arch/x86/kernel/unwind_orc.c
@@ -82,9 +82,9 @@ static struct orc_entry *orc_find(unsigned long ip);
* But they are copies of the ftrace entries that are static and
* defined in ftrace_*.S, which do have orc entries.
*
- * If the undwinder comes across a ftrace trampoline, then find the
+ * If the unwinder comes across a ftrace trampoline, then find the
* ftrace function that was used to create it, and use that ftrace
- * function's orc entrie, as the placement of the return code in
+ * function's orc entry, as the placement of the return code in
* the stack will be identical.
*/
static struct orc_entry *orc_ftrace_find(unsigned long ip)
@@ -128,6 +128,16 @@ static struct orc_entry null_orc_entry = {
.type = ORC_TYPE_CALL
};
+/* Fake frame pointer entry -- used as a fallback for generated code */
+static struct orc_entry orc_fp_entry = {
+ .type = ORC_TYPE_CALL,
+ .sp_reg = ORC_REG_BP,
+ .sp_offset = 16,
+ .bp_reg = ORC_REG_PREV_SP,
+ .bp_offset = -16,
+ .end = 0,
+};
+
static struct orc_entry *orc_find(unsigned long ip)
{
static struct orc_entry *orc;
@@ -392,8 +402,16 @@ bool unwind_next_frame(struct unwind_state *state)
* calls and calls to noreturn functions.
*/
orc = orc_find(state->signal ? state->ip : state->ip - 1);
- if (!orc)
- goto err;
+ if (!orc) {
+ /*
+ * As a fallback, try to assume this code uses a frame pointer.
+ * This is useful for generated code, like BPF, which ORC
+ * doesn't know about. This is just a guess, so the rest of
+ * the unwind is no longer considered reliable.
+ */
+ orc = &orc_fp_entry;
+ state->error = true;
+ }
/* End-of-stack check for kernel threads: */
if (orc->sp_reg == ORC_REG_UNDEFINED) {
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 693aaf28d5fe..0f01c7b1d217 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -671,23 +671,25 @@ static unsigned long __meminit
phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
unsigned long page_size_mask, bool init)
{
- unsigned long paddr_next, paddr_last = paddr_end;
- unsigned long vaddr = (unsigned long)__va(paddr);
- int i = p4d_index(vaddr);
+ unsigned long vaddr, vaddr_end, vaddr_next, paddr_next, paddr_last;
+
+ paddr_last = paddr_end;
+ vaddr = (unsigned long)__va(paddr);
+ vaddr_end = (unsigned long)__va(paddr_end);
if (!pgtable_l5_enabled())
return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end,
page_size_mask, init);
- for (; i < PTRS_PER_P4D; i++, paddr = paddr_next) {
- p4d_t *p4d;
+ for (; vaddr < vaddr_end; vaddr = vaddr_next) {
+ p4d_t *p4d = p4d_page + p4d_index(vaddr);
pud_t *pud;
- vaddr = (unsigned long)__va(paddr);
- p4d = p4d_page + p4d_index(vaddr);
- paddr_next = (paddr & P4D_MASK) + P4D_SIZE;
+ vaddr_next = (vaddr & P4D_MASK) + P4D_SIZE;
+ paddr = __pa(vaddr);
if (paddr >= paddr_end) {
+ paddr_next = __pa(vaddr_next);
if (!after_bootmem &&
!e820__mapped_any(paddr & P4D_MASK, paddr_next,
E820_TYPE_RAM) &&
@@ -699,13 +701,13 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
if (!p4d_none(*p4d)) {
pud = pud_offset(p4d, 0);
- paddr_last = phys_pud_init(pud, paddr, paddr_end,
- page_size_mask, init);
+ paddr_last = phys_pud_init(pud, paddr, __pa(vaddr_end),
+ page_size_mask, init);
continue;
}
pud = alloc_low_page();
- paddr_last = phys_pud_init(pud, paddr, paddr_end,
+ paddr_last = phys_pud_init(pud, paddr, __pa(vaddr_end),
page_size_mask, init);
spin_lock(&init_mm.page_table_lock);
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 632b83885867..3b9fd679cea9 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -728,7 +728,7 @@ void efi_recover_from_page_fault(unsigned long phys_addr)
* Address range 0x0000 - 0x0fff is always mapped in the efi_pgd, so
* page faulting on these addresses isn't expected.
*/
- if (phys_addr >= 0x0000 && phys_addr <= 0x0fff)
+ if (phys_addr <= 0x0fff)
return;
/*
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index f8d430f88d25..f9269ae6da9c 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -240,7 +240,7 @@ static struct kmem_cache *bfq_pool;
* containing only random (seeky) I/O are prevented from being tagged
* as soft real-time.
*/
-#define BFQQ_TOTALLY_SEEKY(bfqq) (bfqq->seek_history & -1)
+#define BFQQ_TOTALLY_SEEKY(bfqq) (bfqq->seek_history == -1)
/* Min number of samples required to perform peak-rate update */
#define BFQ_RATE_MIN_SAMPLES 32
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
index 40c8a552a478..4074886b7bc8 100644
--- a/drivers/auxdisplay/cfag12864bfb.c
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -52,8 +52,9 @@ static const struct fb_var_screeninfo cfag12864bfb_var = {
static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
- return vm_insert_page(vma, vma->vm_start,
- virt_to_page(cfag12864b_buffer));
+ struct page *pages = virt_to_page(cfag12864b_buffer);
+
+ return vm_map_pages_zero(vma, &pages, 1);
}
static struct fb_ops cfag12864bfb_ops = {
diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c
index 21393ec3b9a4..9c0bb771751d 100644
--- a/drivers/auxdisplay/ht16k33.c
+++ b/drivers/auxdisplay/ht16k33.c
@@ -223,9 +223,9 @@ static const struct backlight_ops ht16k33_bl_ops = {
static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct ht16k33_priv *priv = info->par;
+ struct page *pages = virt_to_page(priv->fbdev.buffer);
- return vm_insert_page(vma, vma->vm_start,
- virt_to_page(priv->fbdev.buffer));
+ return vm_map_pages_zero(vma, &pages, 1);
}
static struct fb_ops ht16k33_fb_ops = {
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index aa51756fd4d6..87b410d6e51d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -368,7 +368,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
const char *dev_id = dev ? dev_name(dev) : NULL;
struct device_node *np = core->of_node;
- if (np && index >= 0)
+ if (np && (name || index >= 0))
hw = of_clk_get_hw(np, index, name);
/*
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index 739f64fdf1e3..206fafd299ea 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -2734,8 +2734,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
[CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw,
[CLKID_MALI_1] = &g12a_mali_1.hw,
[CLKID_MALI] = &g12a_mali.hw,
- [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw,
- [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw,
+ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw,
+ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw,
[CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw,
[CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw,
[CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw,
diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h
index 39c41af70804..bcc05cd9882f 100644
--- a/drivers/clk/meson/g12a.h
+++ b/drivers/clk/meson/g12a.h
@@ -166,7 +166,7 @@
#define CLKID_HDMI_DIV 167
#define CLKID_MALI_0_DIV 170
#define CLKID_MALI_1_DIV 173
-#define CLKID_MPLL_5OM_DIV 176
+#define CLKID_MPLL_50M_DIV 176
#define CLKID_SYS_PLL_DIV16_EN 178
#define CLKID_SYS_PLL_DIV16 179
#define CLKID_CPU_CLK_DYN0_SEL 180
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 37cf0f01bb5d..62cd3a7f1f65 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -1761,7 +1761,7 @@ static struct clk_regmap meson8m2_gp_pll = {
},
};
-static const char * const mmeson8b_vpu_0_1_parent_names[] = {
+static const char * const meson8b_vpu_0_1_parent_names[] = {
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
};
@@ -1778,8 +1778,8 @@ static struct clk_regmap meson8b_vpu_0_sel = {
.hw.init = &(struct clk_init_data){
.name = "vpu_0_sel",
.ops = &clk_regmap_mux_ops,
- .parent_names = mmeson8b_vpu_0_1_parent_names,
- .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names),
+ .parent_names = meson8b_vpu_0_1_parent_names,
+ .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names),
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -1837,8 +1837,8 @@ static struct clk_regmap meson8b_vpu_1_sel = {
.hw.init = &(struct clk_init_data){
.name = "vpu_1_sel",
.ops = &clk_regmap_mux_ops,
- .parent_names = mmeson8b_vpu_0_1_parent_names,
- .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names),
+ .parent_names = meson8b_vpu_0_1_parent_names,
+ .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names),
.flags = CLK_SET_RATE_PARENT,
},
};
diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c
index 8281dfbf38c2..5bed36e12951 100644
--- a/drivers/clk/socfpga/clk-s10.c
+++ b/drivers/clk/socfpga/clk-s10.c
@@ -103,9 +103,9 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
{ STRATIX10_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux),
0, 0, 0, 0x3C, 1},
{ STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux),
- 0, 0, 4, 0xB0, 0},
+ 0, 0, 2, 0xB0, 0},
{ STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
- 0, 0, 4, 0xB0, 1},
+ 0, 0, 2, 0xB0, 1},
{ STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux,
ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2},
{ STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index e1ba62d2b1a0..ac1d27a8c650 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -3366,6 +3366,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_I2S3_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
{ TEGRA210_CLK_I2S4_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
{ TEGRA210_CLK_VIMCLK_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
+ { TEGRA210_CLK_HDA, TEGRA210_CLK_PLL_P, 51000000, 0 },
+ { TEGRA210_CLK_HDA2CODEC_2X, TEGRA210_CLK_PLL_P, 48000000, 0 },
/* This MUST be the last entry. */
{ TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 },
};
diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c
index 8e834317c97d..975995eea15c 100644
--- a/drivers/clk/ti/clkctrl.c
+++ b/drivers/clk/ti/clkctrl.c
@@ -229,6 +229,7 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
{
struct omap_clkctrl_provider *provider = data;
struct omap_clkctrl_clk *entry;
+ bool found = false;
if (clkspec->args_count != 2)
return ERR_PTR(-EINVAL);
@@ -238,11 +239,13 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
list_for_each_entry(entry, &provider->clocks, node) {
if (entry->reg_offset == clkspec->args[0] &&
- entry->bit_offset == clkspec->args[1])
+ entry->bit_offset == clkspec->args[1]) {
+ found = true;
break;
+ }
}
- if (!entry)
+ if (!found)
return ERR_PTR(-EINVAL);
return entry->clk;
diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c
index a2384184a7de..b07c17643210 100644
--- a/drivers/firmware/efi/efi-bgrt.c
+++ b/drivers/firmware/efi/efi-bgrt.c
@@ -47,11 +47,6 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
bgrt->version);
goto out;
}
- if (bgrt->status & 0xfe) {
- pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n",
- bgrt->status);
- goto out;
- }
if (bgrt->image_type != 0) {
pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n",
bgrt->image_type);
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 16b2137d117c..4b7cf7bc0ded 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -1009,14 +1009,16 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
/* first try to find a slot in an existing linked list entry */
for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
- rsv = __va(prsv);
+ rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
if (index < rsv->size) {
rsv->entry[index].base = addr;
rsv->entry[index].size = size;
+ memunmap(rsv);
return 0;
}
+ memunmap(rsv);
}
/* no slot found - allocate a new linked list entry */
@@ -1024,7 +1026,13 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
if (!rsv)
return -ENOMEM;
- rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE);
+ /*
+ * The memremap() call above assumes that a linux_efi_memreserve entry
+ * never crosses a page boundary, so let's ensure that this remains true
+ * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by
+ * using SZ_4K explicitly in the size calculation below.
+ */
+ rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K);
atomic_set(&rsv->count, 1);
rsv->entry[0].base = addr;
rsv->entry[0].size = size;
diff --git a/drivers/firmware/efi/efibc.c b/drivers/firmware/efi/efibc.c
index 61e099826cbb..35dccc88ac0a 100644
--- a/drivers/firmware/efi/efibc.c
+++ b/drivers/firmware/efi/efibc.c
@@ -43,11 +43,13 @@ static int efibc_set_variable(const char *name, const char *value)
efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data);
memcpy(&entry->var.VendorGuid, &guid, sizeof(guid));
- ret = efivar_entry_set(entry,
- EFI_VARIABLE_NON_VOLATILE
- | EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS,
- size, entry->var.Data, NULL);
+ ret = efivar_entry_set_safe(entry->var.VariableName,
+ entry->var.VendorGuid,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS,
+ false, size, entry->var.Data);
+
if (ret)
pr_err("failed to set %s EFI variable: 0x%x\n",
name, ret);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index eac0c54c5970..b032d3899fa3 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -80,6 +80,7 @@
#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220
#define HID_DEVICE_ID_ALPS_U1 0x1215
#define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C
+#define HID_DEVICE_ID_ALPS_1222 0x1222
#define USB_VENDOR_ID_AMI 0x046b
@@ -269,6 +270,7 @@
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053
+#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2 0x0939
#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123
#define USB_DEVICE_ID_ASUS_AK1D 0x1125
#define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A 0x1408
@@ -569,6 +571,7 @@
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
+#define USB_DEVICE_ID_HUION_HS64 0x006d
#define USB_VENDOR_ID_IBM 0x04b3
#define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index e564bff86515..bfcf2ee58d14 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -30,6 +30,7 @@
#define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11
+#define REPORT_ID_HIDPP_VERY_LONG 0x12
#define HIDPP_REPORT_SHORT_LENGTH 7
#define HIDPP_REPORT_LONG_LENGTH 20
@@ -1242,7 +1243,8 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
int ret;
if ((buf[0] == REPORT_ID_HIDPP_SHORT) ||
- (buf[0] == REPORT_ID_HIDPP_LONG)) {
+ (buf[0] == REPORT_ID_HIDPP_LONG) ||
+ (buf[0] == REPORT_ID_HIDPP_VERY_LONG)) {
if (count < 2)
return -EINVAL;
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 5df5dd56ecc8..b603c14d043b 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1776,6 +1776,10 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_ALPS_JP,
HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
+ { .driver_data = MT_CLS_WIN_8_DUAL,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_ALPS_JP,
+ HID_DEVICE_ID_ALPS_1222) },
/* Lenovo X1 TAB Gen 2 */
{ .driver_data = MT_CLS_WIN_8_DUAL,
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index e5ca6fe2ca57..671a285724f9 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -42,6 +42,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET },
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index 8fe02d81265d..914fb527ae7a 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -369,6 +369,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
+ USB_DEVICE_ID_HUION_HS64) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index 0187c9f8fc22..273d784fff66 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -977,6 +977,8 @@ int uclogic_params_init(struct uclogic_params *params,
/* FALL THROUGH */
case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET):
+ case VID_PID(USB_VENDOR_ID_HUION,
+ USB_DEVICE_ID_HUION_HS64):
case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET):
case VID_PID(USB_VENDOR_ID_UCLOGIC,
diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
index 22ba21457035..aa2dbed30fc3 100644
--- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
+++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
@@ -816,9 +816,9 @@ static int load_fw_from_host(struct ishtp_cl_data *client_data)
goto end_err_fw_release;
release_firmware(fw);
- kfree(filename);
dev_info(cl_data_to_dev(client_data), "ISH firmware %s loaded\n",
filename);
+ kfree(filename);
return 0;
end_err_fw_release:
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
index c0487b34d2cf..6ba944b40fdb 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
@@ -891,7 +891,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
*/
static int hid_ishtp_cl_suspend(struct device *device)
{
- struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+ struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
@@ -912,7 +912,7 @@ static int hid_ishtp_cl_suspend(struct device *device)
*/
static int hid_ishtp_cl_resume(struct device *device)
{
- struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+ struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index 794e700d65f7..c47c3328a0f4 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -471,7 +471,6 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
}
ishtp_device_ready = true;
- dev_set_drvdata(&device->dev, device);
return device;
}
@@ -640,6 +639,20 @@ void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
EXPORT_SYMBOL(ishtp_get_drvdata);
/**
+ * ishtp_dev_to_cl_device() - get ishtp_cl_device instance from device instance
+ * @device: device instance
+ *
+ * Get ish_cl_device instance which embeds device instance in it.
+ *
+ * Return: pointer to ishtp_cl_device instance
+ */
+struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *device)
+{
+ return to_ishtp_cl_device(device);
+}
+EXPORT_SYMBOL(ishtp_dev_to_cl_device);
+
+/**
* ishtp_bus_new_client() - Create a new client
* @dev: ISHTP device instance
*
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
index c67c961ab6cc..a4c1aacba1ff 100644
--- a/drivers/irqchip/irq-csky-mpintc.c
+++ b/drivers/irqchip/irq-csky-mpintc.c
@@ -89,8 +89,19 @@ static int csky_irq_set_affinity(struct irq_data *d,
if (cpu >= nr_cpu_ids)
return -EINVAL;
- /* Enable interrupt destination */
- cpu |= BIT(31);
+ /*
+ * The csky,mpintc could support auto irq deliver, but it only
+ * could deliver external irq to one cpu or all cpus. So it
+ * doesn't support deliver external irq to a group of cpus
+ * with cpu_mask.
+ * SO we only use auto deliver mode when affinity mask_val is
+ * equal to cpu_present_mask.
+ *
+ */
+ if (cpumask_equal(mask_val, cpu_present_mask))
+ cpu = 0;
+ else
+ cpu |= BIT(31);
writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset);
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index d29b44b677e4..35500801dc2b 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -733,32 +733,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
}
static int its_wait_for_range_completion(struct its_node *its,
- struct its_cmd_block *from,
+ u64 prev_idx,
struct its_cmd_block *to)
{
- u64 rd_idx, from_idx, to_idx;
+ u64 rd_idx, to_idx, linear_idx;
u32 count = 1000000; /* 1s! */
- from_idx = its_cmd_ptr_to_offset(its, from);
+ /* Linearize to_idx if the command set has wrapped around */
to_idx = its_cmd_ptr_to_offset(its, to);
+ if (to_idx < prev_idx)
+ to_idx += ITS_CMD_QUEUE_SZ;
+
+ linear_idx = prev_idx;
while (1) {
+ s64 delta;
+
rd_idx = readl_relaxed(its->base + GITS_CREADR);
- /* Direct case */
- if (from_idx < to_idx && rd_idx >= to_idx)
- break;
+ /*
+ * Compute the read pointer progress, taking the
+ * potential wrap-around into account.
+ */
+ delta = rd_idx - prev_idx;
+ if (rd_idx < prev_idx)
+ delta += ITS_CMD_QUEUE_SZ;
- /* Wrapped case */
- if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx)
+ linear_idx += delta;
+ if (linear_idx >= to_idx)
break;
count--;
if (!count) {
- pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n",
- from_idx, to_idx, rd_idx);
+ pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
+ to_idx, linear_idx);
return -1;
}
+ prev_idx = rd_idx;
cpu_relax();
udelay(1);
}
@@ -775,6 +786,7 @@ void name(struct its_node *its, \
struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
synctype *sync_obj; \
unsigned long flags; \
+ u64 rd_idx; \
\
raw_spin_lock_irqsave(&its->lock, flags); \
\
@@ -796,10 +808,11 @@ void name(struct its_node *its, \
} \
\
post: \
+ rd_idx = readl_relaxed(its->base + GITS_CREADR); \
next_cmd = its_post_commands(its); \
raw_spin_unlock_irqrestore(&its->lock, flags); \
\
- if (its_wait_for_range_completion(its, cmd, next_cmd)) \
+ if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \
pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
}
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index d32268cc1174..f3985469c221 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
cd = irq_data_get_irq_chip_data(d);
- write_gic_vl_map(intr, cd->map);
+ write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
if (cd->mask)
write_gic_vl_smask(BIT(intr));
}
@@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
spin_lock_irqsave(&gic_lock, flags);
for_each_online_cpu(cpu) {
write_gic_vl_other(mips_cm_vp_id(cpu));
- write_gic_vo_map(intr, map);
+ write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
}
spin_unlock_irqrestore(&gic_lock, flags);
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index 011b60a49e3f..ef4d625d2d80 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -159,9 +159,9 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
parent_fwspec.param[1] = vint_desc->vint_id;
parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
- if (parent_virq <= 0) {
+ if (parent_virq == 0) {
kfree(vint_desc);
- return ERR_PTR(parent_virq);
+ return ERR_PTR(-EINVAL);
}
vint_desc->parent_virq = parent_virq;
diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c
index 352e803f566e..728733a514c7 100644
--- a/drivers/md/dm-init.c
+++ b/drivers/md/dm-init.c
@@ -140,8 +140,8 @@ static char __init *dm_parse_table_entry(struct dm_device *dev, char *str)
return ERR_PTR(-EINVAL);
}
/* target_args */
- dev->target_args_array[n] = kstrndup(field[3], GFP_KERNEL,
- DM_MAX_STR_SIZE);
+ dev->target_args_array[n] = kstrndup(field[3], DM_MAX_STR_SIZE,
+ GFP_KERNEL);
if (!dev->target_args_array[n])
return ERR_PTR(-ENOMEM);
@@ -272,10 +272,10 @@ static int __init dm_init_init(void)
return 0;
if (strlen(create) >= DM_MAX_STR_SIZE) {
- DMERR("Argument is too big. Limit is %d\n", DM_MAX_STR_SIZE);
+ DMERR("Argument is too big. Limit is %d", DM_MAX_STR_SIZE);
return -EINVAL;
}
- str = kstrndup(create, GFP_KERNEL, DM_MAX_STR_SIZE);
+ str = kstrndup(create, DM_MAX_STR_SIZE, GFP_KERNEL);
if (!str)
return -ENOMEM;
@@ -283,7 +283,7 @@ static int __init dm_init_init(void)
if (r)
goto out;
- DMINFO("waiting for all devices to be available before creating mapped devices\n");
+ DMINFO("waiting for all devices to be available before creating mapped devices");
wait_for_device_probe();
list_for_each_entry(dev, &devices, list) {
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 9ea2b0291f20..e549392e0ea5 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -60,6 +60,7 @@
#define WRITE_LOG_VERSION 1ULL
#define WRITE_LOG_MAGIC 0x6a736677736872ULL
+#define WRITE_LOG_SUPER_SECTOR 0
/*
* The disk format for this is braindead simple.
@@ -115,6 +116,7 @@ struct log_writes_c {
struct list_head logging_blocks;
wait_queue_head_t wait;
struct task_struct *log_kthread;
+ struct completion super_done;
};
struct pending_block {
@@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio)
bio_put(bio);
}
+static void log_end_super(struct bio *bio)
+{
+ struct log_writes_c *lc = bio->bi_private;
+
+ complete(&lc->super_done);
+ log_end_io(bio);
+}
+
/*
* Meant to be called if there is an error, it will free all the pages
* associated with the block.
@@ -215,7 +225,8 @@ static int write_metadata(struct log_writes_c *lc, void *entry,
bio->bi_iter.bi_size = 0;
bio->bi_iter.bi_sector = sector;
bio_set_dev(bio, lc->logdev->bdev);
- bio->bi_end_io = log_end_io;
+ bio->bi_end_io = (sector == WRITE_LOG_SUPER_SECTOR) ?
+ log_end_super : log_end_io;
bio->bi_private = lc;
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
@@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc)
super.nr_entries = cpu_to_le64(lc->logged_entries);
super.sectorsize = cpu_to_le32(lc->sectorsize);
- if (write_metadata(lc, &super, sizeof(super), NULL, 0, 0)) {
+ if (write_metadata(lc, &super, sizeof(super), NULL, 0,
+ WRITE_LOG_SUPER_SECTOR)) {
DMERR("Couldn't write super");
return -1;
}
+ /*
+ * Super sector should be writen in-order, otherwise the
+ * nr_entries could be rewritten incorrectly by an old bio.
+ */
+ wait_for_completion_io(&lc->super_done);
+
return 0;
}
@@ -531,6 +549,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv)
INIT_LIST_HEAD(&lc->unflushed_blocks);
INIT_LIST_HEAD(&lc->logging_blocks);
init_waitqueue_head(&lc->wait);
+ init_completion(&lc->super_done);
atomic_set(&lc->io_blocks, 0);
atomic_set(&lc->pending_blocks, 0);
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 350cf0451456..ec8b27e20de3 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv)
gfp = GFP_NOIO;
}
argv = kmalloc_array(new_size, sizeof(*argv), gfp);
- if (argv) {
+ if (argv && old_argv) {
memcpy(argv, old_argv, *size * sizeof(*argv));
*size = new_size;
}
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 720d06531aa3..ea24ff0612e3 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -235,8 +235,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
BUG();
}
- DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
- block);
+ DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
+ type_str, block);
if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
DMERR("%s: reached maximum errors", v->data_dev->name);
diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c
index fe8efba2d45f..857991cb3cbb 100644
--- a/drivers/mfd/stmfx.c
+++ b/drivers/mfd/stmfx.c
@@ -204,12 +204,11 @@ static struct irq_chip stmfx_irq_chip = {
static irqreturn_t stmfx_irq_handler(int irq, void *data)
{
struct stmfx *stmfx = data;
- unsigned long n, pending;
- u32 ack;
- int ret;
+ unsigned long bits;
+ u32 pending, ack;
+ int n, ret;
- ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING,
- (u32 *)&pending);
+ ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, &pending);
if (ret)
return IRQ_NONE;
@@ -224,7 +223,8 @@ static irqreturn_t stmfx_irq_handler(int irq, void *data)
return IRQ_NONE;
}
- for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX)
+ bits = pending;
+ for_each_set_bit(n, &bits, STMFX_REG_IRQ_SRC_MAX)
handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n));
return IRQ_HANDLED;
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index b5b68aa16eb3..6eb131292eb2 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4662,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
memorg = nanddev_get_memorg(&chip->base);
memorg->planes_per_lun = 1;
memorg->luns_per_target = 1;
- memorg->ntargets = 1;
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -5027,6 +5026,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
if (ret)
return ret;
+ memorg->ntargets = maxchips;
+
/* Read the flash type */
ret = nand_detect(chip, table);
if (ret) {
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 73172d7f512b..0c2ec1c21434 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
return 0;
}
+/**
+ * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_clear_sr_bp(struct spi_nor *nor)
+{
+ int ret;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+ ret = read_sr(nor);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while reading status register\n");
+ return ret;
+ }
+
+ write_enable(nor);
+
+ ret = write_sr(nor, ret & ~mask);
+ if (ret) {
+ dev_err(nor->dev, "write to status register failed\n");
+ return ret;
+ }
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ dev_err(nor->dev, "timeout while writing status register\n");
+ return ret;
+}
+
+/**
+ * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
+ * bits on spansion flashes.
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits. The function is tightly
+ * coupled with the spansion_quad_enable() function. Both assume that the Write
+ * Register with 16 bits, together with the Read Configuration Register (35h)
+ * instructions are supported.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
+{
+ int ret;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 sr_cr[2] = {0};
+
+ /* Check current Quad Enable bit value. */
+ ret = read_cr(nor);
+ if (ret < 0) {
+ dev_err(nor->dev,
+ "error while reading configuration register\n");
+ return ret;
+ }
+
+ /*
+ * When the configuration register Quad Enable bit is one, only the
+ * Write Status (01h) command with two data bytes may be used.
+ */
+ if (ret & CR_QUAD_EN_SPAN) {
+ sr_cr[1] = ret;
+
+ ret = read_sr(nor);
+ if (ret < 0) {
+ dev_err(nor->dev,
+ "error while reading status register\n");
+ return ret;
+ }
+ sr_cr[0] = ret & ~mask;
+
+ ret = write_sr_cr(nor, sr_cr);
+ if (ret)
+ dev_err(nor->dev, "16-bit write register failed\n");
+ return ret;
+ }
+
+ /*
+ * If the Quad Enable bit is zero, use the Write Status (01h) command
+ * with one data byte.
+ */
+ return spi_nor_clear_sr_bp(nor);
+}
+
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
@@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
default:
/* Kept only for backward compatibility purpose. */
params->quad_enable = spansion_quad_enable;
+ if (nor->clear_sr_bp)
+ nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
break;
}
@@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
- /*
- * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
- * with the software protection bits set
- */
- if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
- JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
- JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
- nor->info->flags & SPI_NOR_HAS_LOCK) {
- write_enable(nor);
- write_sr(nor, 0);
- spi_nor_wait_till_ready(nor);
+ if (nor->clear_sr_bp) {
+ err = nor->clear_sr_bp(nor);
+ if (err) {
+ dev_err(nor->dev,
+ "fail to clear block protection bits\n");
+ return err;
+ }
}
if (nor->quad_enable) {
@@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (info->flags & SPI_S3AN)
nor->flags |= SNOR_F_READY_XSR_RDY;
+ /*
+ * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+ * with the software protection bits set.
+ */
+ if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
+ JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
+ JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
+ nor->info->flags & SPI_NOR_HAS_LOCK)
+ nor->clear_sr_bp = spi_nor_clear_sr_bp;
+
/* Parse the Serial Flash Discoverable Parameters table. */
ret = spi_nor_init_params(nor, &params);
if (ret)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 407f4095a37a..799fc38c5c34 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4320,12 +4320,12 @@ void bond_setup(struct net_device *bond_dev)
bond_dev->features |= NETIF_F_NETNS_LOCAL;
bond_dev->hw_features = BOND_VLAN_FEATURES |
- NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
bond_dev->features |= bond_dev->hw_features;
+ bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
}
/* Destroy a bonding device.
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index f46086fa9064..db91b213eae1 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -436,9 +436,9 @@ int ksz_switch_register(struct ksz_device *dev,
return PTR_ERR(dev->reset_gpio);
if (dev->reset_gpio) {
- gpiod_set_value(dev->reset_gpio, 1);
+ gpiod_set_value_cansleep(dev->reset_gpio, 1);
mdelay(10);
- gpiod_set_value(dev->reset_gpio, 0);
+ gpiod_set_value_cansleep(dev->reset_gpio, 0);
}
mutex_init(&dev->dev_mutex);
@@ -487,7 +487,7 @@ void ksz_switch_remove(struct ksz_device *dev)
dsa_unregister_switch(dev->ds);
if (dev->reset_gpio)
- gpiod_set_value(dev->reset_gpio, 1);
+ gpiod_set_value_cansleep(dev->reset_gpio, 1);
}
EXPORT_SYMBOL(ksz_switch_remove);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index 18bc035da850..1fff462a4175 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -843,9 +843,14 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
return err;
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
- if (hweight < AQ_VLAN_MAX_FILTERS)
- err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, true);
+ if (hweight < AQ_VLAN_MAX_FILTERS && hweight > 0) {
+ err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw,
+ !(aq_nic->packet_filter & IFF_PROMISC));
+ aq_nic->aq_nic_cfg.is_vlan_force_promisc = false;
+ } else {
/* otherwise left in promiscue mode */
+ aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
+ }
}
return err;
@@ -866,6 +871,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
return -EOPNOTSUPP;
+ aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
if (err)
return err;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 0da5e161ec5d..41172fbebddd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -126,6 +126,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
cfg->features = cfg->aq_hw_caps->hw_features;
+ cfg->is_vlan_force_promisc = true;
}
static int aq_nic_update_link_status(struct aq_nic_s *self)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index eb2e3c7c36f9..0f22f5d5691b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -35,6 +35,7 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 wol;
+ bool is_vlan_force_promisc;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 1c7593d54035..13ac2661a473 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -778,8 +778,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
unsigned int packet_filter)
{
unsigned int i = 0U;
+ struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
+
+ hw_atl_rpfl2promiscuous_mode_en_set(self,
+ IS_FILTER_ENABLED(IFF_PROMISC));
+
+ hw_atl_rpf_vlan_prom_mode_en_set(self,
+ IS_FILTER_ENABLED(IFF_PROMISC) ||
+ cfg->is_vlan_force_promisc);
- hw_atl_rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC));
hw_atl_rpfl2multicast_flr_en_set(self,
IS_FILTER_ENABLED(IFF_ALLMULTI), 0);
@@ -788,13 +795,13 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST));
- self->aq_nic_cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
+ cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i)
hw_atl_rpfl2_uc_flr_en_set(self,
- (self->aq_nic_cfg->is_mc_list_enabled &&
- (i <= self->aq_nic_cfg->mc_list_count)) ?
- 1U : 0U, i);
+ (cfg->is_mc_list_enabled &&
+ (i <= cfg->mc_list_count)) ?
+ 1U : 0U, i);
return aq_hw_err_from_flags(self);
}
@@ -1086,7 +1093,7 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self,
static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
{
/* set promisc in case of disabing the vland filter */
- hw_atl_rpf_vlan_prom_mode_en_set(self, !!!enable);
+ hw_atl_rpf_vlan_prom_mode_en_set(self, !enable);
return aq_hw_err_from_flags(self);
}
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 2375a13bb446..262a28ff81fc 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -4180,7 +4180,7 @@ static int macb_probe(struct platform_device *pdev)
if (PTR_ERR(mac) == -EPROBE_DEFER) {
err = -EPROBE_DEFER;
goto err_out_free_netdev;
- } else if (!IS_ERR(mac)) {
+ } else if (!IS_ERR_OR_NULL(mac)) {
ether_addr_copy(bp->dev->dev_addr, mac);
} else {
macb_get_hwaddr(bp);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 8a6785173228..492f8769ac12 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -891,7 +891,7 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- int status;
+ int status, cnt;
u8 link_status = 0;
if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
@@ -902,6 +902,9 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
+ /* check link status before offline tests */
+ link_status = netif_carrier_ok(netdev);
+
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)
test->flags |= ETH_TEST_FL_FAILED;
@@ -922,13 +925,26 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
test->flags |= ETH_TEST_FL_FAILED;
}
- status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
- if (status) {
- test->flags |= ETH_TEST_FL_FAILED;
- data[4] = -1;
- } else if (!link_status) {
+ /* link status was down prior to test */
+ if (!link_status) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = 1;
+ return;
+ }
+
+ for (cnt = 10; cnt; cnt--) {
+ status = be_cmd_link_status_query(adapter, NULL, &link_status,
+ 0);
+ if (status) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ data[4] = -1;
+ break;
+ }
+
+ if (link_status)
+ break;
+
+ msleep_interruptible(500);
}
}
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 67f9bb6e941b..9b036c857b1d 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -1057,7 +1057,7 @@ sis900_open(struct net_device *net_dev)
sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
sw32(cr, RxENA | sr32(cr));
sw32(ier, IE);
@@ -1578,7 +1578,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
sw32(txdp, sis_priv->tx_ring_dma);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
}
/**
@@ -1618,7 +1618,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
spin_unlock_irqrestore(&sis_priv->lock, flags);
return NETDEV_TX_OK;
}
- sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
+ sis_priv->tx_ring[entry].cmdsts = (OWN | INTR | skb->len);
sw32(cr, TxENA | sr32(cr));
sis_priv->cur_tx ++;
@@ -1674,7 +1674,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
do {
status = sr32(isr);
- if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
+ if ((status & (HIBERR|TxURN|TxERR|TxIDLE|TxDESC|RxORN|RxERR|RxOK)) == 0)
/* nothing intresting happened */
break;
handled = 1;
@@ -1684,7 +1684,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
/* Rx interrupt */
sis900_rx(net_dev);
- if (status & (TxURN | TxERR | TxIDLE))
+ if (status & (TxURN | TxERR | TxIDLE | TxDESC))
/* Tx interrupt */
sis900_finish_xmit(net_dev);
@@ -1896,8 +1896,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (tx_status & OWN) {
/* The packet is not transmitted yet (owned by hardware) !
- * Note: the interrupt is generated only when Tx Machine
- * is idle, so this is an almost impossible case */
+ * Note: this is an almost impossible condition
+ * in case of TxDESC ('descriptor interrupt') */
break;
}
@@ -2473,7 +2473,7 @@ static int sis900_resume(struct pci_dev *pci_dev)
sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
sw32(cr, RxENA | sr32(cr));
sw32(ier, IE);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index 2dcdf761d525..020159622559 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -112,7 +112,7 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
* programmed with (2^32 – <new_sec_value>)
*/
if (gmac4)
- sec = (100000000ULL - sec);
+ sec = -sec;
value = readl(ioaddr + PTP_TCR);
if (value & PTP_TCR_TSCTRLSSR)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 06dd51f47cfd..06358fe5b245 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2947,12 +2947,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
/* Manage tx mitigation */
tx_q->tx_count_frames += nfrags + 1;
- if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+ if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+ !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ stmmac_tx_timer_arm(priv, queue);
+ } else {
+ tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
priv->xstats.tx_set_ic_bit++;
- tx_q->tx_count_frames = 0;
- } else {
- stmmac_tx_timer_arm(priv, queue);
}
skb_tx_timestamp(skb);
@@ -3166,12 +3169,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
* element in case of no SG.
*/
tx_q->tx_count_frames += nfrags + 1;
- if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+ if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+ !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ stmmac_tx_timer_arm(priv, queue);
+ } else {
+ tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
priv->xstats.tx_set_ic_bit++;
- tx_q->tx_count_frames = 0;
- } else {
- stmmac_tx_timer_arm(priv, queue);
}
skb_tx_timestamp(skb);
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index ff61dd8748de..66c8e65f6872 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -63,6 +63,7 @@ MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");
MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_SOFTDEP("pre: arc4");
MODULE_VERSION("1.0.2");
static unsigned int
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index b48006e7fa2f..36916bf51ee6 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2128,12 +2128,12 @@ static void team_setup(struct net_device *dev)
dev->features |= NETIF_F_NETNS_LOCAL;
dev->hw_features = TEAM_VLAN_FEATURES |
- NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
dev->features |= dev->hw_features;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
}
static int team_newlink(struct net *src_net, struct net_device *dev,
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index d080f8048e52..8b4ad10cf940 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1482,7 +1482,7 @@ static int qmi_wwan_probe(struct usb_interface *intf,
* different. Ignore the current interface if the number of endpoints
* equals the number for the diag interface (two).
*/
- info = (void *)&id->driver_info;
+ info = (void *)id->driver_info;
if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) {
if (desc->bNumEndpoints == 2)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 11b9525dff27..311b0cc6eb98 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -350,8 +350,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
{
struct dst_entry *dst = skb_dst(skb);
struct net_device *dev = dst->dev;
+ const struct in6_addr *nexthop;
struct neighbour *neigh;
- struct in6_addr *nexthop;
int ret;
nf_reset(skb);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 98af9ecd4a90..ca3793002e2f 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -859,7 +859,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
pci_dev->bus->self->skip_bus_pm = true;
}
- if (pci_dev->skip_bus_pm && !pm_suspend_via_firmware()) {
+ if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) {
dev_dbg(dev, "PCI PM: Skipped\n");
goto Fixup;
}
@@ -914,10 +914,10 @@ static int pci_pm_resume_noirq(struct device *dev)
/*
* In the suspend-to-idle case, devices left in D0 during suspend will
* stay in D0, so it is not necessary to restore or update their
- * configuration here and attempting to put them into D0 again may
- * confuse some firmware, so avoid doing that.
+ * configuration here and attempting to put them into D0 again is
+ * pointless, so avoid doing that.
*/
- if (!pci_dev->skip_bus_pm || pm_suspend_via_firmware())
+ if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform()))
pci_pm_default_resume_early(pci_dev);
pci_fixup_device(pci_fixup_resume_early, pci_dev);
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index f464f8cd274b..7e526bcf5e0b 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -113,6 +113,8 @@ static void mtk_eint_mask(struct irq_data *d)
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_set);
+ eint->cur_mask[d->hwirq >> 5] &= ~mask;
+
writel(mask, reg);
}
@@ -123,6 +125,8 @@ static void mtk_eint_unmask(struct irq_data *d)
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_clr);
+ eint->cur_mask[d->hwirq >> 5] |= mask;
+
writel(mask, reg);
if (eint->dual_edge[d->hwirq])
@@ -217,19 +221,6 @@ static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
}
}
-static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
- void __iomem *base, u32 *buf)
-{
- int port;
- void __iomem *reg;
-
- for (port = 0; port < eint->hw->ports; port++) {
- reg = base + eint->regs->mask + (port << 2);
- buf[port] = ~readl_relaxed(reg);
- /* Mask is 0 when irq is enabled, and 1 when disabled. */
- }
-}
-
static int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -318,7 +309,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mtk_eint *eint = irq_desc_get_handler_data(desc);
unsigned int status, eint_num;
- int offset, index, virq;
+ int offset, mask_offset, index, virq;
void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
int dual_edge, start_level, curr_level;
@@ -328,10 +319,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
status = readl(reg);
while (status) {
offset = __ffs(status);
+ mask_offset = eint_num >> 5;
index = eint_num + offset;
virq = irq_find_mapping(eint->domain, index);
status &= ~BIT(offset);
+ /*
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
+ */
+ if (eint->wake_mask[mask_offset] & BIT(offset) &&
+ !(eint->cur_mask[mask_offset] & BIT(offset))) {
+ writel_relaxed(BIT(offset), reg -
+ eint->regs->stat +
+ eint->regs->mask_set);
+ }
+
dual_edge = eint->dual_edge[index];
if (dual_edge) {
/*
@@ -370,7 +375,6 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
return 0;
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 568ca96cdb6d..3a235487e38d 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -771,6 +771,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
if (ret < 0)
goto fail;
+ ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
+ if (ret < 0)
+ goto fail;
+
mcp->irq_controller =
device_property_read_bool(dev, "interrupt-controller");
if (mcp->irq && mcp->irq_controller) {
@@ -812,10 +816,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
goto fail;
}
- ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
- if (ret < 0)
- goto fail;
-
if (one_regmap_config) {
mcp->pinctrl_desc.name = devm_kasprintf(dev, GFP_KERNEL,
"mcp23xxx-pinctrl.%d", raw_chip_address);
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index 3b4ca52d2456..fb76fb2e9ea5 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -396,7 +396,7 @@ static int ocelot_pin_function_idx(struct ocelot_pinctrl *info,
return -1;
}
-#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+#define REG_ALT(msb, info, p) (OCELOT_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32))))
static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int selector, unsigned int group)
@@ -412,19 +412,21 @@ static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
/*
* f is encoded on two bits.
- * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of
- * ALT1
+ * bit 0 of f goes in BIT(pin) of ALT[0], bit 1 of f goes in BIT(pin) of
+ * ALT[1]
* This is racy because both registers can't be updated at the same time
* but it doesn't matter much for now.
*/
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, pin->pin),
+ regmap_update_bits(info->map, REG_ALT(0, info, pin->pin),
BIT(p), f << p);
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, pin->pin),
+ regmap_update_bits(info->map, REG_ALT(1, info, pin->pin),
BIT(p), f << (p - 1));
return 0;
}
+#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+
static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int pin, bool input)
@@ -432,7 +434,7 @@ static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
unsigned int p = pin % 32;
- regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, p), BIT(p),
+ regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, pin), BIT(p),
input ? 0 : BIT(p));
return 0;
@@ -445,9 +447,9 @@ static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev,
struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
unsigned int p = offset % 32;
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, offset),
+ regmap_update_bits(info->map, REG_ALT(0, info, offset),
BIT(p), 0);
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, offset),
+ regmap_update_bits(info->map, REG_ALT(1, info, offset),
BIT(p), 0);
return 0;
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index ecee4b3ff073..377b07b2feeb 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -763,6 +763,7 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
struct pvscsi_adapter *adapter = shost_priv(host);
struct pvscsi_ctx *ctx;
unsigned long flags;
+ unsigned char op;
spin_lock_irqsave(&adapter->hw_lock, flags);
@@ -775,13 +776,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
}
cmd->scsi_done = done;
+ op = cmd->cmnd[0];
dev_dbg(&cmd->device->sdev_gendev,
- "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+ "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op);
spin_unlock_irqrestore(&adapter->hw_lock, flags);
- pvscsi_kick_io(adapter, cmd->cmnd[0]);
+ pvscsi_kick_io(adapter, op);
return 0;
}
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index d441bef72163..915010464572 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -275,9 +275,9 @@ static void afs_break_one_callback(struct afs_server *server,
struct afs_super_info *as = AFS_FS_S(cbi->sb);
struct afs_volume *volume = as->volume;
- write_lock(&volume->cb_break_lock);
+ write_lock(&volume->cb_v_break_lock);
volume->cb_v_break++;
- write_unlock(&volume->cb_break_lock);
+ write_unlock(&volume->cb_v_break_lock);
} else {
data.volume = NULL;
data.fid = *fid;
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index b42d9d09669c..18a50d4febcf 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -56,6 +56,16 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren
}
/*
+ * Set the file size and block count. Estimate the number of 512 bytes blocks
+ * used, rounded up to nearest 1K for consistency with other AFS clients.
+ */
+static void afs_set_i_size(struct afs_vnode *vnode, u64 size)
+{
+ i_size_write(&vnode->vfs_inode, size);
+ vnode->vfs_inode.i_blocks = ((size + 1023) >> 10) << 1;
+}
+
+/*
* Initialise an inode from the vnode status.
*/
static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
@@ -124,12 +134,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type);
}
- /*
- * Estimate 512 bytes blocks used, rounded up to nearest 1K
- * for consistency with other AFS clients.
- */
- inode->i_blocks = ((i_size_read(inode) + 1023) >> 10) << 1;
- i_size_write(&vnode->vfs_inode, status->size);
+ afs_set_i_size(vnode, status->size);
vnode->invalid_before = status->data_version;
inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
@@ -207,11 +212,13 @@ static void afs_apply_status(struct afs_fs_cursor *fc,
if (expected_version &&
*expected_version != status->data_version) {
- kdebug("vnode modified %llx on {%llx:%llu} [exp %llx] %s",
- (unsigned long long) status->data_version,
- vnode->fid.vid, vnode->fid.vnode,
- (unsigned long long) *expected_version,
- fc->type ? fc->type->name : "???");
+ if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags))
+ pr_warn("kAFS: vnode modified {%llx:%llu} %llx->%llx %s\n",
+ vnode->fid.vid, vnode->fid.vnode,
+ (unsigned long long)*expected_version,
+ (unsigned long long)status->data_version,
+ fc->type ? fc->type->name : "???");
+
vnode->invalid_before = status->data_version;
if (vnode->status.type == AFS_FTYPE_DIR) {
if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
@@ -230,7 +237,7 @@ static void afs_apply_status(struct afs_fs_cursor *fc,
if (data_changed) {
inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
- i_size_write(&vnode->vfs_inode, status->size);
+ afs_set_i_size(vnode, status->size);
}
}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 8a67bf741880..7ee63526c6a2 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -109,10 +109,8 @@ struct afs_call {
struct rxrpc_call *rxcall; /* RxRPC call handle */
struct key *key; /* security for this call */
struct afs_net *net; /* The network namespace */
- union {
- struct afs_server *server;
- struct afs_vlserver *vlserver;
- };
+ struct afs_server *server; /* The fileserver record if fs op (pins ref) */
+ struct afs_vlserver *vlserver; /* The vlserver record if vl op */
struct afs_cb_interest *cbi; /* Callback interest for server used */
struct afs_vnode *lvnode; /* vnode being locked */
void *request; /* request data (first part) */
@@ -616,7 +614,7 @@ struct afs_volume {
unsigned int servers_seq; /* Incremented each time ->servers changes */
unsigned cb_v_break; /* Break-everything counter. */
- rwlock_t cb_break_lock;
+ rwlock_t cb_v_break_lock;
afs_voltype_t type; /* type of volume */
short error;
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 08fdb3951c49..1a414300b654 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -43,6 +43,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
atomic_set(&volume->usage, 1);
INIT_LIST_HEAD(&volume->proc_link);
rwlock_init(&volume->servers_lock);
+ rwlock_init(&volume->cb_v_break_lock);
memcpy(volume->name, vldb->name, vldb->name_len + 1);
slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask);
diff --git a/fs/aio.c b/fs/aio.c
index 3490d1fa0e16..c1e581dd32f5 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -2095,6 +2095,7 @@ SYSCALL_DEFINE6(io_pgetevents,
struct __aio_sigset ksig = { NULL, };
sigset_t ksigmask, sigsaved;
struct timespec64 ts;
+ bool interrupted;
int ret;
if (timeout && unlikely(get_timespec64(&ts, timeout)))
@@ -2108,8 +2109,10 @@ SYSCALL_DEFINE6(io_pgetevents,
return ret;
ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
- restore_user_sigmask(ksig.sigmask, &sigsaved);
- if (signal_pending(current) && !ret)
+
+ interrupted = signal_pending(current);
+ restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+ if (interrupted && !ret)
ret = -ERESTARTNOHAND;
return ret;
@@ -2128,6 +2131,7 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
struct __aio_sigset ksig = { NULL, };
sigset_t ksigmask, sigsaved;
struct timespec64 ts;
+ bool interrupted;
int ret;
if (timeout && unlikely(get_old_timespec32(&ts, timeout)))
@@ -2142,8 +2146,10 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
return ret;
ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
- restore_user_sigmask(ksig.sigmask, &sigsaved);
- if (signal_pending(current) && !ret)
+
+ interrupted = signal_pending(current);
+ restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+ if (interrupted && !ret)
ret = -ERESTARTNOHAND;
return ret;
@@ -2193,6 +2199,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
struct __compat_aio_sigset ksig = { NULL, };
sigset_t ksigmask, sigsaved;
struct timespec64 t;
+ bool interrupted;
int ret;
if (timeout && get_old_timespec32(&t, timeout))
@@ -2206,8 +2213,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
return ret;
ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
- restore_user_sigmask(ksig.sigmask, &sigsaved);
- if (signal_pending(current) && !ret)
+
+ interrupted = signal_pending(current);
+ restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+ if (interrupted && !ret)
ret = -ERESTARTNOHAND;
return ret;
@@ -2226,6 +2235,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
struct __compat_aio_sigset ksig = { NULL, };
sigset_t ksigmask, sigsaved;
struct timespec64 t;
+ bool interrupted;
int ret;
if (timeout && get_timespec64(&t, timeout))
@@ -2239,8 +2249,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
return ret;
ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
- restore_user_sigmask(ksig.sigmask, &sigsaved);
- if (signal_pending(current) && !ret)
+
+ interrupted = signal_pending(current);
+ restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+ if (interrupted && !ret)
ret = -ERESTARTNOHAND;
return ret;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 82a48e830018..e4b59e76afb0 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -856,9 +856,14 @@ err:
static int load_flat_shared_library(int id, struct lib_info *libs)
{
+ /*
+ * This is a fake bprm struct; only the members "buf", "file" and
+ * "filename" are actually used.
+ */
struct linux_binprm bprm;
int res;
char buf[16];
+ loff_t pos = 0;
memset(&bprm, 0, sizeof(bprm));
@@ -872,25 +877,11 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
if (IS_ERR(bprm.file))
return res;
- bprm.cred = prepare_exec_creds();
- res = -ENOMEM;
- if (!bprm.cred)
- goto out;
-
- /* We don't really care about recalculating credentials at this point
- * as we're past the point of no return and are dealing with shared
- * libraries.
- */
- bprm.called_set_creds = 1;
+ res = kernel_read(bprm.file, bprm.buf, BINPRM_BUF_SIZE, &pos);
- res = prepare_binprm(&bprm);
-
- if (!res)
+ if (res >= 0)
res = load_flat_file(&bprm, libs, id, NULL);
- abort_creds(bprm.cred);
-
-out:
allow_write_access(bprm.file);
fput(bprm.file);
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 6af2d0d4a87a..c8a9b89b922d 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2121,9 +2121,10 @@ retry:
if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
dout("build_path path+%d: %p SNAPDIR\n",
pos, temp);
- } else if (stop_on_nosnap && inode &&
+ } else if (stop_on_nosnap && inode && dentry != temp &&
ceph_snap(inode) == CEPH_NOSNAP) {
spin_unlock(&temp->d_lock);
+ pos++; /* get rid of any prepended '/' */
break;
} else {
pos -= temp->d_name.len;
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index c6f513100cc9..4c74c768ae43 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -2325,7 +2325,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
error = do_epoll_wait(epfd, events, maxevents, timeout);
- restore_user_sigmask(sigmask, &sigsaved);
+ restore_user_sigmask(sigmask, &sigsaved, error == -EINTR);
return error;
}
@@ -2350,7 +2350,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
err = do_epoll_wait(epfd, events, maxevents, timeout);
- restore_user_sigmask(sigmask, &sigsaved);
+ restore_user_sigmask(sigmask, &sigsaved, err == -EINTR);
return err;
}
diff --git a/fs/inode.c b/fs/inode.c
index df6542ec3b88..2bf21e2c90fc 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -362,7 +362,7 @@ EXPORT_SYMBOL(inc_nlink);
static void __address_space_init_once(struct address_space *mapping)
{
- xa_init_flags(&mapping->i_pages, XA_FLAGS_LOCK_IRQ);
+ xa_init_flags(&mapping->i_pages, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ACCOUNT);
init_rwsem(&mapping->i_mmap_rwsem);
INIT_LIST_HEAD(&mapping->private_list);
spin_lock_init(&mapping->private_lock);
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 86a2bd721900..4ef62a45045d 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -579,6 +579,7 @@ static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
state->cur_req++;
}
+ req->file = NULL;
req->ctx = ctx;
req->flags = 0;
/* one is dropped after submission, the other at completion */
@@ -1801,10 +1802,8 @@ static int io_req_set_file(struct io_ring_ctx *ctx, const struct sqe_submit *s,
req->sequence = ctx->cached_sq_head - 1;
}
- if (!io_op_needs_file(s->sqe)) {
- req->file = NULL;
+ if (!io_op_needs_file(s->sqe))
return 0;
- }
if (flags & IOSQE_FIXED_FILE) {
if (unlikely(!ctx->user_files ||
@@ -2201,11 +2200,12 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
}
ret = wait_event_interruptible(ctx->wait, io_cqring_events(ring) >= min_events);
- if (ret == -ERESTARTSYS)
- ret = -EINTR;
if (sig)
- restore_user_sigmask(sig, &sigsaved);
+ restore_user_sigmask(sig, &sigsaved, ret == -ERESTARTSYS);
+
+ if (ret == -ERESTARTSYS)
+ ret = -EINTR;
return READ_ONCE(ring->r.head) == READ_ONCE(ring->r.tail) ? ret : 0;
}
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index a809989807d6..19f856f45689 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -18,7 +18,7 @@
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
-static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS;
+static unsigned int dataserver_timeo = NFS_DEF_TCP_TIMEO;
static unsigned int dataserver_retrans;
static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 2edbb657f859..55180501b915 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -462,7 +462,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
* a program is not able to use ptrace(2) in that case. It is
* safe because the task has stopped executing permanently.
*/
- if (permitted && (task->flags & PF_DUMPCORE)) {
+ if (permitted && (task->flags & (PF_EXITING|PF_DUMPCORE))) {
if (try_get_task_stack(task)) {
eip = KSTK_EIP(task);
esp = KSTK_ESP(task);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 9c8ca6cd3ce4..255f6754c70d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3077,8 +3077,7 @@ static const struct file_operations proc_tgid_base_operations = {
struct pid *tgid_pidfd_to_pid(const struct file *file)
{
- if (!d_is_dir(file->f_path.dentry) ||
- (file->f_op != &proc_tgid_base_operations))
+ if (file->f_op != &proc_tgid_base_operations)
return ERR_PTR(-EBADF);
return proc_pid(file_inode(file));
diff --git a/fs/select.c b/fs/select.c
index 6cbc9ff56ba0..a4d8f6e8b63c 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -758,10 +758,9 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
return ret;
ret = core_sys_select(n, inp, outp, exp, to);
+ restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
- restore_user_sigmask(sigmask, &sigsaved);
-
return ret;
}
@@ -1106,8 +1105,7 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
ret = do_sys_poll(ufds, nfds, to);
- restore_user_sigmask(sigmask, &sigsaved);
-
+ restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
/* We can restart this syscall, usually */
if (ret == -EINTR)
ret = -ERESTARTNOHAND;
@@ -1142,8 +1140,7 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds,
ret = do_sys_poll(ufds, nfds, to);
- restore_user_sigmask(sigmask, &sigsaved);
-
+ restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
/* We can restart this syscall, usually */
if (ret == -EINTR)
ret = -ERESTARTNOHAND;
@@ -1350,10 +1347,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
return ret;
ret = compat_core_sys_select(n, inp, outp, exp, to);
+ restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
- restore_user_sigmask(sigmask, &sigsaved);
-
return ret;
}
@@ -1425,8 +1421,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds,
ret = do_sys_poll(ufds, nfds, to);
- restore_user_sigmask(sigmask, &sigsaved);
-
+ restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
/* We can restart this syscall, usually */
if (ret == -EINTR)
ret = -ERESTARTNOHAND;
@@ -1461,8 +1456,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds,
ret = do_sys_poll(ufds, nfds, to);
- restore_user_sigmask(sigmask, &sigsaved);
-
+ restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
/* We can restart this syscall, usually */
if (ret == -EINTR)
ret = -ERESTARTNOHAND;
diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h
index 82c9e0c020b2..e10470ed7c4f 100644
--- a/include/dt-bindings/clock/g12a-clkc.h
+++ b/include/dt-bindings/clock/g12a-clkc.h
@@ -130,7 +130,7 @@
#define CLKID_MALI_1_SEL 172
#define CLKID_MALI_1 174
#define CLKID_MALI 175
-#define CLKID_MPLL_5OM 177
+#define CLKID_MPLL_50M 177
#define CLKID_CPU_CLK 187
#define CLKID_PCIE_PLL 201
#define CLKID_VDEC_1 204
diff --git a/include/dt-bindings/clock/sifive-fu540-prci.h b/include/dt-bindings/clock/sifive-fu540-prci.h
index 6a0b70a37d78..3b21d0522c91 100644
--- a/include/dt-bindings/clock/sifive-fu540-prci.h
+++ b/include/dt-bindings/clock/sifive-fu540-prci.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (C) 2018-2019 SiFive, Inc.
* Wesley Terpstra
diff --git a/include/linux/intel-ish-client-if.h b/include/linux/intel-ish-client-if.h
index 16255c2ca2f4..0d6b4bc191c5 100644
--- a/include/linux/intel-ish-client-if.h
+++ b/include/linux/intel-ish-client-if.h
@@ -103,6 +103,7 @@ void ishtp_put_device(struct ishtp_cl_device *cl_dev);
void ishtp_get_device(struct ishtp_cl_device *cl_dev);
void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data);
void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device);
+struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *dev);
int ishtp_register_event_cb(struct ishtp_cl_device *device,
void (*read_cb)(struct ishtp_cl_device *));
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 74b1ee9027f5..0c9bc231107f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -93,7 +93,8 @@
#define DIV_ROUND_DOWN_ULL(ll, d) \
({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
-#define DIV_ROUND_UP_ULL(ll, d) DIV_ROUND_DOWN_ULL((ll) + (d) - 1, (d))
+#define DIV_ROUND_UP_ULL(ll, d) \
+ DIV_ROUND_DOWN_ULL((unsigned long long)(ll) + (d) - 1, (d))
#if BITS_PER_LONG == 32
# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d)
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index b3d360b0ee3d..9f57cdfcc93d 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -373,6 +373,8 @@ struct flash_info;
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
* @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
+ * the SPI NOR Status Register.
* completely locked
* @priv: the private data
*/
@@ -410,6 +412,7 @@ struct spi_nor {
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
+ int (*clear_sr_bp)(struct spi_nor *nor);
void *priv;
};
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0ab99c7b652d..2bca72f3028b 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -241,6 +241,7 @@ struct perf_event;
#define PERF_PMU_CAP_NO_INTERRUPT 0x01
#define PERF_PMU_CAP_NO_NMI 0x02
#define PERF_PMU_CAP_AUX_NO_SG 0x04
+#define PERF_PMU_CAP_EXTENDED_REGS 0x08
#define PERF_PMU_CAP_EXCLUSIVE 0x10
#define PERF_PMU_CAP_ITRACE 0x20
#define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40
diff --git a/include/linux/perf_regs.h b/include/linux/perf_regs.h
index 476747456bca..2d12e97d5e7b 100644
--- a/include/linux/perf_regs.h
+++ b/include/linux/perf_regs.h
@@ -11,6 +11,11 @@ struct perf_regs {
#ifdef CONFIG_HAVE_PERF_REGS
#include <asm/perf_regs.h>
+
+#ifndef PERF_REG_EXTENDED_MASK
+#define PERF_REG_EXTENDED_MASK 0
+#endif
+
u64 perf_reg_value(struct pt_regs *regs, int idx);
int perf_reg_validate(u64 mask);
u64 perf_reg_abi(struct task_struct *task);
@@ -18,6 +23,9 @@ void perf_get_regs_user(struct perf_regs *regs_user,
struct pt_regs *regs,
struct pt_regs *regs_user_copy);
#else
+
+#define PERF_REG_EXTENDED_MASK 0
+
static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
{
return 0;
diff --git a/include/linux/pfn_t.h b/include/linux/pfn_t.h
index 7bb77850c65a..3c202a11a79e 100644
--- a/include/linux/pfn_t.h
+++ b/include/linux/pfn_t.h
@@ -68,7 +68,7 @@ static inline phys_addr_t pfn_t_to_phys(pfn_t pfn)
static inline void *pfn_t_to_virt(pfn_t pfn)
{
- if (pfn_t_has_page(pfn))
+ if (pfn_t_has_page(pfn) && !is_device_private_page(pfn_t_to_page(pfn)))
return __va(pfn_t_to_phys(pfn));
return NULL;
}
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 9702016734b1..78c2bb376954 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -276,7 +276,7 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);
extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
sigset_t *oldset, size_t sigsetsize);
extern void restore_user_sigmask(const void __user *usigmask,
- sigset_t *sigsaved);
+ sigset_t *sigsaved, bool interrupted);
extern void set_current_blocked(sigset_t *);
extern void __set_current_blocked(const sigset_t *);
extern int show_unhandled_signals;
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 8594001e8be8..f0d262ad7b78 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -209,8 +209,9 @@ extern int suspend_valid_only_mem(suspend_state_t state);
extern unsigned int pm_suspend_global_flags;
-#define PM_SUSPEND_FLAG_FW_SUSPEND (1 << 0)
-#define PM_SUSPEND_FLAG_FW_RESUME (1 << 1)
+#define PM_SUSPEND_FLAG_FW_SUSPEND BIT(0)
+#define PM_SUSPEND_FLAG_FW_RESUME BIT(1)
+#define PM_SUSPEND_FLAG_NO_PLATFORM BIT(2)
static inline void pm_suspend_clear_flags(void)
{
@@ -227,6 +228,11 @@ static inline void pm_set_resume_via_firmware(void)
pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
}
+static inline void pm_set_suspend_no_platform(void)
+{
+ pm_suspend_global_flags |= PM_SUSPEND_FLAG_NO_PLATFORM;
+}
+
/**
* pm_suspend_via_firmware - Check if platform firmware will suspend the system.
*
@@ -268,6 +274,22 @@ static inline bool pm_resume_via_firmware(void)
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
}
+/**
+ * pm_suspend_no_platform - Check if platform may change device power states.
+ *
+ * To be called during system-wide power management transitions to sleep states
+ * or during the subsequent system-wide transitions back to the working state.
+ *
+ * Return 'true' if the power states of devices remain under full control of the
+ * kernel throughout the system-wide suspend and resume cycle in progress (that
+ * is, if a device is put into a certain power state during suspend, it can be
+ * expected to remain in that state during resume).
+ */
+static inline bool pm_suspend_no_platform(void)
+{
+ return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_NO_PLATFORM);
+}
+
/* Suspend-to-idle state machnine. */
enum s2idle_states {
S2IDLE_STATE_NONE, /* Not suspended/suspending. */
diff --git a/include/linux/xarray.h b/include/linux/xarray.h
index 0e01e6129145..5921599b6dc4 100644
--- a/include/linux/xarray.h
+++ b/include/linux/xarray.h
@@ -265,6 +265,7 @@ enum xa_lock_type {
#define XA_FLAGS_TRACK_FREE ((__force gfp_t)4U)
#define XA_FLAGS_ZERO_BUSY ((__force gfp_t)8U)
#define XA_FLAGS_ALLOC_WRAPPED ((__force gfp_t)16U)
+#define XA_FLAGS_ACCOUNT ((__force gfp_t)32U)
#define XA_FLAGS_MARK(mark) ((__force gfp_t)((1U << __GFP_BITS_SHIFT) << \
(__force unsigned)(mark)))
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 4790beaa86e0..ee7405e759ba 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -262,8 +262,8 @@ static inline bool ip6_sk_ignore_df(const struct sock *sk)
inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;
}
-static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt,
- struct in6_addr *daddr)
+static inline const struct in6_addr *rt6_nexthop(const struct rt6_info *rt,
+ const struct in6_addr *daddr)
{
if (rt->rt6i_flags & RTF_GATEWAY)
return &rt->rt6i_gateway;
diff --git a/include/net/route.h b/include/net/route.h
index 065b47754f05..55ff71ffb796 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -221,6 +221,7 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
struct rtable *rt_dst_alloc(struct net_device *dev,
unsigned int flags, u16 type,
bool nopolicy, bool noxfrm, bool will_cache);
+struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
struct in_ifaddr;
void fib_add_ifaddr(struct in_ifaddr *);
diff --git a/include/net/tls.h b/include/net/tls.h
index 4a55ce6a303f..53d96bca220d 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -373,21 +373,6 @@ static inline bool tls_is_partially_sent_record(struct tls_context *ctx)
return !!ctx->partially_sent_record;
}
-static inline int tls_complete_pending_work(struct sock *sk,
- struct tls_context *ctx,
- int flags, long *timeo)
-{
- int rc = 0;
-
- if (unlikely(sk->sk_write_pending))
- rc = wait_on_pending_writer(sk, timeo);
-
- if (!rc && tls_is_partially_sent_record(ctx))
- rc = tls_push_partial_record(sk, ctx, flags);
-
- return rc;
-}
-
static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx)
{
return tls_ctx->pending_open_record_frags;
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index c5188ff724d1..bc88d6f964da 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -173,10 +173,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
if (snd_BUG_ON(!stream))
return;
- if (stream->direction == SND_COMPRESS_PLAYBACK)
- stream->runtime->state = SNDRV_PCM_STATE_SETUP;
- else
- stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
wake_up(&stream->runtime->sleep);
}
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
index c4299da22f93..871993696c5f 100644
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -252,6 +252,8 @@ struct hda_codec {
unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
unsigned int force_pin_prefix:1; /* Add location prefix */
unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
+ unsigned int relaxed_resume:1; /* don't resume forcibly for jack */
+
#ifdef CONFIG_PM
unsigned long power_on_acct;
unsigned long power_off_acct;
@@ -271,9 +273,6 @@ struct hda_codec {
unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */
struct delayed_work jackpoll_work;
- /* jack detection */
- struct snd_array jacks;
-
int depop_delay; /* depop delay in ms, -1 for default delay time */
/* fix-up list */
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index e8346784cf3f..612a17e375d0 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -120,7 +120,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec);
int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name);
int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size);
-int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs);
+int snd_hdac_refresh_widgets(struct hdac_device *codec);
unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int parm);
@@ -358,6 +358,9 @@ struct hdac_bus {
bool align_bdle_4k:1; /* BDLE align 4K boundary */
bool reverse_assign:1; /* assign devices in reverse order */
bool corbrp_self_clear:1; /* CORBRP clears itself after reset */
+ bool polling_mode:1;
+
+ int poll_count;
int bdl_pos_adj; /* BDL position adjustment */
diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
index ddc5396800aa..76b7c3f6cd0d 100644
--- a/include/uapi/linux/usb/audio.h
+++ b/include/uapi/linux/usb/audio.h
@@ -450,6 +450,43 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc
}
}
+/*
+ * Extension Unit (XU) has almost compatible layout with Processing Unit, but
+ * on UAC2, it has a different bmControls size (bControlSize); it's 1 byte for
+ * XU while 2 bytes for PU. The last iExtension field is a one-byte index as
+ * well as iProcessing field of PU.
+ */
+static inline __u8 uac_extension_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
+ int protocol)
+{
+ switch (protocol) {
+ case UAC_VERSION_1:
+ return desc->baSourceID[desc->bNrInPins + 4];
+ case UAC_VERSION_2:
+ return 1; /* in UAC2, this value is constant */
+ case UAC_VERSION_3:
+ return 4; /* in UAC3, this value is constant */
+ default:
+ return 1;
+ }
+}
+
+static inline __u8 uac_extension_unit_iExtension(struct uac_processing_unit_descriptor *desc,
+ int protocol)
+{
+ __u8 control_size = uac_extension_unit_bControlSize(desc, protocol);
+
+ switch (protocol) {
+ case UAC_VERSION_1:
+ case UAC_VERSION_2:
+ default:
+ return *(uac_processing_unit_bmControls(desc, protocol)
+ + control_size);
+ case UAC_VERSION_3:
+ return 0; /* UAC3 does not have this field */
+ }
+}
+
/* 4.5.2 Class-Specific AS Interface Descriptor */
struct uac1_as_header_descriptor {
__u8 bLength; /* in bytes: 7 */
diff --git a/init/initramfs.c b/init/initramfs.c
index 178130fd61c2..c47dad0884f7 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -617,7 +617,7 @@ static inline void clean_rootfs(void)
#endif /* CONFIG_BLK_DEV_RAM */
#ifdef CONFIG_BLK_DEV_RAM
-static void populate_initrd_image(char *err)
+static void __init populate_initrd_image(char *err)
{
ssize_t written;
int fd;
@@ -637,7 +637,7 @@ static void populate_initrd_image(char *err)
ksys_close(fd);
}
#else
-static void populate_initrd_image(char *err)
+static void __init populate_initrd_image(char *err)
{
printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
}
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 077fde6fb953..ef1c565edc5d 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1964,6 +1964,9 @@ static ssize_t write_cpuhp_fail(struct device *dev,
if (ret)
return ret;
+ if (fail < CPUHP_OFFLINE || fail > CPUHP_ONLINE)
+ return -EINVAL;
+
/*
* Cannot fail STARTING/DYING callbacks.
*/
@@ -2339,6 +2342,9 @@ static int __init mitigations_parse_cmdline(char *arg)
cpu_mitigations = CPU_MITIGATIONS_AUTO;
else if (!strcmp(arg, "auto,nosmt"))
cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT;
+ else
+ pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n",
+ arg);
return 0;
}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index abbd4b3b96c2..f85929ce13be 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5005,6 +5005,9 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
if (perf_event_check_period(event, value))
return -EINVAL;
+ if (!event->attr.freq && (value & (1ULL << 63)))
+ return -EINVAL;
+
event_function_call(event, __perf_event_period, &value);
return 0;
@@ -5923,7 +5926,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
if (user_mode(regs)) {
regs_user->abi = perf_reg_abi(current);
regs_user->regs = regs;
- } else if (current->mm) {
+ } else if (!(current->flags & PF_KTHREAD)) {
perf_get_regs_user(regs_user, regs, regs_user_copy);
} else {
regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
@@ -10033,6 +10036,12 @@ void perf_pmu_unregister(struct pmu *pmu)
}
EXPORT_SYMBOL_GPL(perf_pmu_unregister);
+static inline bool has_extended_regs(struct perf_event *event)
+{
+ return (event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK) ||
+ (event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK);
+}
+
static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
{
struct perf_event_context *ctx = NULL;
@@ -10064,12 +10073,16 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
perf_event_ctx_unlock(event->group_leader, ctx);
if (!ret) {
+ if (!(pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS) &&
+ has_extended_regs(event))
+ ret = -EOPNOTSUPP;
+
if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
- event_has_any_exclude_flag(event)) {
- if (event->destroy)
- event->destroy(event);
+ event_has_any_exclude_flag(event))
ret = -EINVAL;
- }
+
+ if (ret && event->destroy)
+ event->destroy(event);
}
if (ret)
diff --git a/kernel/fork.c b/kernel/fork.c
index 75675b9bf6df..61667909ce83 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -248,7 +248,11 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
struct page *page = alloc_pages_node(node, THREADINFO_GFP,
THREAD_SIZE_ORDER);
- return page ? page_address(page) : NULL;
+ if (likely(page)) {
+ tsk->stack = page_address(page);
+ return tsk->stack;
+ }
+ return NULL;
#endif
}
@@ -1712,31 +1716,6 @@ const struct file_operations pidfd_fops = {
#endif
};
-/**
- * pidfd_create() - Create a new pid file descriptor.
- *
- * @pid: struct pid that the pidfd will reference
- *
- * This creates a new pid file descriptor with the O_CLOEXEC flag set.
- *
- * Note, that this function can only be called after the fd table has
- * been unshared to avoid leaking the pidfd to the new process.
- *
- * Return: On success, a cloexec pidfd is returned.
- * On error, a negative errno number will be returned.
- */
-static int pidfd_create(struct pid *pid)
-{
- int fd;
-
- fd = anon_inode_getfd("[pidfd]", &pidfd_fops, get_pid(pid),
- O_RDWR | O_CLOEXEC);
- if (fd < 0)
- put_pid(pid);
-
- return fd;
-}
-
static void __delayed_free_task(struct rcu_head *rhp)
{
struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
@@ -1774,6 +1753,7 @@ static __latent_entropy struct task_struct *copy_process(
int pidfd = -1, retval;
struct task_struct *p;
struct multiprocess_signals delayed;
+ struct file *pidfile = NULL;
/*
* Don't allow sharing the root directory with processes in a different
@@ -1822,8 +1802,6 @@ static __latent_entropy struct task_struct *copy_process(
}
if (clone_flags & CLONE_PIDFD) {
- int reserved;
-
/*
* - CLONE_PARENT_SETTID is useless for pidfds and also
* parent_tidptr is used to return pidfds.
@@ -1834,16 +1812,6 @@ static __latent_entropy struct task_struct *copy_process(
if (clone_flags &
(CLONE_DETACHED | CLONE_PARENT_SETTID | CLONE_THREAD))
return ERR_PTR(-EINVAL);
-
- /*
- * Verify that parent_tidptr is sane so we can potentially
- * reuse it later.
- */
- if (get_user(reserved, parent_tidptr))
- return ERR_PTR(-EFAULT);
-
- if (reserved != 0)
- return ERR_PTR(-EINVAL);
}
/*
@@ -2058,11 +2026,20 @@ static __latent_entropy struct task_struct *copy_process(
* if the fd table isn't shared).
*/
if (clone_flags & CLONE_PIDFD) {
- retval = pidfd_create(pid);
+ retval = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
if (retval < 0)
goto bad_fork_free_pid;
pidfd = retval;
+
+ pidfile = anon_inode_getfile("[pidfd]", &pidfd_fops, pid,
+ O_RDWR | O_CLOEXEC);
+ if (IS_ERR(pidfile)) {
+ put_unused_fd(pidfd);
+ goto bad_fork_free_pid;
+ }
+ get_pid(pid); /* held by pidfile now */
+
retval = put_user(pidfd, parent_tidptr);
if (retval)
goto bad_fork_put_pidfd;
@@ -2180,6 +2157,9 @@ static __latent_entropy struct task_struct *copy_process(
goto bad_fork_cancel_cgroup;
}
+ /* past the last point of failure */
+ if (pidfile)
+ fd_install(pidfd, pidfile);
init_task_pid_links(p);
if (likely(p->pid)) {
@@ -2246,8 +2226,10 @@ bad_fork_cancel_cgroup:
bad_fork_cgroup_threadgroup_change_end:
cgroup_threadgroup_change_end(current);
bad_fork_put_pidfd:
- if (clone_flags & CLONE_PIDFD)
- ksys_close(pidfd);
+ if (clone_flags & CLONE_PIDFD) {
+ fput(pidfile);
+ put_unused_fd(pidfd);
+ }
bad_fork_free_pid:
if (pid != &init_struct_pid)
free_pid(pid);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 9505101ed2bc..096211299c07 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -493,6 +493,9 @@ int suspend_devices_and_enter(suspend_state_t state)
pm_suspend_target_state = state;
+ if (state == PM_SUSPEND_TO_IDLE)
+ pm_set_suspend_no_platform();
+
error = platform_suspend_begin(state);
if (error)
goto Close;
diff --git a/kernel/signal.c b/kernel/signal.c
index d622eac9d169..edf8915ddd54 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2912,7 +2912,8 @@ EXPORT_SYMBOL(set_compat_user_sigmask);
* This is useful for syscalls such as ppoll, pselect, io_pgetevents and
* epoll_pwait where a new sigmask is passed in from userland for the syscalls.
*/
-void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
+void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved,
+ bool interrupted)
{
if (!usigmask)
@@ -2922,7 +2923,7 @@ void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
* Restoring sigmask here can lead to delivering signals that the above
* syscalls are intended to block because of the sigmask passed in.
*/
- if (signal_pending(current)) {
+ if (interrupted) {
current->saved_sigmask = *sigsaved;
set_restore_sigmask();
return;
diff --git a/lib/idr.c b/lib/idr.c
index c34e256d2f01..66a374892482 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -228,11 +228,21 @@ void *idr_get_next(struct idr *idr, int *nextid)
{
struct radix_tree_iter iter;
void __rcu **slot;
+ void *entry = NULL;
unsigned long base = idr->idr_base;
unsigned long id = *nextid;
id = (id < base) ? 0 : id - base;
- slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
+ radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, id) {
+ entry = rcu_dereference_raw(*slot);
+ if (!entry)
+ continue;
+ if (!xa_is_internal(entry))
+ break;
+ if (slot != &idr->idr_rt.xa_head && !xa_is_retry(entry))
+ break;
+ slot = radix_tree_iter_retry(&iter);
+ }
if (!slot)
return NULL;
id = iter.index + base;
@@ -241,7 +251,7 @@ void *idr_get_next(struct idr *idr, int *nextid)
return NULL;
*nextid = id;
- return rcu_dereference_raw(*slot);
+ return entry;
}
EXPORT_SYMBOL(idr_get_next);
diff --git a/lib/test_xarray.c b/lib/test_xarray.c
index 5d4bad8bd96a..9d631a7b6a70 100644
--- a/lib/test_xarray.c
+++ b/lib/test_xarray.c
@@ -38,6 +38,12 @@ static void *xa_store_index(struct xarray *xa, unsigned long index, gfp_t gfp)
return xa_store(xa, index, xa_mk_index(index), gfp);
}
+static void xa_insert_index(struct xarray *xa, unsigned long index)
+{
+ XA_BUG_ON(xa, xa_insert(xa, index, xa_mk_index(index),
+ GFP_KERNEL) != 0);
+}
+
static void xa_alloc_index(struct xarray *xa, unsigned long index, gfp_t gfp)
{
u32 id;
@@ -338,6 +344,37 @@ static noinline void check_xa_shrink(struct xarray *xa)
}
}
+static noinline void check_insert(struct xarray *xa)
+{
+ unsigned long i;
+
+ for (i = 0; i < 1024; i++) {
+ xa_insert_index(xa, i);
+ XA_BUG_ON(xa, xa_load(xa, i - 1) != NULL);
+ XA_BUG_ON(xa, xa_load(xa, i + 1) != NULL);
+ xa_erase_index(xa, i);
+ }
+
+ for (i = 10; i < BITS_PER_LONG; i++) {
+ xa_insert_index(xa, 1UL << i);
+ XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 1) != NULL);
+ XA_BUG_ON(xa, xa_load(xa, (1UL << i) + 1) != NULL);
+ xa_erase_index(xa, 1UL << i);
+
+ xa_insert_index(xa, (1UL << i) - 1);
+ XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 2) != NULL);
+ XA_BUG_ON(xa, xa_load(xa, 1UL << i) != NULL);
+ xa_erase_index(xa, (1UL << i) - 1);
+ }
+
+ xa_insert_index(xa, ~0UL);
+ XA_BUG_ON(xa, xa_load(xa, 0UL) != NULL);
+ XA_BUG_ON(xa, xa_load(xa, ~1UL) != NULL);
+ xa_erase_index(xa, ~0UL);
+
+ XA_BUG_ON(xa, !xa_empty(xa));
+}
+
static noinline void check_cmpxchg(struct xarray *xa)
{
void *FIVE = xa_mk_value(5);
@@ -1527,6 +1564,7 @@ static int xarray_checks(void)
check_xa_mark(&array);
check_xa_shrink(&array);
check_xas_erase(&array);
+ check_insert(&array);
check_cmpxchg(&array);
check_reserve(&array);
check_reserve(&xa0);
diff --git a/lib/xarray.c b/lib/xarray.c
index 6be3acbb861f..446b956c9188 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -298,6 +298,8 @@ bool xas_nomem(struct xa_state *xas, gfp_t gfp)
xas_destroy(xas);
return false;
}
+ if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+ gfp |= __GFP_ACCOUNT;
xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp);
if (!xas->xa_alloc)
return false;
@@ -325,6 +327,8 @@ static bool __xas_nomem(struct xa_state *xas, gfp_t gfp)
xas_destroy(xas);
return false;
}
+ if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+ gfp |= __GFP_ACCOUNT;
if (gfpflags_allow_blocking(gfp)) {
xas_unlock_type(xas, lock_type);
xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp);
@@ -358,8 +362,12 @@ static void *xas_alloc(struct xa_state *xas, unsigned int shift)
if (node) {
xas->xa_alloc = NULL;
} else {
- node = kmem_cache_alloc(radix_tree_node_cachep,
- GFP_NOWAIT | __GFP_NOWARN);
+ gfp_t gfp = GFP_NOWAIT | __GFP_NOWARN;
+
+ if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+ gfp |= __GFP_ACCOUNT;
+
+ node = kmem_cache_alloc(radix_tree_node_cachep, gfp);
if (!node) {
xas_set_err(xas, -ENOMEM);
return NULL;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ac843d32b019..ede7e7f5d1ab 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1510,16 +1510,29 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
/*
* Dissolve a given free hugepage into free buddy pages. This function does
- * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the
- * dissolution fails because a give page is not a free hugepage, or because
- * free hugepages are fully reserved.
+ * nothing for in-use hugepages and non-hugepages.
+ * This function returns values like below:
+ *
+ * -EBUSY: failed to dissolved free hugepages or the hugepage is in-use
+ * (allocated or reserved.)
+ * 0: successfully dissolved free hugepages or the page is not a
+ * hugepage (considered as already dissolved)
*/
int dissolve_free_huge_page(struct page *page)
{
int rc = -EBUSY;
+ /* Not to disrupt normal path by vainly holding hugetlb_lock */
+ if (!PageHuge(page))
+ return 0;
+
spin_lock(&hugetlb_lock);
- if (PageHuge(page) && !page_count(page)) {
+ if (!PageHuge(page)) {
+ rc = 0;
+ goto out;
+ }
+
+ if (!page_count(page)) {
struct page *head = compound_head(page);
struct hstate *h = page_hstate(head);
int nid = page_to_nid(head);
@@ -1564,11 +1577,9 @@ int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order) {
page = pfn_to_page(pfn);
- if (PageHuge(page) && !page_count(page)) {
- rc = dissolve_free_huge_page(page);
- if (rc)
- break;
- }
+ rc = dissolve_free_huge_page(page);
+ if (rc)
+ break;
}
return rc;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8da0334b9ca0..d9cc6606f409 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1730,6 +1730,8 @@ static int soft_offline_huge_page(struct page *page, int flags)
if (!ret) {
if (set_hwpoison_free_buddy_page(page))
num_poisoned_pages_inc();
+ else
+ ret = -EBUSY;
}
}
return ret;
@@ -1854,11 +1856,8 @@ static int soft_offline_in_use_page(struct page *page, int flags)
static int soft_offline_free_page(struct page *page)
{
- int rc = 0;
- struct page *head = compound_head(page);
+ int rc = dissolve_free_huge_page(page);
- if (PageHuge(head))
- rc = dissolve_free_huge_page(page);
if (!rc) {
if (set_hwpoison_free_buddy_page(page))
num_poisoned_pages_inc();
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 01600d80ae01..fdcb73536319 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -306,7 +306,7 @@ static void mpol_rebind_nodemask(struct mempolicy *pol, const nodemask_t *nodes)
else {
nodes_remap(tmp, pol->v.nodes,pol->w.cpuset_mems_allowed,
*nodes);
- pol->w.cpuset_mems_allowed = tmp;
+ pol->w.cpuset_mems_allowed = *nodes;
}
if (nodes_empty(tmp))
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 5a58778c91d4..f719b64741d6 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -987,8 +987,7 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
/*
* Determines whether the kernel must panic because of the panic_on_oom sysctl.
*/
-static void check_panic_on_oom(struct oom_control *oc,
- enum oom_constraint constraint)
+static void check_panic_on_oom(struct oom_control *oc)
{
if (likely(!sysctl_panic_on_oom))
return;
@@ -998,7 +997,7 @@ static void check_panic_on_oom(struct oom_control *oc,
* does not panic for cpuset, mempolicy, or memcg allocation
* failures.
*/
- if (constraint != CONSTRAINT_NONE)
+ if (oc->constraint != CONSTRAINT_NONE)
return;
}
/* Do not panic for oom kills triggered by sysrq */
@@ -1035,7 +1034,6 @@ EXPORT_SYMBOL_GPL(unregister_oom_notifier);
bool out_of_memory(struct oom_control *oc)
{
unsigned long freed = 0;
- enum oom_constraint constraint = CONSTRAINT_NONE;
if (oom_killer_disabled)
return false;
@@ -1071,10 +1069,10 @@ bool out_of_memory(struct oom_control *oc)
* Check if there were limitations on the allocation (only relevant for
* NUMA and memcg) that may require different handling.
*/
- constraint = constrained_alloc(oc);
- if (constraint != CONSTRAINT_MEMORY_POLICY)
+ oc->constraint = constrained_alloc(oc);
+ if (oc->constraint != CONSTRAINT_MEMORY_POLICY)
oc->nodemask = NULL;
- check_panic_on_oom(oc, constraint);
+ check_panic_on_oom(oc);
if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task &&
current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) &&
diff --git a/mm/page_idle.c b/mm/page_idle.c
index 0b39ec0c945c..295512465065 100644
--- a/mm/page_idle.c
+++ b/mm/page_idle.c
@@ -136,7 +136,7 @@ static ssize_t page_idle_bitmap_read(struct file *file, struct kobject *kobj,
end_pfn = pfn + count * BITS_PER_BYTE;
if (end_pfn > max_pfn)
- end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+ end_pfn = max_pfn;
for (; pfn < end_pfn; pfn++) {
bit = pfn % BITMAP_CHUNK_BITS;
@@ -181,7 +181,7 @@ static ssize_t page_idle_bitmap_write(struct file *file, struct kobject *kobj,
end_pfn = pfn + count * BITS_PER_BYTE;
if (end_pfn > max_pfn)
- end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+ end_pfn = max_pfn;
for (; pfn < end_pfn; pfn++) {
bit = pfn % BITMAP_CHUNK_BITS;
diff --git a/mm/page_io.c b/mm/page_io.c
index 2e8019d0e048..189415852077 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -29,10 +29,9 @@
static struct bio *get_swap_bio(gfp_t gfp_flags,
struct page *page, bio_end_io_t end_io)
{
- int i, nr = hpage_nr_pages(page);
struct bio *bio;
- bio = bio_alloc(gfp_flags, nr);
+ bio = bio_alloc(gfp_flags, 1);
if (bio) {
struct block_device *bdev;
@@ -41,9 +40,7 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9;
bio->bi_end_io = end_io;
- for (i = 0; i < nr; i++)
- bio_add_page(bio, page + i, PAGE_SIZE, 0);
- VM_BUG_ON(bio->bi_iter.bi_size != PAGE_SIZE * nr);
+ bio_add_page(bio, page, PAGE_SIZE * hpage_nr_pages(page), 0);
}
return bio;
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 4c9e150e5ad3..0f76cca32a1c 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -913,7 +913,7 @@ adjust_va_to_fit_type(struct vmap_area *va,
unsigned long nva_start_addr, unsigned long size,
enum fit_type type)
{
- struct vmap_area *lva;
+ struct vmap_area *lva = NULL;
if (type == FL_FIT_TYPE) {
/*
@@ -972,7 +972,7 @@ adjust_va_to_fit_type(struct vmap_area *va,
if (type != FL_FIT_TYPE) {
augment_tree_propagate_from(va);
- if (type == NE_FIT_TYPE)
+ if (lva) /* type == NE_FIT_TYPE */
insert_vmap_area_augment(lva, &va->rb_node,
&free_vmap_area_root, &free_vmap_area_list);
}
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 19d27bee285e..1555b0c6f7ec 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -160,10 +160,10 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
struct in6_addr *daddr,
struct sk_buff *skb)
{
- struct lowpan_peer *peer;
- struct in6_addr *nexthop;
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
int count = atomic_read(&dev->peer_count);
+ const struct in6_addr *nexthop;
+ struct lowpan_peer *peer;
BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 16f9159234a2..8c2ec35b6512 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -318,6 +318,7 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk
static int ip_mc_finish_output(struct net *net, struct sock *sk,
struct sk_buff *skb)
{
+ struct rtable *new_rt;
int ret;
ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
@@ -326,6 +327,17 @@ static int ip_mc_finish_output(struct net *net, struct sock *sk,
return ret;
}
+ /* Reset rt_iif so that inet_iif() will return skb->skb_iif. Setting
+ * this to non-zero causes ipi_ifindex in in_pktinfo to be overwritten,
+ * see ipv4_pktinfo_prepare().
+ */
+ new_rt = rt_dst_clone(net->loopback_dev, skb_rtable(skb));
+ if (new_rt) {
+ new_rt->rt_iif = 0;
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &new_rt->dst);
+ }
+
return dev_loopback_xmit(net, sk, skb);
}
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 0b8e06ca75d6..40a6abbc9cf6 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -197,7 +197,7 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
}
sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
iph->saddr, iph->daddr,
- skb->dev->ifindex, sdif);
+ dif, sdif);
}
out:
read_unlock(&raw_v4_hashinfo.lock);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6cb7cff22db9..8ea0735a6754 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1647,6 +1647,39 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
}
EXPORT_SYMBOL(rt_dst_alloc);
+struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt)
+{
+ struct rtable *new_rt;
+
+ new_rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK,
+ rt->dst.flags);
+
+ if (new_rt) {
+ new_rt->rt_genid = rt_genid_ipv4(dev_net(dev));
+ new_rt->rt_flags = rt->rt_flags;
+ new_rt->rt_type = rt->rt_type;
+ new_rt->rt_is_input = rt->rt_is_input;
+ new_rt->rt_iif = rt->rt_iif;
+ new_rt->rt_pmtu = rt->rt_pmtu;
+ new_rt->rt_mtu_locked = rt->rt_mtu_locked;
+ new_rt->rt_gw_family = rt->rt_gw_family;
+ if (rt->rt_gw_family == AF_INET)
+ new_rt->rt_gw4 = rt->rt_gw4;
+ else if (rt->rt_gw_family == AF_INET6)
+ new_rt->rt_gw6 = rt->rt_gw6;
+ INIT_LIST_HEAD(&new_rt->rt_uncached);
+
+ new_rt->dst.flags |= DST_HOST;
+ new_rt->dst.input = rt->dst.input;
+ new_rt->dst.output = rt->dst.output;
+ new_rt->dst.error = rt->dst.error;
+ new_rt->dst.lastuse = jiffies;
+ new_rt->dst.lwtstate = lwtstate_get(rt->dst.lwtstate);
+ }
+ return new_rt;
+}
+EXPORT_SYMBOL(rt_dst_clone);
+
/* called in rcu_read_lock() section */
int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev,
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 834475717110..21efcd02f337 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -59,8 +59,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
{
struct dst_entry *dst = skb_dst(skb);
struct net_device *dev = dst->dev;
+ const struct in6_addr *nexthop;
struct neighbour *neigh;
- struct in6_addr *nexthop;
int ret;
if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 11ad62effd56..97a843cf164c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -218,7 +218,8 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
{
const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
- return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr);
+ return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any),
+ dst->dev, skb, daddr);
}
static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
@@ -5281,7 +5282,7 @@ static struct ctl_table ipv6_route_table_template[] = {
.data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &one,
},
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 241317473114..cdfc33517e85 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -439,9 +439,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
struct nf_flowtable *flow_table = priv;
struct flow_offload_tuple tuple = {};
enum flow_offload_tuple_dir dir;
+ const struct in6_addr *nexthop;
struct flow_offload *flow;
struct net_device *outdev;
- struct in6_addr *nexthop;
struct ipv6hdr *ip6h;
struct rt6_info *rt;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index a29d66da7394..5f78df080573 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2401,6 +2401,9 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
ts = __packet_set_timestamp(po, ph, skb);
__packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts);
+
+ if (!packet_read_pending(&po->tx_ring))
+ complete(&po->skb_completion);
}
sock_wfree(skb);
@@ -2585,7 +2588,7 @@ static int tpacket_parse_header(struct packet_sock *po, void *frame,
static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct net_device *dev;
struct virtio_net_hdr *vnet_hdr = NULL;
struct sockcm_cookie sockc;
@@ -2600,6 +2603,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
int len_sum = 0;
int status = TP_STATUS_AVAILABLE;
int hlen, tlen, copylen = 0;
+ long timeo = 0;
mutex_lock(&po->pg_vec_lock);
@@ -2646,12 +2650,21 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
if ((size_max > dev->mtu + reserve + VLAN_HLEN) && !po->has_vnet_hdr)
size_max = dev->mtu + reserve + VLAN_HLEN;
+ reinit_completion(&po->skb_completion);
+
do {
ph = packet_current_frame(po, &po->tx_ring,
TP_STATUS_SEND_REQUEST);
if (unlikely(ph == NULL)) {
- if (need_wait && need_resched())
- schedule();
+ if (need_wait && skb) {
+ timeo = sock_sndtimeo(&po->sk, msg->msg_flags & MSG_DONTWAIT);
+ timeo = wait_for_completion_interruptible_timeout(&po->skb_completion, timeo);
+ if (timeo <= 0) {
+ err = !timeo ? -ETIMEDOUT : -ERESTARTSYS;
+ goto out_put;
+ }
+ }
+ /* check for additional frames */
continue;
}
@@ -3207,6 +3220,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
sock_init_data(sock, sk);
po = pkt_sk(sk);
+ init_completion(&po->skb_completion);
sk->sk_family = PF_PACKET;
po->num = proto;
po->xmit = dev_queue_xmit;
@@ -4314,7 +4328,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
req3->tp_sizeof_priv ||
req3->tp_feature_req_word) {
err = -EINVAL;
- goto out;
+ goto out_free_pg_vec;
}
}
break;
@@ -4378,6 +4392,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
prb_shutdown_retire_blk_timer(po, rb_queue);
}
+out_free_pg_vec:
if (pg_vec)
free_pg_vec(pg_vec, order, req->tp_block_nr);
out:
diff --git a/net/packet/internal.h b/net/packet/internal.h
index 3bb7c5fb3bff..c70a2794456f 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -128,6 +128,7 @@ struct packet_sock {
unsigned int tp_hdrlen;
unsigned int tp_reserve;
unsigned int tp_tstamp;
+ struct completion skb_completion;
struct net_device __rcu *cached_dev;
int (*xmit)(struct sk_buff *skb);
struct packet_type prot_hook ____cacheline_aligned_in_smp;
diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c
index e16a3d37d2bc..732e109c3055 100644
--- a/net/sched/sch_cbs.c
+++ b/net/sched/sch_cbs.c
@@ -549,12 +549,17 @@ static struct notifier_block cbs_device_notifier = {
static int __init cbs_module_init(void)
{
- int err = register_netdevice_notifier(&cbs_device_notifier);
+ int err;
+ err = register_netdevice_notifier(&cbs_device_notifier);
if (err)
return err;
- return register_qdisc(&cbs_qdisc_ops);
+ err = register_qdisc(&cbs_qdisc_ops);
+ if (err)
+ unregister_netdevice_notifier(&cbs_device_notifier);
+
+ return err;
}
static void __exit cbs_module_exit(void)
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index e358437ba29b..69cebb2c998b 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -118,10 +118,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Initialize the bind addr area */
sctp_bind_addr_init(&ep->base.bind_addr, 0);
- /* Remember who we are attached to. */
- ep->base.sk = sk;
- sock_hold(ep->base.sk);
-
/* Create the lists of associations. */
INIT_LIST_HEAD(&ep->asocs);
@@ -154,6 +150,10 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
ep->prsctp_enable = net->sctp.prsctp_enable;
ep->reconf_enable = net->sctp.reconf_enable;
+ /* Remember who we are attached to. */
+ ep->base.sk = sk;
+ sock_hold(ep->base.sk);
+
return ep;
nomem_shkey:
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 0c874e996f85..7621ec2f539c 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -2029,7 +2029,7 @@ static int __init smc_init(void)
rc = smc_pnet_init();
if (rc)
- return rc;
+ goto out_pernet_subsys;
rc = smc_llc_init();
if (rc) {
@@ -2080,6 +2080,9 @@ out_proto:
proto_unregister(&smc_proto);
out_pnet:
smc_pnet_exit();
+out_pernet_subsys:
+ unregister_pernet_subsys(&smc_net_ops);
+
return rc;
}
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 2d2850adc2a3..4ca50ddf8d16 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -652,7 +652,10 @@ create:
rc = smc_lgr_create(smc, ini);
if (rc)
goto out;
+ lgr = conn->lgr;
+ write_lock_bh(&lgr->conns_lock);
smc_lgr_register_conn(conn); /* add smc conn to lgr */
+ write_unlock_bh(&lgr->conns_lock);
}
conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index c69951ed2ebc..36652352a38c 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -950,6 +950,8 @@ static int xs_local_send_request(struct rpc_rqst *req)
struct sock_xprt *transport =
container_of(xprt, struct sock_xprt, xprt);
struct xdr_buf *xdr = &req->rq_snd_buf;
+ rpc_fraghdr rm = xs_stream_record_marker(xdr);
+ unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen;
int status;
int sent = 0;
@@ -964,9 +966,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
req->rq_xtime = ktime_get();
status = xs_sendpages(transport->sock, NULL, 0, xdr,
- transport->xmit.offset,
- xs_stream_record_marker(xdr),
- &sent);
+ transport->xmit.offset, rm, &sent);
dprintk("RPC: %s(%u) = %d\n",
__func__, xdr->len - transport->xmit.offset, status);
@@ -976,7 +976,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
if (likely(sent > 0) || status == 0) {
transport->xmit.offset += sent;
req->rq_bytes_sent = transport->xmit.offset;
- if (likely(req->rq_bytes_sent >= req->rq_slen)) {
+ if (likely(req->rq_bytes_sent >= msglen)) {
req->rq_xmit_bytes_sent += transport->xmit.offset;
transport->xmit.offset = 0;
return 0;
@@ -1097,6 +1097,8 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
struct rpc_xprt *xprt = req->rq_xprt;
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct xdr_buf *xdr = &req->rq_snd_buf;
+ rpc_fraghdr rm = xs_stream_record_marker(xdr);
+ unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen;
bool vm_wait = false;
int status;
int sent;
@@ -1122,9 +1124,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
while (1) {
sent = 0;
status = xs_sendpages(transport->sock, NULL, 0, xdr,
- transport->xmit.offset,
- xs_stream_record_marker(xdr),
- &sent);
+ transport->xmit.offset, rm, &sent);
dprintk("RPC: xs_tcp_send_request(%u) = %d\n",
xdr->len - transport->xmit.offset, status);
@@ -1133,7 +1133,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
* reset the count of bytes sent. */
transport->xmit.offset += sent;
req->rq_bytes_sent = transport->xmit.offset;
- if (likely(req->rq_bytes_sent >= req->rq_slen)) {
+ if (likely(req->rq_bytes_sent >= msglen)) {
req->rq_xmit_bytes_sent += transport->xmit.offset;
transport->xmit.offset = 0;
return 0;
diff --git a/net/tipc/core.c b/net/tipc/core.c
index ed536c05252a..c8370722f0bb 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -134,7 +134,7 @@ static int __init tipc_init(void)
if (err)
goto out_sysctl;
- err = register_pernet_subsys(&tipc_net_ops);
+ err = register_pernet_device(&tipc_net_ops);
if (err)
goto out_pernet;
@@ -142,7 +142,7 @@ static int __init tipc_init(void)
if (err)
goto out_socket;
- err = register_pernet_subsys(&tipc_topsrv_net_ops);
+ err = register_pernet_device(&tipc_topsrv_net_ops);
if (err)
goto out_pernet_topsrv;
@@ -153,11 +153,11 @@ static int __init tipc_init(void)
pr_info("Started in single node mode\n");
return 0;
out_bearer:
- unregister_pernet_subsys(&tipc_topsrv_net_ops);
+ unregister_pernet_device(&tipc_topsrv_net_ops);
out_pernet_topsrv:
tipc_socket_stop();
out_socket:
- unregister_pernet_subsys(&tipc_net_ops);
+ unregister_pernet_device(&tipc_net_ops);
out_pernet:
tipc_unregister_sysctl();
out_sysctl:
@@ -172,9 +172,9 @@ out_netlink:
static void __exit tipc_exit(void)
{
tipc_bearer_cleanup();
- unregister_pernet_subsys(&tipc_topsrv_net_ops);
+ unregister_pernet_device(&tipc_topsrv_net_ops);
tipc_socket_stop();
- unregister_pernet_subsys(&tipc_net_ops);
+ unregister_pernet_device(&tipc_net_ops);
tipc_netlink_stop();
tipc_netlink_compat_stop();
tipc_unregister_sysctl();
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index c6a04c09d075..cf155061c472 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -445,7 +445,11 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,
if (!bearer)
return -EMSGSIZE;
- len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME);
+ len = TLV_GET_DATA_LEN(msg->req);
+ if (len <= 0)
+ return -EINVAL;
+
+ len = min_t(int, len, TIPC_MAX_BEARER_NAME);
if (!string_is_valid(name, len))
return -EINVAL;
@@ -539,7 +543,11 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,
name = (char *)TLV_DATA(msg->req);
- len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME);
+ len = TLV_GET_DATA_LEN(msg->req);
+ if (len <= 0)
+ return -EINVAL;
+
+ len = min_t(int, len, TIPC_MAX_BEARER_NAME);
if (!string_is_valid(name, len))
return -EINVAL;
@@ -817,7 +825,11 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,
if (!link)
return -EMSGSIZE;
- len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME);
+ len = TLV_GET_DATA_LEN(msg->req);
+ if (len <= 0)
+ return -EINVAL;
+
+ len = min_t(int, len, TIPC_MAX_BEARER_NAME);
if (!string_is_valid(name, len))
return -EINVAL;
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index fc81ae18cc44..e2b69e805d46 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -279,7 +279,8 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
goto skip_tx_cleanup;
}
- if (!tls_complete_pending_work(sk, ctx, 0, &timeo))
+ if (unlikely(sk->sk_write_pending) &&
+ !wait_on_pending_writer(sk, &timeo))
tls_handle_open_record(sk, 0);
/* We need these for tls_sw_fallback handling of other packets */
diff --git a/samples/pidfd/pidfd-metadata.c b/samples/pidfd/pidfd-metadata.c
index 14b454448429..c459155daf9a 100644
--- a/samples/pidfd/pidfd-metadata.c
+++ b/samples/pidfd/pidfd-metadata.c
@@ -83,7 +83,7 @@ static int pidfd_metadata_fd(pid_t pid, int pidfd)
int main(int argc, char *argv[])
{
- int pidfd = 0, ret = EXIT_FAILURE;
+ int pidfd = -1, ret = EXIT_FAILURE;
char buf[4096] = { 0 };
pid_t pid;
int procfd, statusfd;
@@ -91,7 +91,11 @@ int main(int argc, char *argv[])
pid = pidfd_clone(CLONE_PIDFD, &pidfd);
if (pid < 0)
- exit(ret);
+ err(ret, "CLONE_PIDFD");
+ if (pidfd == -1) {
+ warnx("CLONE_PIDFD is not supported by the kernel");
+ goto out;
+ }
procfd = pidfd_metadata_fd(pid, pidfd);
close(pidfd);
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
index 7b977b753a03..7985dd8198b6 100644
--- a/sound/ac97/bus.c
+++ b/sound/ac97/bus.c
@@ -122,17 +122,12 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
vendor_id);
ret = device_add(&codec->dev);
- if (ret)
- goto err_free_codec;
+ if (ret) {
+ put_device(&codec->dev);
+ return ret;
+ }
return 0;
-err_free_codec:
- of_node_put(codec->dev.of_node);
- put_device(&codec->dev);
- kfree(codec);
- ac97_ctrl->codecs[idx] = NULL;
-
- return ret;
}
unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 99b882158705..41905afada63 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -574,10 +574,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
stream->metadata_set = false;
stream->next_track = false;
- if (stream->direction == SND_COMPRESS_PLAYBACK)
- stream->runtime->state = SNDRV_PCM_STATE_SETUP;
- else
- stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
} else {
return -EPERM;
}
@@ -693,8 +690,17 @@ static int snd_compr_start(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_SETUP:
+ if (stream->direction != SND_COMPRESS_CAPTURE)
+ return -EPERM;
+ break;
+ case SNDRV_PCM_STATE_PREPARED:
+ break;
+ default:
return -EPERM;
+ }
+
retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
if (!retval)
stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
@@ -705,9 +711,15 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
- stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_SETUP:
+ case SNDRV_PCM_STATE_PREPARED:
return -EPERM;
+ default:
+ break;
+ }
+
retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
if (!retval) {
snd_compr_drain_notify(stream);
@@ -795,9 +807,17 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
- stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_SETUP:
+ case SNDRV_PCM_STATE_PREPARED:
+ case SNDRV_PCM_STATE_PAUSED:
return -EPERM;
+ case SNDRV_PCM_STATE_XRUN:
+ return -EPIPE;
+ default:
+ break;
+ }
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
if (retval) {
@@ -817,6 +837,10 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
return -EPERM;
+ /* next track doesn't have any meaning for capture streams */
+ if (stream->direction == SND_COMPRESS_CAPTURE)
+ return -EPERM;
+
/* you can signal next track if this is intended to be a gapless stream
* and current track metadata is set
*/
@@ -834,9 +858,23 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
static int snd_compr_partial_drain(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
- stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_SETUP:
+ case SNDRV_PCM_STATE_PREPARED:
+ case SNDRV_PCM_STATE_PAUSED:
+ return -EPERM;
+ case SNDRV_PCM_STATE_XRUN:
+ return -EPIPE;
+ default:
+ break;
+ }
+
+ /* partial drain doesn't have any meaning for capture streams */
+ if (stream->direction == SND_COMPRESS_CAPTURE)
return -EPERM;
+
/* stream can be drained only when next track has been signalled */
if (stream->next_track == false)
return -EPERM;
diff --git a/sound/core/control.c b/sound/core/control.c
index 5be5b9b931bf..7a4d8690ce41 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -196,16 +196,12 @@ EXPORT_SYMBOL(snd_ctl_notify);
static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
unsigned int access, struct snd_ctl_file *file)
{
- unsigned int size;
unsigned int idx;
if (count == 0 || count > MAX_CONTROL_COUNT)
return -EINVAL;
- size = sizeof(struct snd_kcontrol);
- size += sizeof(struct snd_kcontrol_volatile) * count;
-
- *kctl = kzalloc(size, GFP_KERNEL);
+ *kctl = kzalloc(struct_size(*kctl, vd, count), GFP_KERNEL);
if (!*kctl)
return -ENOMEM;
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 2fa9299a440d..7cd09cef6961 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -323,8 +323,8 @@ int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
err = snd_pcm_plugin_build(plug, "rate conversion",
src_format, dst_format,
- sizeof(struct rate_priv) +
- src_format->channels * sizeof(struct rate_channel),
+ struct_size(data, channels,
+ src_format->channels),
&plugin);
if (err < 0)
return err;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 860543a4c840..703857aab00f 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -77,7 +77,7 @@ void snd_pcm_group_init(struct snd_pcm_group *group)
spin_lock_init(&group->lock);
mutex_init(&group->mutex);
INIT_LIST_HEAD(&group->substreams);
- refcount_set(&group->refs, 0);
+ refcount_set(&group->refs, 1);
}
/* define group lock helpers */
@@ -1096,8 +1096,7 @@ static void snd_pcm_group_unref(struct snd_pcm_group *group,
if (!group)
return;
- do_free = refcount_dec_and_test(&group->refs) &&
- list_empty(&group->substreams);
+ do_free = refcount_dec_and_test(&group->refs);
snd_pcm_group_unlock(group, substream->pcm->nonatomic);
if (do_free)
kfree(group);
@@ -1874,6 +1873,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
if (!to_check)
break; /* all drained */
init_waitqueue_entry(&wait, current);
+ set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&to_check->sleep, &wait);
snd_pcm_stream_unlock_irq(substream);
if (runtime->no_period_wakeup)
@@ -1886,7 +1886,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
}
tout = msecs_to_jiffies(tout * 1000);
}
- tout = schedule_timeout_interruptible(tout);
+ tout = schedule_timeout(tout);
snd_pcm_stream_lock_irq(substream);
group = snd_pcm_stream_group_ref(substream);
@@ -2020,6 +2020,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
snd_pcm_group_lock_irq(target_group, nonatomic);
snd_pcm_stream_lock(substream1);
snd_pcm_group_assign(substream1, target_group);
+ refcount_inc(&target_group->refs);
snd_pcm_stream_unlock(substream1);
snd_pcm_group_unlock_irq(target_group, nonatomic);
_end:
@@ -2056,13 +2057,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
snd_pcm_group_lock_irq(group, nonatomic);
relink_to_local(substream);
+ refcount_dec(&group->refs);
/* detach the last stream, too */
if (list_is_singular(&group->substreams)) {
relink_to_local(list_first_entry(&group->substreams,
struct snd_pcm_substream,
link_list));
- do_free = !refcount_read(&group->refs);
+ do_free = refcount_dec_and_test(&group->refs);
}
snd_pcm_group_unlock_irq(group, nonatomic);
diff --git a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
index 96ad01fb668c..ccf682689ec9 100644
--- a/sound/core/seq/oss/seq_oss_ioctl.c
+++ b/sound/core/seq/oss/seq_oss_ioctl.c
@@ -49,7 +49,7 @@ static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
if (copy_from_user(ev, arg, 8))
return -EFAULT;
memset(&tmpev, 0, sizeof(tmpev));
- snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client);
+ snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.client, dp->addr.port);
tmpev.time.tick = 0;
if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
index 79ef430e56e1..537d5f423e20 100644
--- a/sound/core/seq/oss/seq_oss_rw.c
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -161,7 +161,7 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
memset(&event, 0, sizeof(event));
/* set dummy -- to be sure */
event.type = SNDRV_SEQ_EVENT_NOTEOFF;
- snd_seq_oss_fill_addr(dp, &event, dp->addr.port, dp->addr.client);
+ snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port);
if (snd_seq_oss_process_event(dp, rec, &event))
return 0; /* invalid event - no need to insert queue */
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index a60e7a17f0b8..7737b2670064 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1021,7 +1021,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
{
struct snd_seq_client *client = file->private_data;
int written = 0, len;
- int err;
+ int err, handled;
struct snd_seq_event event;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1034,6 +1034,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
if (!client->accept_output || client->pool == NULL)
return -ENXIO;
+ repeat:
+ handled = 0;
/* allocate the pool now if the pool is not allocated yet */
mutex_lock(&client->ioctl_mutex);
if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
@@ -1093,12 +1095,19 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
0, 0, &client->ioctl_mutex);
if (err < 0)
break;
+ handled++;
__skip_event:
/* Update pointers and counts */
count -= len;
buf += len;
written += len;
+
+ /* let's have a coffee break if too many events are queued */
+ if (++handled >= 200) {
+ mutex_unlock(&client->ioctl_mutex);
+ goto repeat;
+ }
}
out:
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c
index cc6eb30f03a2..fd5d6b8ac557 100644
--- a/sound/firewire/amdtp-am824.c
+++ b/sound/firewire/amdtp-am824.c
@@ -82,7 +82,7 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
if (err < 0)
return err;
- s->fdf = AMDTP_FDF_AM824 | s->sfc;
+ s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
p->pcm_channels = pcm_channels;
p->midi_ports = midi_ports;
@@ -320,7 +320,7 @@ static void read_midi_messages(struct amdtp_stream *s,
u8 *b;
for (f = 0; f < frames; f++) {
- port = (s->data_block_counter + f) % 8;
+ port = (8 - s->ctx_data.tx.first_dbc + s->data_block_counter + f) % 8;
b = (u8 *)&buffer[p->midi_position];
len = b[0] - 0x80;
diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h
index edb5c3afa6f8..4adbbf789cbe 100644
--- a/sound/firewire/amdtp-stream-trace.h
+++ b/sound/firewire/amdtp-stream-trace.h
@@ -13,147 +13,16 @@
#include <linux/tracepoint.h>
-TRACE_EVENT(in_packet,
- TP_PROTO(const struct amdtp_stream *s, u32 cycles, u32 *cip_header, unsigned int payload_length, unsigned int index),
- TP_ARGS(s, cycles, cip_header, payload_length, index),
- TP_STRUCT__entry(
- __field(unsigned int, second)
- __field(unsigned int, cycle)
- __field(int, channel)
- __field(int, src)
- __field(int, dest)
- __field(u32, cip_header0)
- __field(u32, cip_header1)
- __field(unsigned int, payload_quadlets)
- __field(unsigned int, packet_index)
- __field(unsigned int, irq)
- __field(unsigned int, index)
- ),
- TP_fast_assign(
- __entry->second = cycles / CYCLES_PER_SECOND;
- __entry->cycle = cycles % CYCLES_PER_SECOND;
- __entry->channel = s->context->channel;
- __entry->src = fw_parent_device(s->unit)->node_id;
- __entry->dest = fw_parent_device(s->unit)->card->node_id;
- __entry->cip_header0 = cip_header[0];
- __entry->cip_header1 = cip_header[1];
- __entry->payload_quadlets = payload_length / 4;
- __entry->packet_index = s->packet_index;
- __entry->irq = !!in_interrupt();
- __entry->index = index;
- ),
- TP_printk(
- "%02u %04u %04x %04x %02d %08x %08x %03u %02u %01u %02u",
- __entry->second,
- __entry->cycle,
- __entry->src,
- __entry->dest,
- __entry->channel,
- __entry->cip_header0,
- __entry->cip_header1,
- __entry->payload_quadlets,
- __entry->packet_index,
- __entry->irq,
- __entry->index)
-);
-
-TRACE_EVENT(out_packet,
- TP_PROTO(const struct amdtp_stream *s, u32 cycles, __be32 *cip_header, unsigned int payload_length, unsigned int index),
- TP_ARGS(s, cycles, cip_header, payload_length, index),
- TP_STRUCT__entry(
- __field(unsigned int, second)
- __field(unsigned int, cycle)
- __field(int, channel)
- __field(int, src)
- __field(int, dest)
- __field(u32, cip_header0)
- __field(u32, cip_header1)
- __field(unsigned int, payload_quadlets)
- __field(unsigned int, packet_index)
- __field(unsigned int, irq)
- __field(unsigned int, index)
- ),
- TP_fast_assign(
- __entry->second = cycles / CYCLES_PER_SECOND;
- __entry->cycle = cycles % CYCLES_PER_SECOND;
- __entry->channel = s->context->channel;
- __entry->src = fw_parent_device(s->unit)->card->node_id;
- __entry->dest = fw_parent_device(s->unit)->node_id;
- __entry->cip_header0 = be32_to_cpu(cip_header[0]);
- __entry->cip_header1 = be32_to_cpu(cip_header[1]);
- __entry->payload_quadlets = payload_length / 4;
- __entry->packet_index = s->packet_index;
- __entry->irq = !!in_interrupt();
- __entry->index = index;
- ),
- TP_printk(
- "%02u %04u %04x %04x %02d %08x %08x %03u %02u %01u %02u",
- __entry->second,
- __entry->cycle,
- __entry->src,
- __entry->dest,
- __entry->channel,
- __entry->cip_header0,
- __entry->cip_header1,
- __entry->payload_quadlets,
- __entry->packet_index,
- __entry->irq,
- __entry->index)
-);
-
-TRACE_EVENT(in_packet_without_header,
- TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_quadlets, unsigned int data_blocks, unsigned int index),
- TP_ARGS(s, cycles, payload_quadlets, data_blocks, index),
- TP_STRUCT__entry(
- __field(unsigned int, second)
- __field(unsigned int, cycle)
- __field(int, channel)
- __field(int, src)
- __field(int, dest)
- __field(unsigned int, payload_quadlets)
- __field(unsigned int, data_blocks)
- __field(unsigned int, data_block_counter)
- __field(unsigned int, packet_index)
- __field(unsigned int, irq)
- __field(unsigned int, index)
- ),
- TP_fast_assign(
- __entry->second = cycles / CYCLES_PER_SECOND;
- __entry->cycle = cycles % CYCLES_PER_SECOND;
- __entry->channel = s->context->channel;
- __entry->src = fw_parent_device(s->unit)->node_id;
- __entry->dest = fw_parent_device(s->unit)->card->node_id;
- __entry->payload_quadlets = payload_quadlets;
- __entry->data_blocks = data_blocks,
- __entry->data_block_counter = s->data_block_counter,
- __entry->packet_index = s->packet_index;
- __entry->irq = !!in_interrupt();
- __entry->index = index;
- ),
- TP_printk(
- "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
- __entry->second,
- __entry->cycle,
- __entry->src,
- __entry->dest,
- __entry->channel,
- __entry->payload_quadlets,
- __entry->data_blocks,
- __entry->data_block_counter,
- __entry->packet_index,
- __entry->irq,
- __entry->index)
-);
-
-TRACE_EVENT(out_packet_without_header,
- TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
- TP_ARGS(s, cycles, payload_length, data_blocks, index),
+TRACE_EVENT(amdtp_packet,
+ TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
+ TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, index),
TP_STRUCT__entry(
__field(unsigned int, second)
__field(unsigned int, cycle)
__field(int, channel)
__field(int, src)
__field(int, dest)
+ __dynamic_array(u8, cip_header, cip_header ? 8 : 0)
__field(unsigned int, payload_quadlets)
__field(unsigned int, data_blocks)
__field(unsigned int, data_block_counter)
@@ -165,17 +34,26 @@ TRACE_EVENT(out_packet_without_header,
__entry->second = cycles / CYCLES_PER_SECOND;
__entry->cycle = cycles % CYCLES_PER_SECOND;
__entry->channel = s->context->channel;
- __entry->src = fw_parent_device(s->unit)->card->node_id;
- __entry->dest = fw_parent_device(s->unit)->node_id;
- __entry->payload_quadlets = payload_length / 4;
- __entry->data_blocks = data_blocks,
+ if (s->direction == AMDTP_IN_STREAM) {
+ __entry->src = fw_parent_device(s->unit)->node_id;
+ __entry->dest = fw_parent_device(s->unit)->card->node_id;
+ } else {
+ __entry->src = fw_parent_device(s->unit)->card->node_id;
+ __entry->dest = fw_parent_device(s->unit)->node_id;
+ }
+ if (cip_header) {
+ memcpy(__get_dynamic_array(cip_header), cip_header,
+ __get_dynamic_array_len(cip_header));
+ }
+ __entry->payload_quadlets = payload_length / sizeof(__be32);
+ __entry->data_blocks = data_blocks;
__entry->data_block_counter = s->data_block_counter,
__entry->packet_index = s->packet_index;
__entry->irq = !!in_interrupt();
__entry->index = index;
),
TP_printk(
- "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
+ "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u %s",
__entry->second,
__entry->cycle,
__entry->src,
@@ -186,7 +64,10 @@ TRACE_EVENT(out_packet_without_header,
__entry->data_block_counter,
__entry->packet_index,
__entry->irq,
- __entry->index)
+ __entry->index,
+ __print_array(__get_dynamic_array(cip_header),
+ __get_dynamic_array_len(cip_header),
+ sizeof(u8)))
);
#endif
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 68f5fa4b183d..4d71d74707cf 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -56,10 +56,15 @@
#define INTERRUPT_INTERVAL 16
#define QUEUE_LENGTH 48
-#define IR_HEADER_SIZE 8 // For header and timestamp.
-#define OUT_PACKET_HEADER_SIZE 0
+// For iso header, tstamp and 2 CIP header.
+#define IR_CTX_HEADER_SIZE_CIP 16
+// For iso header and tstamp.
+#define IR_CTX_HEADER_SIZE_NO_CIP 8
#define HEADER_TSTAMP_MASK 0x0000ffff
+#define IT_PKT_HEADER_SIZE_CIP 8 // For 2 CIP header.
+#define IT_PKT_HEADER_SIZE_NO_CIP 0 // Nothing.
+
static void pcm_period_tasklet(unsigned long data);
/**
@@ -260,11 +265,18 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
s->data_block_quadlets = data_block_quadlets;
s->syt_interval = amdtp_syt_intervals[sfc];
- /* default buffering in the device */
- s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
- if (s->flags & CIP_BLOCKING)
- /* additional buffering needed to adjust for no-data packets */
- s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
+ // default buffering in the device.
+ if (s->direction == AMDTP_OUT_STREAM) {
+ s->ctx_data.rx.transfer_delay =
+ TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+
+ if (s->flags & CIP_BLOCKING) {
+ // additional buffering needed to adjust for no-data
+ // packets.
+ s->ctx_data.rx.transfer_delay +=
+ TICKS_PER_SECOND * s->syt_interval / rate;
+ }
+ }
return 0;
}
@@ -280,15 +292,15 @@ EXPORT_SYMBOL(amdtp_stream_set_parameters);
unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s)
{
unsigned int multiplier = 1;
- unsigned int header_size = 0;
+ unsigned int cip_header_size = 0;
if (s->flags & CIP_JUMBO_PAYLOAD)
multiplier = 5;
if (!(s->flags & CIP_NO_HEADER))
- header_size = 8;
+ cip_header_size = sizeof(__be32) * 2;
- return header_size +
- s->syt_interval * s->data_block_quadlets * 4 * multiplier;
+ return cip_header_size +
+ s->syt_interval * s->data_block_quadlets * sizeof(__be32) * multiplier;
}
EXPORT_SYMBOL(amdtp_stream_get_max_payload);
@@ -321,10 +333,10 @@ static unsigned int calculate_data_blocks(struct amdtp_stream *s,
/* Non-blocking mode. */
} else {
if (!cip_sfc_is_base_44100(s->sfc)) {
- /* Sample_rate / 8000 is an integer, and precomputed. */
- data_blocks = s->data_block_state;
+ // Sample_rate / 8000 is an integer, and precomputed.
+ data_blocks = s->ctx_data.rx.data_block_state;
} else {
- phase = s->data_block_state;
+ phase = s->ctx_data.rx.data_block_state;
/*
* This calculates the number of data blocks per packet so that
@@ -343,7 +355,7 @@ static unsigned int calculate_data_blocks(struct amdtp_stream *s,
data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
if (++phase >= (80 >> (s->sfc >> 1)))
phase = 0;
- s->data_block_state = phase;
+ s->ctx_data.rx.data_block_state = phase;
}
}
@@ -355,9 +367,10 @@ static unsigned int calculate_syt(struct amdtp_stream *s,
{
unsigned int syt_offset, phase, index, syt;
- if (s->last_syt_offset < TICKS_PER_CYCLE) {
+ if (s->ctx_data.rx.last_syt_offset < TICKS_PER_CYCLE) {
if (!cip_sfc_is_base_44100(s->sfc))
- syt_offset = s->last_syt_offset + s->syt_offset_state;
+ syt_offset = s->ctx_data.rx.last_syt_offset +
+ s->ctx_data.rx.syt_offset_state;
else {
/*
* The time, in ticks, of the n'th SYT_INTERVAL sample is:
@@ -369,21 +382,21 @@ static unsigned int calculate_syt(struct amdtp_stream *s,
* 1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ...
* This code generates _exactly_ the same sequence.
*/
- phase = s->syt_offset_state;
+ phase = s->ctx_data.rx.syt_offset_state;
index = phase % 13;
- syt_offset = s->last_syt_offset;
+ syt_offset = s->ctx_data.rx.last_syt_offset;
syt_offset += 1386 + ((index && !(index & 3)) ||
phase == 146);
if (++phase >= 147)
phase = 0;
- s->syt_offset_state = phase;
+ s->ctx_data.rx.syt_offset_state = phase;
}
} else
- syt_offset = s->last_syt_offset - TICKS_PER_CYCLE;
- s->last_syt_offset = syt_offset;
+ syt_offset = s->ctx_data.rx.last_syt_offset - TICKS_PER_CYCLE;
+ s->ctx_data.rx.last_syt_offset = syt_offset;
if (syt_offset < TICKS_PER_CYCLE) {
- syt_offset += s->transfer_delay;
+ syt_offset += s->ctx_data.rx.transfer_delay;
syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
syt += syt_offset % TICKS_PER_CYCLE;
@@ -420,23 +433,15 @@ static void pcm_period_tasklet(unsigned long data)
snd_pcm_period_elapsed(pcm);
}
-static int queue_packet(struct amdtp_stream *s, unsigned int header_length,
- unsigned int payload_length)
+static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
{
- struct fw_iso_packet p = {0};
- int err = 0;
+ int err;
- if (IS_ERR(s->context))
- goto end;
+ params->interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
+ params->tag = s->tag;
+ params->sy = 0;
- p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
- p.tag = s->tag;
- p.header_length = header_length;
- if (payload_length > 0)
- p.payload_length = payload_length;
- else
- p.skip = true;
- err = fw_iso_context_queue(s->context, &p, &s->buffer.iso_buffer,
+ err = fw_iso_context_queue(s->context, params, &s->buffer.iso_buffer,
s->buffer.packets[s->packet_index].offset);
if (err < 0) {
dev_err(&s->unit->device, "queueing error: %d\n", err);
@@ -450,112 +455,83 @@ end:
}
static inline int queue_out_packet(struct amdtp_stream *s,
- unsigned int payload_length)
+ struct fw_iso_packet *params)
{
- return queue_packet(s, OUT_PACKET_HEADER_SIZE, payload_length);
+ params->skip =
+ !!(params->header_length == 0 && params->payload_length == 0);
+ return queue_packet(s, params);
}
-static inline int queue_in_packet(struct amdtp_stream *s)
+static inline int queue_in_packet(struct amdtp_stream *s,
+ struct fw_iso_packet *params)
{
- return queue_packet(s, IR_HEADER_SIZE, s->max_payload_length);
+ // Queue one packet for IR context.
+ params->header_length = s->ctx_data.tx.ctx_header_size;
+ params->payload_length = s->ctx_data.tx.max_ctx_payload_length;
+ params->skip = false;
+ return queue_packet(s, params);
}
-static int handle_out_packet(struct amdtp_stream *s,
- unsigned int payload_length, unsigned int cycle,
- unsigned int index)
+static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2],
+ unsigned int syt)
{
- __be32 *buffer;
- unsigned int syt;
- unsigned int data_blocks;
- unsigned int pcm_frames;
- struct snd_pcm_substream *pcm;
-
- buffer = s->buffer.packets[s->packet_index].buffer;
- syt = calculate_syt(s, cycle);
- data_blocks = calculate_data_blocks(s, syt);
- pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
-
- if (s->flags & CIP_DBC_IS_END_EVENT)
- s->data_block_counter =
- (s->data_block_counter + data_blocks) & 0xff;
-
- buffer[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) |
+ cip_header[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) |
(s->data_block_quadlets << CIP_DBS_SHIFT) |
((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) |
s->data_block_counter);
- buffer[1] = cpu_to_be32(CIP_EOH |
- ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
- ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
- (syt & CIP_SYT_MASK));
-
- if (!(s->flags & CIP_DBC_IS_END_EVENT))
- s->data_block_counter =
- (s->data_block_counter + data_blocks) & 0xff;
- payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
-
- trace_out_packet(s, cycle, buffer, payload_length, index);
-
- if (queue_out_packet(s, payload_length) < 0)
- return -EIO;
-
- pcm = READ_ONCE(s->pcm);
- if (pcm && pcm_frames > 0)
- update_pcm_pointers(s, pcm, pcm_frames);
-
- /* No need to return the number of handled data blocks. */
- return 0;
+ cip_header[1] = cpu_to_be32(CIP_EOH |
+ ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
+ ((s->ctx_data.rx.fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
+ (syt & CIP_SYT_MASK));
}
-static int handle_out_packet_without_header(struct amdtp_stream *s,
- unsigned int payload_length, unsigned int cycle,
- unsigned int index)
+static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle,
+ struct fw_iso_packet *params,
+ unsigned int data_blocks, unsigned int syt,
+ unsigned int index)
{
- __be32 *buffer;
- unsigned int syt;
- unsigned int data_blocks;
- unsigned int pcm_frames;
- struct snd_pcm_substream *pcm;
-
- buffer = s->buffer.packets[s->packet_index].buffer;
- syt = calculate_syt(s, cycle);
- data_blocks = calculate_data_blocks(s, syt);
- pcm_frames = s->process_data_blocks(s, buffer, data_blocks, &syt);
- s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+ unsigned int payload_length;
+ __be32 *cip_header;
- payload_length = data_blocks * 4 * s->data_block_quadlets;
+ payload_length = data_blocks * sizeof(__be32) * s->data_block_quadlets;
+ params->payload_length = payload_length;
- trace_out_packet_without_header(s, cycle, payload_length, data_blocks,
- index);
+ if (s->flags & CIP_DBC_IS_END_EVENT) {
+ s->data_block_counter =
+ (s->data_block_counter + data_blocks) & 0xff;
+ }
- if (queue_out_packet(s, payload_length) < 0)
- return -EIO;
+ if (!(s->flags & CIP_NO_HEADER)) {
+ cip_header = (__be32 *)params->header;
+ generate_cip_header(s, cip_header, syt);
+ params->header_length = 2 * sizeof(__be32);
+ payload_length += params->header_length;
+ } else {
+ cip_header = NULL;
+ }
- pcm = READ_ONCE(s->pcm);
- if (pcm && pcm_frames > 0)
- update_pcm_pointers(s, pcm, pcm_frames);
+ trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks,
+ index);
- /* No need to return the number of handled data blocks. */
- return 0;
+ if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
+ s->data_block_counter =
+ (s->data_block_counter + data_blocks) & 0xff;
+ }
}
-static int handle_in_packet(struct amdtp_stream *s,
- unsigned int payload_length, unsigned int cycle,
- unsigned int index)
+static int check_cip_header(struct amdtp_stream *s, const __be32 *buf,
+ unsigned int payload_length,
+ unsigned int *data_blocks, unsigned int *dbc,
+ unsigned int *syt)
{
- __be32 *buffer;
u32 cip_header[2];
- unsigned int sph, fmt, fdf, syt;
- unsigned int data_block_quadlets, data_block_counter, dbc_interval;
- unsigned int data_blocks;
- struct snd_pcm_substream *pcm;
- unsigned int pcm_frames;
+ unsigned int sph;
+ unsigned int fmt;
+ unsigned int fdf;
bool lost;
- buffer = s->buffer.packets[s->packet_index].buffer;
- cip_header[0] = be32_to_cpu(buffer[0]);
- cip_header[1] = be32_to_cpu(buffer[1]);
-
- trace_in_packet(s, cycle, cip_header, payload_length, index);
+ cip_header[0] = be32_to_cpu(buf[0]);
+ cip_header[1] = be32_to_cpu(buf[1]);
/*
* This module supports 'Two-quadlet CIP header with SYT field'.
@@ -567,9 +543,7 @@ static int handle_in_packet(struct amdtp_stream *s,
dev_info_ratelimited(&s->unit->device,
"Invalid CIP header for AMDTP: %08X:%08X\n",
cip_header[0], cip_header[1]);
- data_blocks = 0;
- pcm_frames = 0;
- goto end;
+ return -EAGAIN;
}
/* Check valid protocol or not. */
@@ -579,19 +553,17 @@ static int handle_in_packet(struct amdtp_stream *s,
dev_info_ratelimited(&s->unit->device,
"Detect unexpected protocol: %08x %08x\n",
cip_header[0], cip_header[1]);
- data_blocks = 0;
- pcm_frames = 0;
- goto end;
+ return -EAGAIN;
}
/* Calculate data blocks */
fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT;
- if (payload_length < 12 ||
+ if (payload_length < sizeof(__be32) * 2 ||
(fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) {
- data_blocks = 0;
+ *data_blocks = 0;
} else {
- data_block_quadlets =
- (cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
+ unsigned int data_block_quadlets =
+ (cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
/* avoid division by zero */
if (data_block_quadlets == 0) {
dev_err(&s->unit->device,
@@ -602,95 +574,97 @@ static int handle_in_packet(struct amdtp_stream *s,
if (s->flags & CIP_WRONG_DBS)
data_block_quadlets = s->data_block_quadlets;
- data_blocks = (payload_length / 4 - 2) /
+ *data_blocks = (payload_length / sizeof(__be32) - 2) /
data_block_quadlets;
}
/* Check data block counter continuity */
- data_block_counter = cip_header[0] & CIP_DBC_MASK;
- if (data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
+ *dbc = cip_header[0] & CIP_DBC_MASK;
+ if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
s->data_block_counter != UINT_MAX)
- data_block_counter = s->data_block_counter;
+ *dbc = s->data_block_counter;
if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) &&
- data_block_counter == s->tx_first_dbc) ||
+ *dbc == s->ctx_data.tx.first_dbc) ||
s->data_block_counter == UINT_MAX) {
lost = false;
} else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
- lost = data_block_counter != s->data_block_counter;
+ lost = *dbc != s->data_block_counter;
} else {
- if (data_blocks > 0 && s->tx_dbc_interval > 0)
- dbc_interval = s->tx_dbc_interval;
+ unsigned int dbc_interval;
+
+ if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
+ dbc_interval = s->ctx_data.tx.dbc_interval;
else
- dbc_interval = data_blocks;
+ dbc_interval = *data_blocks;
- lost = data_block_counter !=
- ((s->data_block_counter + dbc_interval) & 0xff);
+ lost = *dbc != ((s->data_block_counter + dbc_interval) & 0xff);
}
if (lost) {
dev_err(&s->unit->device,
"Detect discontinuity of CIP: %02X %02X\n",
- s->data_block_counter, data_block_counter);
+ s->data_block_counter, *dbc);
return -EIO;
}
- syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
- pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
-
- if (s->flags & CIP_DBC_IS_END_EVENT)
- s->data_block_counter = data_block_counter;
- else
- s->data_block_counter =
- (data_block_counter + data_blocks) & 0xff;
-end:
- if (queue_in_packet(s) < 0)
- return -EIO;
-
- pcm = READ_ONCE(s->pcm);
- if (pcm && pcm_frames > 0)
- update_pcm_pointers(s, pcm, pcm_frames);
+ *syt = cip_header[1] & CIP_SYT_MASK;
return 0;
}
-static int handle_in_packet_without_header(struct amdtp_stream *s,
- unsigned int payload_length, unsigned int cycle,
- unsigned int index)
+static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle,
+ const __be32 *ctx_header,
+ unsigned int *payload_length,
+ unsigned int *data_blocks, unsigned int *syt,
+ unsigned int index)
{
- __be32 *buffer;
- unsigned int payload_quadlets;
- unsigned int data_blocks;
- struct snd_pcm_substream *pcm;
- unsigned int pcm_frames;
-
- buffer = s->buffer.packets[s->packet_index].buffer;
- payload_quadlets = payload_length / 4;
- data_blocks = payload_quadlets / s->data_block_quadlets;
+ unsigned int dbc;
+ const __be32 *cip_header;
+ int err;
- trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks,
- index);
+ *payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT;
+ if (*payload_length > s->ctx_data.tx.ctx_header_size +
+ s->ctx_data.tx.max_ctx_payload_length) {
+ dev_err(&s->unit->device,
+ "Detect jumbo payload: %04x %04x\n",
+ *payload_length, s->ctx_data.tx.max_ctx_payload_length);
+ return -EIO;
+ }
- pcm_frames = s->process_data_blocks(s, buffer, data_blocks, NULL);
- s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+ if (!(s->flags & CIP_NO_HEADER)) {
+ cip_header = ctx_header + 2;
+ err = check_cip_header(s, cip_header, *payload_length,
+ data_blocks, &dbc, syt);
+ if (err < 0)
+ return err;
+ } else {
+ cip_header = NULL;
+ err = 0;
+ *data_blocks = *payload_length / sizeof(__be32) /
+ s->data_block_quadlets;
+ *syt = 0;
+
+ if (s->data_block_counter != UINT_MAX)
+ dbc = s->data_block_counter;
+ else
+ dbc = 0;
+ }
- if (queue_in_packet(s) < 0)
- return -EIO;
+ s->data_block_counter = dbc;
- pcm = READ_ONCE(s->pcm);
- if (pcm && pcm_frames > 0)
- update_pcm_pointers(s, pcm, pcm_frames);
+ trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks,
+ index);
- return 0;
+ return err;
}
-/*
- * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On
- * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent
- * it. Thus, via Linux firewire subsystem, we can get the 3 bits for second.
- */
-static inline u32 compute_cycle_count(u32 tstamp)
+// In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On
+// the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent
+// it. Thus, via Linux firewire subsystem, we can get the 3 bits for second.
+static inline u32 compute_cycle_count(__be32 ctx_header_tstamp)
{
+ u32 tstamp = be32_to_cpu(ctx_header_tstamp) & HEADER_TSTAMP_MASK;
return (((tstamp >> 13) & 0x07) * 8000) + (tstamp & 0x1fff);
}
@@ -702,31 +676,68 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
return cycle;
}
+// Align to actual cycle count for the packet which is going to be scheduled.
+// This module queued the same number of isochronous cycle as QUEUE_LENGTH to
+// skip isochronous cycle, therefore it's OK to just increment the cycle by
+// QUEUE_LENGTH for scheduled cycle.
+static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp)
+{
+ u32 cycle = compute_cycle_count(ctx_header_tstamp);
+ return increment_cycle_count(cycle, QUEUE_LENGTH);
+}
+
+static inline void cancel_stream(struct amdtp_stream *s)
+{
+ s->packet_index = -1;
+ if (in_interrupt())
+ amdtp_stream_pcm_abort(s);
+ WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
+}
+
static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
size_t header_length, void *header,
void *private_data)
{
struct amdtp_stream *s = private_data;
- unsigned int i, packets = header_length / 4;
- u32 cycle;
+ const __be32 *ctx_header = header;
+ unsigned int packets = header_length / sizeof(*ctx_header);
+ int i;
if (s->packet_index < 0)
return;
- cycle = compute_cycle_count(tstamp);
-
- /* Align to actual cycle count for the last packet. */
- cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
-
for (i = 0; i < packets; ++i) {
- cycle = increment_cycle_count(cycle, 1);
- if (s->handle_packet(s, 0, cycle, i) < 0) {
- s->packet_index = -1;
- if (in_interrupt())
- amdtp_stream_pcm_abort(s);
- WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
+ u32 cycle;
+ unsigned int syt;
+ unsigned int data_blocks;
+ __be32 *buffer;
+ unsigned int pcm_frames;
+ struct {
+ struct fw_iso_packet params;
+ __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)];
+ } template = { {0}, {0} };
+ struct snd_pcm_substream *pcm;
+
+ cycle = compute_it_cycle(*ctx_header);
+ syt = calculate_syt(s, cycle);
+ data_blocks = calculate_data_blocks(s, syt);
+ buffer = s->buffer.packets[s->packet_index].buffer;
+ pcm_frames = s->process_data_blocks(s, buffer, data_blocks,
+ &syt);
+
+ build_it_pkt_header(s, cycle, &template.params, data_blocks,
+ syt, i);
+
+ if (queue_out_packet(s, &template.params) < 0) {
+ cancel_stream(s);
return;
}
+
+ pcm = READ_ONCE(s->pcm);
+ if (pcm && pcm_frames > 0)
+ update_pcm_pointers(s, pcm, pcm_frames);
+
+ ++ctx_header;
}
fw_iso_context_queue_flush(s->context);
@@ -738,46 +749,55 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
{
struct amdtp_stream *s = private_data;
unsigned int i, packets;
- unsigned int payload_length, max_payload_length;
__be32 *ctx_header = header;
if (s->packet_index < 0)
return;
- /* The number of packets in buffer */
- packets = header_length / IR_HEADER_SIZE;
-
- /* For buffer-over-run prevention. */
- max_payload_length = s->max_payload_length;
+ // The number of packets in buffer.
+ packets = header_length / s->ctx_data.tx.ctx_header_size;
for (i = 0; i < packets; i++) {
- u32 iso_header = be32_to_cpu(ctx_header[0]);
- unsigned int cycle;
+ u32 cycle;
+ unsigned int payload_length;
+ unsigned int data_blocks;
+ unsigned int syt;
+ __be32 *buffer;
+ unsigned int pcm_frames = 0;
+ struct fw_iso_packet params = {0};
+ struct snd_pcm_substream *pcm;
+ int err;
+
+ cycle = compute_cycle_count(ctx_header[1]);
+ err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length,
+ &data_blocks, &syt, i);
+ if (err < 0 && err != -EAGAIN)
+ break;
- tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
- cycle = compute_cycle_count(tstamp);
+ if (err >= 0) {
+ buffer = s->buffer.packets[s->packet_index].buffer;
+ pcm_frames = s->process_data_blocks(s, buffer,
+ data_blocks, &syt);
- /* The number of bytes in this packet */
- payload_length = iso_header >> ISO_DATA_LENGTH_SHIFT;
- if (payload_length > max_payload_length) {
- dev_err(&s->unit->device,
- "Detect jumbo payload: %04x %04x\n",
- payload_length, max_payload_length);
- break;
+ if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
+ s->data_block_counter += data_blocks;
+ s->data_block_counter &= 0xff;
+ }
}
- if (s->handle_packet(s, payload_length, cycle, i) < 0)
+ if (queue_in_packet(s, &params) < 0)
break;
- ctx_header += IR_HEADER_SIZE / sizeof(__be32);
+ pcm = READ_ONCE(s->pcm);
+ if (pcm && pcm_frames > 0)
+ update_pcm_pointers(s, pcm, pcm_frames);
+
+ ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header);
}
/* Queueing error or detecting invalid payload. */
if (i < packets) {
- s->packet_index = -1;
- if (in_interrupt())
- amdtp_stream_pcm_abort(s);
- WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
+ cancel_stream(s);
return;
}
@@ -790,9 +810,8 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
void *header, void *private_data)
{
struct amdtp_stream *s = private_data;
- __be32 *ctx_header = header;
+ const __be32 *ctx_header = header;
u32 cycle;
- unsigned int packets;
/*
* For in-stream, first packet has come.
@@ -802,23 +821,13 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
wake_up(&s->callback_wait);
if (s->direction == AMDTP_IN_STREAM) {
- tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
- cycle = compute_cycle_count(tstamp);
+ cycle = compute_cycle_count(ctx_header[1]);
context->callback.sc = in_stream_callback;
- if (s->flags & CIP_NO_HEADER)
- s->handle_packet = handle_in_packet_without_header;
- else
- s->handle_packet = handle_in_packet;
} else {
- packets = header_length / 4;
- cycle = compute_cycle_count(tstamp);
- cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
+ cycle = compute_it_cycle(*ctx_header);
+
context->callback.sc = out_stream_callback;
- if (s->flags & CIP_NO_HEADER)
- s->handle_packet = handle_out_packet_without_header;
- else
- s->handle_packet = handle_out_packet;
}
s->start_cycle = cycle;
@@ -841,7 +850,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
static const struct {
unsigned int data_block;
unsigned int syt_offset;
- } initial_state[] = {
+ } *entry, initial_state[] = {
[CIP_SFC_32000] = { 4, 3072 },
[CIP_SFC_48000] = { 6, 1024 },
[CIP_SFC_96000] = { 12, 1024 },
@@ -850,7 +859,8 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
[CIP_SFC_88200] = { 0, 67 },
[CIP_SFC_176400] = { 0, 67 },
};
- unsigned int header_size;
+ unsigned int ctx_header_size;
+ unsigned int max_ctx_payload_size;
enum dma_data_direction dir;
int type, tag, err;
@@ -862,32 +872,46 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
goto err_unlock;
}
- if (s->direction == AMDTP_IN_STREAM)
+ if (s->direction == AMDTP_IN_STREAM) {
s->data_block_counter = UINT_MAX;
- else
+ } else {
+ entry = &initial_state[s->sfc];
+
s->data_block_counter = 0;
- s->data_block_state = initial_state[s->sfc].data_block;
- s->syt_offset_state = initial_state[s->sfc].syt_offset;
- s->last_syt_offset = TICKS_PER_CYCLE;
+ s->ctx_data.rx.data_block_state = entry->data_block;
+ s->ctx_data.rx.syt_offset_state = entry->syt_offset;
+ s->ctx_data.rx.last_syt_offset = TICKS_PER_CYCLE;
+ }
/* initialize packet buffer */
if (s->direction == AMDTP_IN_STREAM) {
dir = DMA_FROM_DEVICE;
type = FW_ISO_CONTEXT_RECEIVE;
- header_size = IR_HEADER_SIZE;
+ if (!(s->flags & CIP_NO_HEADER))
+ ctx_header_size = IR_CTX_HEADER_SIZE_CIP;
+ else
+ ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP;
+
+ max_ctx_payload_size = amdtp_stream_get_max_payload(s) -
+ ctx_header_size;
} else {
dir = DMA_TO_DEVICE;
type = FW_ISO_CONTEXT_TRANSMIT;
- header_size = OUT_PACKET_HEADER_SIZE;
+ ctx_header_size = 0; // No effect for IT context.
+
+ max_ctx_payload_size = amdtp_stream_get_max_payload(s);
+ if (!(s->flags & CIP_NO_HEADER))
+ max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP;
}
+
err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
- amdtp_stream_get_max_payload(s), dir);
+ max_ctx_payload_size, dir);
if (err < 0)
goto err_unlock;
s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
- type, channel, speed, header_size,
- amdtp_stream_first_callback, s);
+ type, channel, speed, ctx_header_size,
+ amdtp_stream_first_callback, s);
if (IS_ERR(s->context)) {
err = PTR_ERR(s->context);
if (err == -EBUSY)
@@ -898,8 +922,10 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
amdtp_stream_update(s);
- if (s->direction == AMDTP_IN_STREAM)
- s->max_payload_length = amdtp_stream_get_max_payload(s);
+ if (s->direction == AMDTP_IN_STREAM) {
+ s->ctx_data.tx.max_ctx_payload_length = max_ctx_payload_size;
+ s->ctx_data.tx.ctx_header_size = ctx_header_size;
+ }
if (s->flags & CIP_NO_HEADER)
s->tag = TAG_NO_CIP_HEADER;
@@ -908,10 +934,14 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
s->packet_index = 0;
do {
- if (s->direction == AMDTP_IN_STREAM)
- err = queue_in_packet(s);
- else
- err = queue_out_packet(s, 0);
+ struct fw_iso_packet params;
+ if (s->direction == AMDTP_IN_STREAM) {
+ err = queue_in_packet(s, &params);
+ } else {
+ params.header_length = 0;
+ params.payload_length = 0;
+ err = queue_out_packet(s, &params);
+ }
if (err < 0)
goto err_context;
} while (s->packet_index > 0);
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index e45de3eecfe3..3942894c11ac 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -108,10 +108,31 @@ struct amdtp_stream {
struct iso_packets_buffer buffer;
int packet_index;
int tag;
- int (*handle_packet)(struct amdtp_stream *s,
- unsigned int payload_quadlets, unsigned int cycle,
- unsigned int index);
- unsigned int max_payload_length;
+ union {
+ struct {
+ unsigned int ctx_header_size;
+
+ // limit for payload of iso packet.
+ unsigned int max_ctx_payload_length;
+
+ // For quirks of CIP headers.
+ // Fixed interval of dbc between previos/current
+ // packets.
+ unsigned int dbc_interval;
+ // Indicate the value of dbc field in a first packet.
+ unsigned int first_dbc;
+ } tx;
+ struct {
+ // To calculate CIP data blocks and tstamp.
+ unsigned int transfer_delay;
+ unsigned int data_block_state;
+ unsigned int last_syt_offset;
+ unsigned int syt_offset_state;
+
+ // To generate CIP header.
+ unsigned int fdf;
+ } rx;
+ } ctx_data;
/* For CIP headers. */
unsigned int source_node_id_field;
@@ -119,19 +140,10 @@ struct amdtp_stream {
unsigned int data_block_counter;
unsigned int sph;
unsigned int fmt;
- unsigned int fdf;
- /* quirk: fixed interval of dbc between previos/current packets. */
- unsigned int tx_dbc_interval;
- /* quirk: indicate the value of dbc field in a first packet. */
- unsigned int tx_first_dbc;
/* Internal flags. */
enum cip_sfc sfc;
unsigned int syt_interval;
- unsigned int transfer_delay;
- unsigned int data_block_state;
- unsigned int last_syt_offset;
- unsigned int syt_offset_state;
/* For a PCM substream processing. */
struct snd_pcm_substream *pcm;
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index af71dac9f084..9e0b689fe34a 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -92,8 +92,6 @@ struct snd_bebob {
unsigned int midi_input_ports;
unsigned int midi_output_ports;
- bool connected;
-
struct amdtp_stream tx_stream;
struct amdtp_stream rx_stream;
struct cmp_connection out_conn;
@@ -217,7 +215,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
enum snd_bebob_clock_type *src);
int snd_bebob_stream_discover(struct snd_bebob *bebob);
int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
-int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate);
+int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate);
+int snd_bebob_stream_start_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c
index c54ac42622ad..4d8805fa8a00 100644
--- a/sound/firewire/bebob/bebob_midi.c
+++ b/sound/firewire/bebob/bebob_midi.c
@@ -7,58 +7,31 @@
#include "bebob.h"
-static int midi_capture_open(struct snd_rawmidi_substream *substream)
+static int midi_open(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
int err;
err = snd_bebob_stream_lock_try(bebob);
if (err < 0)
- goto end;
+ return err;
mutex_lock(&bebob->mutex);
- bebob->substreams_counter++;
- err = snd_bebob_stream_start_duplex(bebob, 0);
+ err = snd_bebob_stream_reserve_duplex(bebob, 0);
+ if (err >= 0) {
+ ++bebob->substreams_counter;
+ err = snd_bebob_stream_start_duplex(bebob);
+ if (err < 0)
+ --bebob->substreams_counter;
+ }
mutex_unlock(&bebob->mutex);
if (err < 0)
snd_bebob_stream_lock_release(bebob);
-end:
- return err;
-}
-
-static int midi_playback_open(struct snd_rawmidi_substream *substream)
-{
- struct snd_bebob *bebob = substream->rmidi->private_data;
- int err;
-
- err = snd_bebob_stream_lock_try(bebob);
- if (err < 0)
- goto end;
- mutex_lock(&bebob->mutex);
- bebob->substreams_counter++;
- err = snd_bebob_stream_start_duplex(bebob, 0);
- mutex_unlock(&bebob->mutex);
- if (err < 0)
- snd_bebob_stream_lock_release(bebob);
-end:
return err;
}
-static int midi_capture_close(struct snd_rawmidi_substream *substream)
-{
- struct snd_bebob *bebob = substream->rmidi->private_data;
-
- mutex_lock(&bebob->mutex);
- bebob->substreams_counter--;
- snd_bebob_stream_stop_duplex(bebob);
- mutex_unlock(&bebob->mutex);
-
- snd_bebob_stream_lock_release(bebob);
- return 0;
-}
-
-static int midi_playback_close(struct snd_rawmidi_substream *substream)
+static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
@@ -120,13 +93,13 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
{
static const struct snd_rawmidi_ops capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
+ .open = midi_open,
+ .close = midi_close,
.trigger = midi_capture_trigger,
};
static const struct snd_rawmidi_ops playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
+ .open = midi_open,
+ .close = midi_close,
.trigger = midi_playback_trigger,
};
struct snd_rawmidi *rmidi;
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index 2f50ec7b0147..0fb9eed46837 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -184,9 +184,8 @@ pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int
-pcm_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_bebob *bebob = substream->private_data;
int err;
@@ -197,62 +196,31 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&bebob->mutex);
- bebob->substreams_counter++;
- mutex_unlock(&bebob->mutex);
- }
+ unsigned int rate = params_rate(hw_params);
- return 0;
-}
-static int
-pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_bebob *bebob = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
-
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
- bebob->substreams_counter++;
+ err = snd_bebob_stream_reserve_duplex(bebob, rate);
+ if (err >= 0)
+ ++bebob->substreams_counter;
mutex_unlock(&bebob->mutex);
}
- return 0;
+ return err;
}
-static int
-pcm_capture_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&bebob->mutex);
- bebob->substreams_counter--;
- mutex_unlock(&bebob->mutex);
- }
-
- snd_bebob_stream_stop_duplex(bebob);
+ mutex_lock(&bebob->mutex);
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-static int
-pcm_playback_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_bebob *bebob = substream->private_data;
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&bebob->mutex);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
bebob->substreams_counter--;
- mutex_unlock(&bebob->mutex);
- }
snd_bebob_stream_stop_duplex(bebob);
+ mutex_unlock(&bebob->mutex);
+
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
@@ -260,10 +228,9 @@ static int
pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
+ err = snd_bebob_stream_start_duplex(bebob);
if (err >= 0)
amdtp_stream_pcm_prepare(&bebob->tx_stream);
@@ -273,10 +240,9 @@ static int
pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
+ err = snd_bebob_stream_start_duplex(bebob);
if (err >= 0)
amdtp_stream_pcm_prepare(&bebob->rx_stream);
@@ -353,8 +319,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
@@ -365,8 +331,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index 0c93a825cb98..334dc7c96e1d 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -376,24 +376,6 @@ end:
}
static int
-init_both_connections(struct snd_bebob *bebob)
-{
- int err;
-
- err = cmp_connection_init(&bebob->in_conn,
- bebob->unit, CMP_INPUT, 0);
- if (err < 0)
- goto end;
-
- err = cmp_connection_init(&bebob->out_conn,
- bebob->unit, CMP_OUTPUT, 0);
- if (err < 0)
- cmp_connection_destroy(&bebob->in_conn);
-end:
- return err;
-}
-
-static int
check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
{
struct cmp_connection *conn;
@@ -417,49 +399,21 @@ check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
return err;
}
-static int
-make_both_connections(struct snd_bebob *bebob, unsigned int rate)
+static int make_both_connections(struct snd_bebob *bebob)
{
- int index, pcm_channels, midi_channels, err = 0;
-
- if (bebob->connected)
- goto end;
-
- /* confirm params for both streams */
- err = get_formation_index(rate, &index);
- if (err < 0)
- goto end;
- pcm_channels = bebob->tx_stream_formations[index].pcm;
- midi_channels = bebob->tx_stream_formations[index].midi;
- err = amdtp_am824_set_parameters(&bebob->tx_stream, rate,
- pcm_channels, midi_channels * 8,
- false);
- if (err < 0)
- goto end;
+ int err = 0;
- pcm_channels = bebob->rx_stream_formations[index].pcm;
- midi_channels = bebob->rx_stream_formations[index].midi;
- err = amdtp_am824_set_parameters(&bebob->rx_stream, rate,
- pcm_channels, midi_channels * 8,
- false);
+ err = cmp_connection_establish(&bebob->out_conn);
if (err < 0)
- goto end;
+ return err;
- /* establish connections for both streams */
- err = cmp_connection_establish(&bebob->out_conn,
- amdtp_stream_get_max_payload(&bebob->tx_stream));
- if (err < 0)
- goto end;
- err = cmp_connection_establish(&bebob->in_conn,
- amdtp_stream_get_max_payload(&bebob->rx_stream));
+ err = cmp_connection_establish(&bebob->in_conn);
if (err < 0) {
cmp_connection_break(&bebob->out_conn);
- goto end;
+ return err;
}
- bebob->connected = true;
-end:
- return err;
+ return 0;
}
static void
@@ -468,23 +422,13 @@ break_both_connections(struct snd_bebob *bebob)
cmp_connection_break(&bebob->in_conn);
cmp_connection_break(&bebob->out_conn);
- bebob->connected = false;
-
/* These models seems to be in transition state for a longer time. */
if (bebob->maudio_special_quirk != NULL)
msleep(200);
}
-static void
-destroy_both_connections(struct snd_bebob *bebob)
-{
- cmp_connection_destroy(&bebob->in_conn);
- cmp_connection_destroy(&bebob->out_conn);
-}
-
static int
-start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream,
- unsigned int rate)
+start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
{
struct cmp_connection *conn;
int err = 0;
@@ -509,190 +453,252 @@ end:
return err;
}
-int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
+static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
{
+ enum amdtp_stream_direction dir_stream;
+ struct cmp_connection *conn;
+ enum cmp_direction dir_conn;
int err;
- err = init_both_connections(bebob);
+ if (stream == &bebob->tx_stream) {
+ dir_stream = AMDTP_IN_STREAM;
+ conn = &bebob->out_conn;
+ dir_conn = CMP_OUTPUT;
+ } else {
+ dir_stream = AMDTP_OUT_STREAM;
+ conn = &bebob->in_conn;
+ dir_conn = CMP_INPUT;
+ }
+
+ err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
if (err < 0)
- goto end;
+ return err;
- err = amdtp_am824_init(&bebob->tx_stream, bebob->unit,
- AMDTP_IN_STREAM, CIP_BLOCKING);
+ err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING);
if (err < 0) {
- amdtp_stream_destroy(&bebob->tx_stream);
- destroy_both_connections(bebob);
- goto end;
+ cmp_connection_destroy(conn);
+ return err;
}
- /*
- * BeBoB v3 transfers packets with these qurks:
- * - In the beginning of streaming, the value of dbc is incremented
- * even if no data blocks are transferred.
- * - The value of dbc is reset suddenly.
- */
- if (bebob->version > 2)
- bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
- CIP_SKIP_DBC_ZERO_CHECK;
+ if (stream == &bebob->tx_stream) {
+ // BeBoB v3 transfers packets with these qurks:
+ // - In the beginning of streaming, the value of dbc is
+ // incremented even if no data blocks are transferred.
+ // - The value of dbc is reset suddenly.
+ if (bebob->version > 2)
+ bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
+ CIP_SKIP_DBC_ZERO_CHECK;
+
+ // At high sampling rate, M-Audio special firmware transmits
+ // empty packet with the value of dbc incremented by 8 but the
+ // others are valid to IEC 61883-1.
+ if (bebob->maudio_special_quirk)
+ bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
+ }
- /*
- * At high sampling rate, M-Audio special firmware transmits empty
- * packet with the value of dbc incremented by 8 but the others are
- * valid to IEC 61883-1.
- */
- if (bebob->maudio_special_quirk)
- bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
+ return 0;
+}
+
+static void destroy_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
+{
+ amdtp_stream_destroy(stream);
+
+ if (stream == &bebob->tx_stream)
+ cmp_connection_destroy(&bebob->out_conn);
+ else
+ cmp_connection_destroy(&bebob->in_conn);
+}
+
+int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
+{
+ int err;
- err = amdtp_am824_init(&bebob->rx_stream, bebob->unit,
- AMDTP_OUT_STREAM, CIP_BLOCKING);
+ err = init_stream(bebob, &bebob->tx_stream);
+ if (err < 0)
+ return err;
+
+ err = init_stream(bebob, &bebob->rx_stream);
if (err < 0) {
- amdtp_stream_destroy(&bebob->tx_stream);
- amdtp_stream_destroy(&bebob->rx_stream);
- destroy_both_connections(bebob);
+ destroy_stream(bebob, &bebob->tx_stream);
+ return err;
}
-end:
- return err;
+
+ return 0;
}
-int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
+static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
+ unsigned int rate, unsigned int index)
{
- const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
- unsigned int curr_rate;
- int err = 0;
+ struct snd_bebob_stream_formation *formation;
+ struct cmp_connection *conn;
+ int err;
- /* Need no substreams */
- if (bebob->substreams_counter == 0)
- goto end;
+ if (stream == &bebob->tx_stream) {
+ formation = bebob->tx_stream_formations + index;
+ conn = &bebob->out_conn;
+ } else {
+ formation = bebob->rx_stream_formations + index;
+ conn = &bebob->in_conn;
+ }
- /*
- * Considering JACK/FFADO streaming:
- * TODO: This can be removed hwdep functionality becomes popular.
- */
+ err = amdtp_am824_set_parameters(stream, rate, formation->pcm,
+ formation->midi, false);
+ if (err < 0)
+ return err;
+
+ return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
+{
+ unsigned int curr_rate;
+ int err;
+
+ // Considering JACK/FFADO streaming:
+ // TODO: This can be removed hwdep functionality becomes popular.
err = check_connection_used_by_others(bebob, &bebob->rx_stream);
if (err < 0)
- goto end;
+ return err;
- /*
- * packet queueing error or detecting discontinuity
- *
- * At bus reset, connections should not be broken here. So streams need
- * to be re-started. This is a reason to use SKIP_INIT_DBC_CHECK flag.
- */
- if (amdtp_streaming_error(&bebob->rx_stream))
- amdtp_stream_stop(&bebob->rx_stream);
- if (amdtp_streaming_error(&bebob->tx_stream))
+ err = bebob->spec->rate->get(bebob, &curr_rate);
+ if (err < 0)
+ return err;
+ if (rate == 0)
+ rate = curr_rate;
+ if (curr_rate != rate) {
amdtp_stream_stop(&bebob->tx_stream);
- if (!amdtp_stream_running(&bebob->rx_stream) &&
- !amdtp_stream_running(&bebob->tx_stream))
+ amdtp_stream_stop(&bebob->rx_stream);
+
break_both_connections(bebob);
- /* stop streams if rate is different */
- err = rate_spec->get(bebob, &curr_rate);
- if (err < 0) {
- dev_err(&bebob->unit->device,
- "fail to get sampling rate: %d\n", err);
- goto end;
+ cmp_connection_release(&bebob->out_conn);
+ cmp_connection_release(&bebob->in_conn);
}
- if (rate == 0)
- rate = curr_rate;
- if (rate != curr_rate) {
+
+ if (bebob->substreams_counter == 0 || curr_rate != rate) {
+ unsigned int index;
+
+ // NOTE:
+ // If establishing connections at first, Yamaha GO46
+ // (and maybe Terratec X24) don't generate sound.
+ //
+ // For firmware customized by M-Audio, refer to next NOTE.
+ err = bebob->spec->rate->set(bebob, rate);
+ if (err < 0) {
+ dev_err(&bebob->unit->device,
+ "fail to set sampling rate: %d\n",
+ err);
+ return err;
+ }
+
+ err = get_formation_index(rate, &index);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(bebob, &bebob->tx_stream, rate, index);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(bebob, &bebob->rx_stream, rate, index);
+ if (err < 0) {
+ cmp_connection_release(&bebob->out_conn);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
+{
+ int err;
+
+ // Need no substreams.
+ if (bebob->substreams_counter == 0)
+ return -EIO;
+
+ // packet queueing error or detecting discontinuity
+ if (amdtp_streaming_error(&bebob->rx_stream) ||
+ amdtp_streaming_error(&bebob->tx_stream)) {
amdtp_stream_stop(&bebob->rx_stream);
amdtp_stream_stop(&bebob->tx_stream);
+
break_both_connections(bebob);
}
- /* master should be always running */
if (!amdtp_stream_running(&bebob->rx_stream)) {
- /*
- * NOTE:
- * If establishing connections at first, Yamaha GO46
- * (and maybe Terratec X24) don't generate sound.
- *
- * For firmware customized by M-Audio, refer to next NOTE.
- */
- if (bebob->maudio_special_quirk == NULL) {
- err = rate_spec->set(bebob, rate);
- if (err < 0) {
- dev_err(&bebob->unit->device,
- "fail to set sampling rate: %d\n",
- err);
- goto end;
- }
+ unsigned int curr_rate;
+
+ if (bebob->maudio_special_quirk) {
+ err = bebob->spec->rate->get(bebob, &curr_rate);
+ if (err < 0)
+ return err;
}
- err = make_both_connections(bebob, rate);
+ err = make_both_connections(bebob);
if (err < 0)
- goto end;
+ return err;
- err = start_stream(bebob, &bebob->rx_stream, rate);
+ err = start_stream(bebob, &bebob->rx_stream);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to run AMDTP master stream:%d\n", err);
- break_both_connections(bebob);
- goto end;
+ goto error;
}
- /*
- * NOTE:
- * The firmware customized by M-Audio uses these commands to
- * start transmitting stream. This is not usual way.
- */
- if (bebob->maudio_special_quirk != NULL) {
- err = rate_spec->set(bebob, rate);
+ // NOTE:
+ // The firmware customized by M-Audio uses these commands to
+ // start transmitting stream. This is not usual way.
+ if (bebob->maudio_special_quirk) {
+ err = bebob->spec->rate->set(bebob, curr_rate);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to ensure sampling rate: %d\n",
err);
- amdtp_stream_stop(&bebob->rx_stream);
- break_both_connections(bebob);
- goto end;
+ goto error;
}
}
- /* wait first callback */
if (!amdtp_stream_wait_callback(&bebob->rx_stream,
CALLBACK_TIMEOUT)) {
- amdtp_stream_stop(&bebob->rx_stream);
- break_both_connections(bebob);
err = -ETIMEDOUT;
- goto end;
+ goto error;
}
}
- /* start slave if needed */
if (!amdtp_stream_running(&bebob->tx_stream)) {
- err = start_stream(bebob, &bebob->tx_stream, rate);
+ err = start_stream(bebob, &bebob->tx_stream);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to run AMDTP slave stream:%d\n", err);
- amdtp_stream_stop(&bebob->rx_stream);
- break_both_connections(bebob);
- goto end;
+ goto error;
}
- /* wait first callback */
if (!amdtp_stream_wait_callback(&bebob->tx_stream,
CALLBACK_TIMEOUT)) {
- amdtp_stream_stop(&bebob->tx_stream);
- amdtp_stream_stop(&bebob->rx_stream);
- break_both_connections(bebob);
err = -ETIMEDOUT;
+ goto error;
}
}
-end:
+
+ return 0;
+error:
+ amdtp_stream_stop(&bebob->tx_stream);
+ amdtp_stream_stop(&bebob->rx_stream);
+ break_both_connections(bebob);
return err;
}
void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
{
if (bebob->substreams_counter == 0) {
- amdtp_stream_pcm_abort(&bebob->rx_stream);
amdtp_stream_stop(&bebob->rx_stream);
-
- amdtp_stream_pcm_abort(&bebob->tx_stream);
amdtp_stream_stop(&bebob->tx_stream);
break_both_connections(bebob);
+
+ cmp_connection_release(&bebob->out_conn);
+ cmp_connection_release(&bebob->in_conn);
}
}
@@ -702,10 +708,8 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
*/
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
{
- amdtp_stream_destroy(&bebob->rx_stream);
- amdtp_stream_destroy(&bebob->tx_stream);
-
- destroy_both_connections(bebob);
+ destroy_stream(bebob, &bebob->tx_stream);
+ destroy_stream(bebob, &bebob->rx_stream);
}
/*
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index 13f8abc19cfb..14abbe7175b6 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -185,6 +185,37 @@ void cmp_connection_destroy(struct cmp_connection *c)
}
EXPORT_SYMBOL(cmp_connection_destroy);
+int cmp_connection_reserve(struct cmp_connection *c,
+ unsigned int max_payload_bytes)
+{
+ int err;
+
+ mutex_lock(&c->mutex);
+
+ if (WARN_ON(c->resources.allocated)) {
+ err = -EBUSY;
+ goto end;
+ }
+
+ c->speed = min(c->max_speed,
+ fw_parent_device(c->resources.unit)->max_speed);
+
+ err = fw_iso_resources_allocate(&c->resources, max_payload_bytes,
+ c->speed);
+end:
+ mutex_unlock(&c->mutex);
+
+ return err;
+}
+EXPORT_SYMBOL(cmp_connection_reserve);
+
+void cmp_connection_release(struct cmp_connection *c)
+{
+ mutex_lock(&c->mutex);
+ fw_iso_resources_free(&c->resources);
+ mutex_unlock(&c->mutex);
+}
+EXPORT_SYMBOL(cmp_connection_release);
static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr)
{
@@ -270,25 +301,18 @@ static int pcr_set_check(struct cmp_connection *c, __be32 pcr)
* When this function succeeds, the caller is responsible for starting
* transmitting packets.
*/
-int cmp_connection_establish(struct cmp_connection *c,
- unsigned int max_payload_bytes)
+int cmp_connection_establish(struct cmp_connection *c)
{
int err;
- if (WARN_ON(c->connected))
- return -EISCONN;
-
- c->speed = min(c->max_speed,
- fw_parent_device(c->resources.unit)->max_speed);
-
mutex_lock(&c->mutex);
-retry_after_bus_reset:
- err = fw_iso_resources_allocate(&c->resources,
- max_payload_bytes, c->speed);
- if (err < 0)
- goto err_mutex;
+ if (WARN_ON(c->connected)) {
+ mutex_unlock(&c->mutex);
+ return -EISCONN;
+ }
+retry_after_bus_reset:
if (c->direction == CMP_OUTPUT)
err = pcr_modify(c, opcr_set_modify, pcr_set_check,
ABORT_ON_BUS_RESET);
@@ -297,21 +321,13 @@ retry_after_bus_reset:
ABORT_ON_BUS_RESET);
if (err == -EAGAIN) {
- fw_iso_resources_free(&c->resources);
- goto retry_after_bus_reset;
+ err = fw_iso_resources_update(&c->resources);
+ if (err >= 0)
+ goto retry_after_bus_reset;
}
- if (err < 0)
- goto err_resources;
-
- c->connected = true;
-
- mutex_unlock(&c->mutex);
-
- return 0;
+ if (err >= 0)
+ c->connected = true;
-err_resources:
- fw_iso_resources_free(&c->resources);
-err_mutex:
mutex_unlock(&c->mutex);
return err;
@@ -351,14 +367,12 @@ int cmp_connection_update(struct cmp_connection *c)
SUCCEED_ON_BUS_RESET);
if (err < 0)
- goto err_resources;
+ goto err_unconnect;
mutex_unlock(&c->mutex);
return 0;
-err_resources:
- fw_iso_resources_free(&c->resources);
err_unconnect:
c->connected = false;
mutex_unlock(&c->mutex);
@@ -395,8 +409,6 @@ void cmp_connection_break(struct cmp_connection *c)
if (err < 0)
cmp_error(c, "plug is still connected\n");
- fw_iso_resources_free(&c->resources);
-
c->connected = false;
mutex_unlock(&c->mutex);
diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h
index b60b415caa8f..26ab88000e34 100644
--- a/sound/firewire/cmp.h
+++ b/sound/firewire/cmp.h
@@ -42,8 +42,11 @@ int cmp_connection_init(struct cmp_connection *connection,
int cmp_connection_check_used(struct cmp_connection *connection, bool *used);
void cmp_connection_destroy(struct cmp_connection *connection);
-int cmp_connection_establish(struct cmp_connection *connection,
- unsigned int max_payload);
+int cmp_connection_reserve(struct cmp_connection *connection,
+ unsigned int max_payload);
+void cmp_connection_release(struct cmp_connection *connection);
+
+int cmp_connection_establish(struct cmp_connection *connection);
int cmp_connection_update(struct cmp_connection *connection);
void cmp_connection_break(struct cmp_connection *connection);
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile
index 115eadd8d42e..7a62dafd0f78 100644
--- a/sound/firewire/dice/Makefile
+++ b/sound/firewire/dice/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
- dice-alesis.o dice-extension.o dice-mytek.o
+ dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o
obj-$(CONFIG_SND_DICE) += snd-dice.o
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
index ca7ae427e892..c9e19bddfc09 100644
--- a/sound/firewire/dice/dice-midi.c
+++ b/sound/firewire/dice/dice-midi.c
@@ -17,8 +17,13 @@ static int midi_open(struct snd_rawmidi_substream *substream)
mutex_lock(&dice->mutex);
- dice->substreams_counter++;
- err = snd_dice_stream_start_duplex(dice, 0);
+ err = snd_dice_stream_reserve_duplex(dice, 0);
+ if (err >= 0) {
+ ++dice->substreams_counter;
+ err = snd_dice_stream_start_duplex(dice);
+ if (err < 0)
+ --dice->substreams_counter;
+ }
mutex_unlock(&dice->mutex);
@@ -34,7 +39,7 @@ static int midi_close(struct snd_rawmidi_substream *substream)
mutex_lock(&dice->mutex);
- dice->substreams_counter--;
+ --dice->substreams_counter;
snd_dice_stream_stop_duplex(dice);
mutex_unlock(&dice->mutex);
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 8a601befc11e..94a4dccfc381 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -230,8 +230,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_dice *dice = substream->private_data;
int err;
@@ -242,57 +242,26 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&dice->mutex);
- dice->substreams_counter++;
- mutex_unlock(&dice->mutex);
- }
-
- return 0;
-}
-static int playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_dice *dice = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
+ unsigned int rate = params_rate(hw_params);
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&dice->mutex);
- dice->substreams_counter++;
+ err = snd_dice_stream_reserve_duplex(dice, rate);
+ if (err >= 0)
+ ++dice->substreams_counter;
mutex_unlock(&dice->mutex);
}
- return 0;
-}
-
-static int capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_dice *dice = substream->private_data;
-
- mutex_lock(&dice->mutex);
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dice->substreams_counter--;
-
- snd_dice_stream_stop_duplex(dice);
-
- mutex_unlock(&dice->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ return err;
}
-static int playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
mutex_lock(&dice->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dice->substreams_counter--;
+ --dice->substreams_counter;
snd_dice_stream_stop_duplex(dice);
@@ -308,7 +277,7 @@ static int capture_prepare(struct snd_pcm_substream *substream)
int err;
mutex_lock(&dice->mutex);
- err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+ err = snd_dice_stream_start_duplex(dice);
mutex_unlock(&dice->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(stream);
@@ -322,7 +291,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
int err;
mutex_lock(&dice->mutex);
- err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+ err = snd_dice_stream_start_duplex(dice);
mutex_unlock(&dice->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(stream);
@@ -404,8 +373,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = capture_hw_params,
- .hw_free = capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = capture_prepare,
.trigger = capture_trigger,
.pointer = capture_pointer,
@@ -416,8 +385,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = playback_hw_params,
- .hw_free = playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = playback_prepare,
.trigger = playback_trigger,
.pointer = playback_pointer,
diff --git a/sound/firewire/dice/dice-presonus.c b/sound/firewire/dice/dice-presonus.c
new file mode 100644
index 000000000000..503f462a83f4
--- /dev/null
+++ b/sound/firewire/dice/dice-presonus.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+// dice-presonus.c - a part of driver for DICE based devices
+//
+// Copyright (c) 2019 Takashi Sakamoto
+//
+// Licensed under the terms of the GNU General Public License, version 2.
+
+#include "dice.h"
+
+struct dice_presonus_spec {
+ unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+ unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+ bool has_midi;
+};
+
+static const struct dice_presonus_spec dice_presonus_firesutio = {
+ .tx_pcm_chs = {{16, 16, 0}, {10, 2, 0} },
+ .rx_pcm_chs = {{16, 16, 0}, {10, 2, 0} },
+ .has_midi = true,
+};
+
+int snd_dice_detect_presonus_formats(struct snd_dice *dice)
+{
+ static const struct {
+ u32 model_id;
+ const struct dice_presonus_spec *spec;
+ } *entry, entries[] = {
+ {0x000008, &dice_presonus_firesutio},
+ };
+ struct fw_csr_iterator it;
+ int key, val, model_id;
+ int i;
+
+ model_id = 0;
+ fw_csr_iterator_init(&it, dice->unit->directory);
+ while (fw_csr_iterator_next(&it, &key, &val)) {
+ if (key == CSR_MODEL) {
+ model_id = val;
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i) {
+ entry = entries + i;
+ if (entry->model_id == model_id)
+ break;
+ }
+ if (i == ARRAY_SIZE(entries))
+ return -ENODEV;
+
+ memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs,
+ MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+ memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs,
+ MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+
+ if (entry->spec->has_midi) {
+ dice->tx_midi_ports[0] = 1;
+ dice->rx_midi_ports[0] = 1;
+ }
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index 7a93ae3dc58b..a9f0c77734c3 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -137,18 +137,9 @@ static int get_register_params(struct snd_dice *dice,
static void release_resources(struct snd_dice *dice)
{
- unsigned int i;
-
- for (i = 0; i < MAX_STREAMS; i++) {
- if (amdtp_stream_running(&dice->tx_stream[i])) {
- amdtp_stream_pcm_abort(&dice->tx_stream[i]);
- amdtp_stream_stop(&dice->tx_stream[i]);
- }
- if (amdtp_stream_running(&dice->rx_stream[i])) {
- amdtp_stream_pcm_abort(&dice->rx_stream[i]);
- amdtp_stream_stop(&dice->rx_stream[i]);
- }
+ int i;
+ for (i = 0; i < MAX_STREAMS; ++i) {
fw_iso_resources_free(&dice->tx_resources[i]);
fw_iso_resources_free(&dice->rx_resources[i]);
}
@@ -163,10 +154,14 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
for (i = 0; i < params->count; i++) {
reg = cpu_to_be32((u32)-1);
if (dir == AMDTP_IN_STREAM) {
+ amdtp_stream_stop(&dice->tx_stream[i]);
+
snd_dice_transaction_write_tx(dice,
params->size * i + TX_ISOCHRONOUS,
&reg, sizeof(reg));
} else {
+ amdtp_stream_stop(&dice->rx_stream[i]);
+
snd_dice_transaction_write_rx(dice,
params->size * i + RX_ISOCHRONOUS,
&reg, sizeof(reg));
@@ -174,35 +169,22 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
}
}
-static int keep_resources(struct snd_dice *dice,
- enum amdtp_stream_direction dir, unsigned int index,
- unsigned int rate, unsigned int pcm_chs,
- unsigned int midi_ports)
+static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
+ struct fw_iso_resources *resources, unsigned int rate,
+ unsigned int pcm_chs, unsigned int midi_ports)
{
- struct amdtp_stream *stream;
- struct fw_iso_resources *resources;
bool double_pcm_frames;
unsigned int i;
int err;
- if (dir == AMDTP_IN_STREAM) {
- stream = &dice->tx_stream[index];
- resources = &dice->tx_resources[index];
- } else {
- stream = &dice->rx_stream[index];
- resources = &dice->rx_resources[index];
- }
-
- /*
- * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
- * one data block of AMDTP packet. Thus sampling transfer frequency is
- * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
- * transferred on AMDTP packets at 96 kHz. Two successive samples of a
- * channel are stored consecutively in the packet. This quirk is called
- * as 'Dual Wire'.
- * For this quirk, blocking mode is required and PCM buffer size should
- * be aligned to SYT_INTERVAL.
- */
+ // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
+ // one data block of AMDTP packet. Thus sampling transfer frequency is
+ // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
+ // transferred on AMDTP packets at 96 kHz. Two successive samples of a
+ // channel are stored consecutively in the packet. This quirk is called
+ // as 'Dual Wire'.
+ // For this quirk, blocking mode is required and PCM buffer size should
+ // be aligned to SYT_INTERVAL.
double_pcm_frames = rate > 96000;
if (double_pcm_frames) {
rate /= 2;
@@ -229,40 +211,40 @@ static int keep_resources(struct snd_dice *dice,
fw_parent_device(dice->unit)->max_speed);
}
-static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
- unsigned int rate, struct reg_params *params)
+static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
+ enum amdtp_stream_direction dir,
+ struct reg_params *params)
{
- __be32 reg[2];
enum snd_dice_rate_mode mode;
- unsigned int i, pcm_chs, midi_ports;
- struct amdtp_stream *streams;
- struct fw_iso_resources *resources;
- struct fw_device *fw_dev = fw_parent_device(dice->unit);
- int err = 0;
-
- if (dir == AMDTP_IN_STREAM) {
- streams = dice->tx_stream;
- resources = dice->tx_resources;
- } else {
- streams = dice->rx_stream;
- resources = dice->rx_resources;
- }
+ int i;
+ int err;
err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
if (err < 0)
return err;
- for (i = 0; i < params->count; i++) {
+ for (i = 0; i < params->count; ++i) {
+ __be32 reg[2];
+ struct amdtp_stream *stream;
+ struct fw_iso_resources *resources;
unsigned int pcm_cache;
unsigned int midi_cache;
+ unsigned int pcm_chs;
+ unsigned int midi_ports;
if (dir == AMDTP_IN_STREAM) {
+ stream = &dice->tx_stream[i];
+ resources = &dice->tx_resources[i];
+
pcm_cache = dice->tx_pcm_chs[i][mode];
midi_cache = dice->tx_midi_ports[i];
err = snd_dice_transaction_read_tx(dice,
params->size * i + TX_NUMBER_AUDIO,
reg, sizeof(reg));
} else {
+ stream = &dice->rx_stream[i];
+ resources = &dice->rx_resources[i];
+
pcm_cache = dice->rx_pcm_chs[i][mode];
midi_cache = dice->rx_midi_ports[i];
err = snd_dice_transaction_read_rx(dice,
@@ -274,7 +256,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
pcm_chs = be32_to_cpu(reg[0]);
midi_ports = be32_to_cpu(reg[1]);
- /* These are important for developer of this driver. */
+ // These are important for developer of this driver.
if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
dev_info(&dice->unit->device,
"cache mismatch: pcm: %u:%u, midi: %u:%u\n",
@@ -282,141 +264,170 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
return -EPROTO;
}
- err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports);
- if (err < 0)
- return err;
-
- reg[0] = cpu_to_be32(resources[i].channel);
- if (dir == AMDTP_IN_STREAM) {
- err = snd_dice_transaction_write_tx(dice,
- params->size * i + TX_ISOCHRONOUS,
- reg, sizeof(reg[0]));
- } else {
- err = snd_dice_transaction_write_rx(dice,
- params->size * i + RX_ISOCHRONOUS,
- reg, sizeof(reg[0]));
- }
+ err = keep_resources(dice, stream, resources, rate, pcm_chs,
+ midi_ports);
if (err < 0)
return err;
+ }
- if (dir == AMDTP_IN_STREAM) {
- reg[0] = cpu_to_be32(fw_dev->max_speed);
- err = snd_dice_transaction_write_tx(dice,
- params->size * i + TX_SPEED,
- reg, sizeof(reg[0]));
- if (err < 0)
- return err;
- }
+ return 0;
+}
- err = amdtp_stream_start(&streams[i], resources[i].channel,
- fw_dev->max_speed);
- if (err < 0)
- return err;
- }
+static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
+ struct reg_params *rx_params)
+{
+ stop_streams(dice, AMDTP_IN_STREAM, tx_params);
+ stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
- return err;
+ snd_dice_transaction_clear_enable(dice);
}
-static int start_duplex_streams(struct snd_dice *dice, unsigned int rate)
+int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate)
{
- struct reg_params tx_params, rx_params;
- int i;
+ unsigned int curr_rate;
int err;
- err = get_register_params(dice, &tx_params, &rx_params);
+ // Check sampling transmission frequency.
+ err = snd_dice_transaction_get_rate(dice, &curr_rate);
if (err < 0)
return err;
+ if (rate == 0)
+ rate = curr_rate;
- /* Stop transmission. */
- stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
- stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
- snd_dice_transaction_clear_enable(dice);
- release_resources(dice);
+ if (dice->substreams_counter == 0 || curr_rate != rate) {
+ struct reg_params tx_params, rx_params;
- err = ensure_phase_lock(dice, rate);
- if (err < 0) {
- dev_err(&dice->unit->device, "fail to ensure phase lock\n");
- return err;
- }
+ err = get_register_params(dice, &tx_params, &rx_params);
+ if (err < 0)
+ return err;
- /* Likely to have changed stream formats. */
- err = get_register_params(dice, &tx_params, &rx_params);
- if (err < 0)
- return err;
+ finish_session(dice, &tx_params, &rx_params);
- /* Start both streams. */
- err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
- if (err < 0)
- goto error;
- err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
- if (err < 0)
- goto error;
+ release_resources(dice);
- err = snd_dice_transaction_set_enable(dice);
- if (err < 0) {
- dev_err(&dice->unit->device, "fail to enable interface\n");
- goto error;
- }
+ // Just after owning the unit (GLOBAL_OWNER), the unit can
+ // return invalid stream formats. Selecting clock parameters
+ // have an effect for the unit to refine it.
+ err = ensure_phase_lock(dice, rate);
+ if (err < 0)
+ return err;
- for (i = 0; i < MAX_STREAMS; i++) {
- if ((i < tx_params.count &&
- !amdtp_stream_wait_callback(&dice->tx_stream[i],
- CALLBACK_TIMEOUT)) ||
- (i < rx_params.count &&
- !amdtp_stream_wait_callback(&dice->rx_stream[i],
- CALLBACK_TIMEOUT))) {
- err = -ETIMEDOUT;
+ // After changing sampling transfer frequency, the value of
+ // register can be changed.
+ err = get_register_params(dice, &tx_params, &rx_params);
+ if (err < 0)
+ return err;
+
+ err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
+ &tx_params);
+ if (err < 0)
+ goto error;
+
+ err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
+ &rx_params);
+ if (err < 0)
goto error;
- }
}
return 0;
error:
- stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
- stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
- snd_dice_transaction_clear_enable(dice);
release_resources(dice);
return err;
}
+static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
+ unsigned int rate, struct reg_params *params)
+{
+ unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
+ int i;
+ int err;
+
+ for (i = 0; i < params->count; i++) {
+ struct amdtp_stream *stream;
+ struct fw_iso_resources *resources;
+ __be32 reg;
+
+ if (dir == AMDTP_IN_STREAM) {
+ stream = dice->tx_stream + i;
+ resources = dice->tx_resources + i;
+ } else {
+ stream = dice->rx_stream + i;
+ resources = dice->rx_resources + i;
+ }
+
+ reg = cpu_to_be32(resources->channel);
+ if (dir == AMDTP_IN_STREAM) {
+ err = snd_dice_transaction_write_tx(dice,
+ params->size * i + TX_ISOCHRONOUS,
+ &reg, sizeof(reg));
+ } else {
+ err = snd_dice_transaction_write_rx(dice,
+ params->size * i + RX_ISOCHRONOUS,
+ &reg, sizeof(reg));
+ }
+ if (err < 0)
+ return err;
+
+ if (dir == AMDTP_IN_STREAM) {
+ reg = cpu_to_be32(max_speed);
+ err = snd_dice_transaction_write_tx(dice,
+ params->size * i + TX_SPEED,
+ &reg, sizeof(reg));
+ if (err < 0)
+ return err;
+ }
+
+ err = amdtp_stream_start(stream, resources->channel, max_speed);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
/*
* MEMO: After this function, there're two states of streams:
* - None streams are running.
* - All streams are running.
*/
-int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
+int snd_dice_stream_start_duplex(struct snd_dice *dice)
{
- unsigned int curr_rate;
+ unsigned int generation = dice->rx_resources[0].generation;
+ struct reg_params tx_params, rx_params;
unsigned int i;
+ unsigned int rate;
enum snd_dice_rate_mode mode;
int err;
if (dice->substreams_counter == 0)
return -EIO;
- /* Check sampling transmission frequency. */
- err = snd_dice_transaction_get_rate(dice, &curr_rate);
- if (err < 0) {
- dev_err(&dice->unit->device,
- "fail to get sampling rate\n");
+ err = get_register_params(dice, &tx_params, &rx_params);
+ if (err < 0)
return err;
- }
- if (rate == 0)
- rate = curr_rate;
- if (rate != curr_rate)
- goto restart;
- /* Check error of packet streaming. */
+ // Check error of packet streaming.
for (i = 0; i < MAX_STREAMS; ++i) {
- if (amdtp_streaming_error(&dice->tx_stream[i]))
- break;
- if (amdtp_streaming_error(&dice->rx_stream[i]))
+ if (amdtp_streaming_error(&dice->tx_stream[i]) ||
+ amdtp_streaming_error(&dice->rx_stream[i])) {
+ finish_session(dice, &tx_params, &rx_params);
break;
+ }
}
- if (i < MAX_STREAMS)
- goto restart;
- /* Check required streams are running or not. */
+ if (generation != fw_parent_device(dice->unit)->card->generation) {
+ for (i = 0; i < MAX_STREAMS; ++i) {
+ if (i < tx_params.count)
+ fw_iso_resources_update(dice->tx_resources + i);
+ if (i < rx_params.count)
+ fw_iso_resources_update(dice->rx_resources + i);
+ }
+ }
+
+ // Check required streams are running or not.
+ err = snd_dice_transaction_get_rate(dice, &rate);
+ if (err < 0)
+ return err;
err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
if (err < 0)
return err;
@@ -428,12 +439,40 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
!amdtp_stream_running(&dice->rx_stream[i]))
break;
}
- if (i < MAX_STREAMS)
- goto restart;
+ if (i < MAX_STREAMS) {
+ // Start both streams.
+ err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
+ if (err < 0)
+ goto error;
+
+ err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
+ if (err < 0)
+ goto error;
+
+ err = snd_dice_transaction_set_enable(dice);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to enable interface\n");
+ goto error;
+ }
+
+ for (i = 0; i < MAX_STREAMS; i++) {
+ if ((i < tx_params.count &&
+ !amdtp_stream_wait_callback(&dice->tx_stream[i],
+ CALLBACK_TIMEOUT)) ||
+ (i < rx_params.count &&
+ !amdtp_stream_wait_callback(&dice->rx_stream[i],
+ CALLBACK_TIMEOUT))) {
+ err = -ETIMEDOUT;
+ goto error;
+ }
+ }
+ }
return 0;
-restart:
- return start_duplex_streams(dice, rate);
+error:
+ finish_session(dice, &tx_params, &rx_params);
+ return err;
}
/*
@@ -445,17 +484,12 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice)
{
struct reg_params tx_params, rx_params;
- if (dice->substreams_counter > 0)
- return;
-
- snd_dice_transaction_clear_enable(dice);
+ if (dice->substreams_counter == 0) {
+ if (get_register_params(dice, &tx_params, &rx_params) >= 0)
+ finish_session(dice, &tx_params, &rx_params);
- if (get_register_params(dice, &tx_params, &rx_params) == 0) {
- stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
- stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
+ release_resources(dice);
}
-
- release_resources(dice);
}
static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index ea829cee9aaf..13eeb3f52bb6 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -19,6 +19,7 @@ MODULE_LICENSE("GPL v2");
#define OUI_MAUDIO 0x000d6c
#define OUI_MYTEK 0x001ee8
#define OUI_SSL 0x0050c2 // Actually ID reserved by IEEE.
+#define OUI_PRESONUS 0x000a92
#define DICE_CATEGORY_ID 0x04
#define WEISS_CATEGORY_ID 0x00
@@ -371,6 +372,14 @@ static const struct ieee1394_device_id dice_id_table[] = {
.vendor_id = OUI_SSL,
.model_id = 0x000070,
},
+ // Presonus FireStudio.
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_PRESONUS,
+ .model_id = 0x000008,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_presonus_formats,
+ },
{
.match_flags = IEEE1394_MATCH_VERSION,
.version = DICE_INTERFACE,
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index eb4fb8bae2ad..c6304e5e9fc4 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -204,10 +204,11 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
enum snd_dice_rate_mode *mode);
-int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
+int snd_dice_stream_start_duplex(struct snd_dice *dice);
void snd_dice_stream_stop_duplex(struct snd_dice *dice);
int snd_dice_stream_init_duplex(struct snd_dice *dice);
void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
+int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate);
void snd_dice_stream_update_duplex(struct snd_dice *dice);
int snd_dice_stream_detect_current_formats(struct snd_dice *dice);
@@ -226,5 +227,6 @@ int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice);
int snd_dice_detect_alesis_formats(struct snd_dice *dice);
int snd_dice_detect_extension_formats(struct snd_dice *dice);
int snd_dice_detect_mytek_formats(struct snd_dice *dice);
+int snd_dice_detect_presonus_formats(struct snd_dice *dice);
#endif
diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c
index 10c8803d7f19..45ff73d16074 100644
--- a/sound/firewire/digi00x/amdtp-dot.c
+++ b/sound/firewire/digi00x/amdtp-dot.c
@@ -127,7 +127,7 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
if (err < 0)
return err;
- s->fdf = AMDTP_FDF_AM824 | s->sfc;
+ s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
p->pcm_channels = pcm_channels;
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index bf50a168087f..2b57ece89101 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -17,8 +17,13 @@ static int midi_open(struct snd_rawmidi_substream *substream)
return err;
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
- err = snd_dg00x_stream_start_duplex(dg00x, 0);
+ err = snd_dg00x_stream_reserve_duplex(dg00x, 0);
+ if (err >= 0) {
+ ++dg00x->substreams_counter;
+ err = snd_dg00x_stream_start_duplex(dg00x);
+ if (err < 0)
+ --dg00x->substreams_counter;
+ }
mutex_unlock(&dg00x->mutex);
if (err < 0)
snd_dg00x_stream_lock_release(dg00x);
@@ -31,7 +36,7 @@ static int midi_close(struct snd_rawmidi_substream *substream)
struct snd_dg00x *dg00x = substream->rmidi->private_data;
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index 4f637f227513..18e561b26625 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -154,8 +154,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_dg00x *dg00x = substream->private_data;
int err;
@@ -166,58 +166,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
- mutex_unlock(&dg00x->mutex);
- }
+ unsigned int rate = params_rate(hw_params);
- return 0;
-}
-
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_dg00x *dg00x = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
-
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
+ err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
+ if (err >= 0)
+ ++dg00x->substreams_counter;
mutex_unlock(&dg00x->mutex);
}
- return 0;
-}
-
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_dg00x *dg00x = substream->private_data;
-
- mutex_lock(&dg00x->mutex);
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dg00x->substreams_counter--;
-
- snd_dg00x_stream_stop_duplex(dg00x);
-
- mutex_unlock(&dg00x->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ return err;
}
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
mutex_lock(&dg00x->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
@@ -229,12 +197,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+ err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0)
amdtp_stream_pcm_prepare(&dg00x->tx_stream);
@@ -246,12 +213,11 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+ err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0) {
amdtp_stream_pcm_prepare(&dg00x->rx_stream);
amdtp_dot_reset(&dg00x->rx_stream);
@@ -332,8 +298,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
@@ -344,8 +310,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
index ac8052c66b6f..3e77dbd3ee22 100644
--- a/sound/firewire/digi00x/digi00x-stream.c
+++ b/sound/firewire/digi00x/digi00x-stream.c
@@ -124,11 +124,25 @@ int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
static void finish_session(struct snd_dg00x *dg00x)
{
- __be32 data = cpu_to_be32(0x00000003);
+ __be32 data;
+
+ amdtp_stream_stop(&dg00x->tx_stream);
+ amdtp_stream_stop(&dg00x->rx_stream);
+ data = cpu_to_be32(0x00000003);
snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
&data, sizeof(data), 0);
+
+ // Unregister isochronous channels for both direction.
+ data = 0;
+ snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+ DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+ &data, sizeof(data), 0);
+
+ // Just after finishing the session, the device may lost transmitting
+ // functionality for a short time.
+ msleep(50);
}
static int begin_session(struct snd_dg00x *dg00x)
@@ -137,11 +151,20 @@ static int begin_session(struct snd_dg00x *dg00x)
u32 curr;
int err;
+ // Register isochronous channels for both direction.
+ data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
+ dg00x->rx_resources.channel);
+ err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+ DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+ &data, sizeof(data), 0);
+ if (err < 0)
+ return err;
+
err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
&data, sizeof(data), 0);
if (err < 0)
- goto error;
+ return err;
curr = be32_to_cpu(data);
if (curr == 0)
@@ -156,39 +179,23 @@ static int begin_session(struct snd_dg00x *dg00x)
DG00X_OFFSET_STREAMING_SET,
&data, sizeof(data), 0);
if (err < 0)
- goto error;
+ break;
msleep(20);
curr--;
}
- return 0;
-error:
- finish_session(dg00x);
return err;
}
-static void release_resources(struct snd_dg00x *dg00x)
+static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
+ unsigned int rate)
{
- __be32 data = 0;
-
- /* Unregister isochronous channels for both direction. */
- snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
- DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
- &data, sizeof(data), 0);
-
- /* Release isochronous resources. */
- fw_iso_resources_free(&dg00x->tx_resources);
- fw_iso_resources_free(&dg00x->rx_resources);
-}
-
-static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
-{
- unsigned int i;
- __be32 data;
+ struct fw_iso_resources *resources;
+ int i;
int err;
- /* Check sampling rate. */
+ // Check sampling rate.
for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
if (snd_dg00x_stream_rates[i] == rate)
break;
@@ -196,41 +203,19 @@ static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
if (i == SND_DG00X_RATE_COUNT)
return -EINVAL;
- /* Keep resources for out-stream. */
- err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate,
- snd_dg00x_stream_pcm_channels[i]);
- if (err < 0)
- return err;
- err = fw_iso_resources_allocate(&dg00x->rx_resources,
- amdtp_stream_get_max_payload(&dg00x->rx_stream),
- fw_parent_device(dg00x->unit)->max_speed);
- if (err < 0)
- return err;
+ if (stream == &dg00x->tx_stream)
+ resources = &dg00x->tx_resources;
+ else
+ resources = &dg00x->rx_resources;
- /* Keep resources for in-stream. */
- err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate,
+ err = amdtp_dot_set_parameters(stream, rate,
snd_dg00x_stream_pcm_channels[i]);
if (err < 0)
return err;
- err = fw_iso_resources_allocate(&dg00x->tx_resources,
- amdtp_stream_get_max_payload(&dg00x->tx_stream),
- fw_parent_device(dg00x->unit)->max_speed);
- if (err < 0)
- goto error;
- /* Register isochronous channels for both direction. */
- data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
- dg00x->rx_resources.channel);
- err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
- DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
- &data, sizeof(data), 0);
- if (err < 0)
- goto error;
-
- return 0;
-error:
- release_resources(dg00x);
- return err;
+ return fw_iso_resources_allocate(resources,
+ amdtp_stream_get_max_payload(stream),
+ fw_parent_device(dg00x->unit)->max_speed);
}
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
@@ -272,43 +257,68 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
fw_iso_resources_destroy(&dg00x->tx_resources);
}
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
{
unsigned int curr_rate;
- int err = 0;
-
- if (dg00x->substreams_counter == 0)
- goto end;
+ int err;
- /* Check current sampling rate. */
err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
if (err < 0)
- goto error;
+ return err;
if (rate == 0)
rate = curr_rate;
- if (curr_rate != rate ||
- amdtp_streaming_error(&dg00x->tx_stream) ||
- amdtp_streaming_error(&dg00x->rx_stream)) {
+
+ if (dg00x->substreams_counter == 0 || curr_rate != rate) {
finish_session(dg00x);
- amdtp_stream_stop(&dg00x->tx_stream);
- amdtp_stream_stop(&dg00x->rx_stream);
- release_resources(dg00x);
- }
+ fw_iso_resources_free(&dg00x->tx_resources);
+ fw_iso_resources_free(&dg00x->rx_resources);
- /*
- * No packets are transmitted without receiving packets, reagardless of
- * which source of clock is used.
- */
- if (!amdtp_stream_running(&dg00x->rx_stream)) {
err = snd_dg00x_stream_set_local_rate(dg00x, rate);
if (err < 0)
+ return err;
+
+ err = keep_resources(dg00x, &dg00x->rx_stream, rate);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(dg00x, &dg00x->tx_stream, rate);
+ if (err < 0) {
+ fw_iso_resources_free(&dg00x->rx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
+{
+ unsigned int generation = dg00x->rx_resources.generation;
+ int err = 0;
+
+ if (dg00x->substreams_counter == 0)
+ return 0;
+
+ if (amdtp_streaming_error(&dg00x->tx_stream) ||
+ amdtp_streaming_error(&dg00x->rx_stream))
+ finish_session(dg00x);
+
+ if (generation != fw_parent_device(dg00x->unit)->card->generation) {
+ err = fw_iso_resources_update(&dg00x->tx_resources);
+ if (err < 0)
goto error;
- err = keep_resources(dg00x, rate);
+ err = fw_iso_resources_update(&dg00x->rx_resources);
if (err < 0)
goto error;
+ }
+ /*
+ * No packets are transmitted without receiving packets, reagardless of
+ * which source of clock is used.
+ */
+ if (!amdtp_stream_running(&dg00x->rx_stream)) {
err = begin_session(dg00x);
if (err < 0)
goto error;
@@ -343,33 +353,22 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
goto error;
}
}
-end:
- return err;
+
+ return 0;
error:
finish_session(dg00x);
- amdtp_stream_stop(&dg00x->tx_stream);
- amdtp_stream_stop(&dg00x->rx_stream);
- release_resources(dg00x);
-
return err;
}
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
{
- if (dg00x->substreams_counter > 0)
- return;
-
- amdtp_stream_stop(&dg00x->tx_stream);
- amdtp_stream_stop(&dg00x->rx_stream);
- finish_session(dg00x);
- release_resources(dg00x);
+ if (dg00x->substreams_counter == 0) {
+ finish_session(dg00x);
- /*
- * Just after finishing the session, the device may lost transmitting
- * functionality for a short time.
- */
- msleep(50);
+ fw_iso_resources_free(&dg00x->tx_resources);
+ fw_iso_resources_free(&dg00x->rx_resources);
+ }
}
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 464e6d3d82a8..0994d191ccda 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -139,7 +139,8 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
bool *detect);
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index 0d40bb68db50..9eab3ad283ce 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -198,8 +198,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_ff *ff = substream->private_data;
int err;
@@ -210,58 +210,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&ff->mutex);
- ff->substreams_counter++;
- mutex_unlock(&ff->mutex);
- }
-
- return 0;
-}
-
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_ff *ff = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
+ unsigned int rate = params_rate(hw_params);
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&ff->mutex);
- ff->substreams_counter++;
+ err = snd_ff_stream_reserve_duplex(ff, rate);
+ if (err >= 0)
+ ++ff->substreams_counter;
mutex_unlock(&ff->mutex);
}
return 0;
}
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_ff *ff = substream->private_data;
-
- mutex_lock(&ff->mutex);
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- ff->substreams_counter--;
-
- snd_ff_stream_stop_duplex(ff);
-
- mutex_unlock(&ff->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_ff *ff = substream->private_data;
mutex_lock(&ff->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- ff->substreams_counter--;
+ --ff->substreams_counter;
snd_ff_stream_stop_duplex(ff);
@@ -374,8 +342,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
@@ -386,8 +354,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index 8d1c2c6e907b..bf44cad7985e 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -293,27 +293,6 @@ static int former_fill_midi_msg(struct snd_ff *ff,
#define FF800_TX_PACKET_ISOC_CH 0x0000801c0008
-static int allocate_rx_resources(struct snd_ff *ff)
-{
- u32 data;
- __le32 reg;
- int err;
-
- // Controllers should allocate isochronous resources for rx stream.
- err = fw_iso_resources_allocate(&ff->rx_resources,
- amdtp_stream_get_max_payload(&ff->rx_stream),
- fw_parent_device(ff->unit)->max_speed);
- if (err < 0)
- return err;
-
- // Set isochronous channel and the number of quadlets of rx packets.
- data = ff->rx_stream.data_block_quadlets << 3;
- data = (data << 8) | ff->rx_resources.channel;
- reg = cpu_to_le32(data);
- return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
- FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
-}
-
static int allocate_tx_resources(struct snd_ff *ff)
{
__le32 reg;
@@ -355,8 +334,9 @@ static int allocate_tx_resources(struct snd_ff *ff)
return 0;
}
-static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
+static int ff800_allocate_resources(struct snd_ff *ff, unsigned int rate)
{
+ u32 data;
__le32 reg;
int err;
@@ -371,14 +351,38 @@ static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
// Let's sleep for a bit.
msleep(100);
- err = allocate_rx_resources(ff);
+ // Controllers should allocate isochronous resources for rx stream.
+ err = fw_iso_resources_allocate(&ff->rx_resources,
+ amdtp_stream_get_max_payload(&ff->rx_stream),
+ fw_parent_device(ff->unit)->max_speed);
if (err < 0)
return err;
- err = allocate_tx_resources(ff);
+ // Set isochronous channel and the number of quadlets of rx packets.
+ // This should be done before the allocation of tx resources to avoid
+ // periodical noise.
+ data = ff->rx_stream.data_block_quadlets << 3;
+ data = (data << 8) | ff->rx_resources.channel;
+ reg = cpu_to_le32(data);
+ err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
if (err < 0)
return err;
+ return allocate_tx_resources(ff);
+}
+
+static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
+{
+ unsigned int generation = ff->rx_resources.generation;
+ __le32 reg;
+
+ if (generation != fw_parent_device(ff->unit)->card->generation) {
+ int err = fw_iso_resources_update(&ff->rx_resources);
+ if (err < 0)
+ return err;
+ }
+
reg = cpu_to_le32(0x80000000);
reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);
if (fw_parent_device(ff->unit)->max_speed == SCODE_800)
@@ -420,6 +424,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = {
.fill_midi_msg = former_fill_midi_msg,
.get_clock = former_get_clock,
.switch_fetching_mode = former_switch_fetching_mode,
+ .allocate_resources = ff800_allocate_resources,
.begin_session = ff800_begin_session,
.finish_session = ff800_finish_session,
.dump_status = former_dump_status,
@@ -431,12 +436,11 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = {
#define FF400_TX_PACKET_FORMAT 0x00008010050cull
#define FF400_ISOC_COMM_STOP 0x000080100510ull
-/*
- * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
- * we can allocate between 0 and 7 channel.
- */
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+// Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
+// we can allocate between 0 and 7 channel.
+static int ff400_allocate_resources(struct snd_ff *ff, unsigned int rate)
{
+ __le32 reg;
enum snd_ff_stream_mode mode;
int i;
int err;
@@ -449,11 +453,20 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
if (i >= CIP_SFC_COUNT)
return -EINVAL;
+ // Set the number of data blocks transferred in a second.
+ reg = cpu_to_le32(rate);
+ err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF400_STF, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ msleep(100);
+
err = snd_ff_stream_get_multiplier_mode(i, &mode);
if (err < 0)
return err;
- /* Keep resources for in-stream. */
+ // Keep resources for in-stream.
ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->tx_resources,
amdtp_stream_get_max_payload(&ff->tx_stream),
@@ -461,7 +474,7 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
if (err < 0)
return err;
- /* Keep resources for out-stream. */
+ // Keep resources for out-stream.
ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->rx_resources,
amdtp_stream_get_max_payload(&ff->rx_stream),
@@ -474,26 +487,22 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
{
+ unsigned int generation = ff->rx_resources.generation;
__le32 reg;
int err;
- err = keep_resources(ff, rate);
- if (err < 0)
- return err;
-
- /* Set the number of data blocks transferred in a second. */
- reg = cpu_to_le32(rate);
- err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
- FF400_STF, &reg, sizeof(reg), 0);
- if (err < 0)
- return err;
+ if (generation != fw_parent_device(ff->unit)->card->generation) {
+ err = fw_iso_resources_update(&ff->tx_resources);
+ if (err < 0)
+ return err;
- msleep(100);
+ err = fw_iso_resources_update(&ff->rx_resources);
+ if (err < 0)
+ return err;
+ }
- /*
- * Set isochronous channel and the number of quadlets of received
- * packets.
- */
+ // Set isochronous channel and the number of quadlets of received
+ // packets.
reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |
ff->rx_resources.channel);
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
@@ -501,11 +510,9 @@ static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
if (err < 0)
return err;
- /*
- * Set isochronous channel and the number of quadlets of transmitted
- * packet.
- */
- /* TODO: investigate the purpose of this 0x80. */
+ // Set isochronous channel and the number of quadlets of transmitted
+ // packet.
+ // TODO: investigate the purpose of this 0x80.
reg = cpu_to_le32((0x80 << 24) |
(ff->tx_resources.channel << 5) |
(ff->tx_stream.data_block_quadlets));
@@ -514,7 +521,7 @@ static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
if (err < 0)
return err;
- /* Allow to transmit packets. */
+ // Allow to transmit packets.
reg = cpu_to_le32(0x00000001);
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
FF400_ISOC_COMM_START, &reg, sizeof(reg), 0);
@@ -591,6 +598,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff400 = {
.fill_midi_msg = former_fill_midi_msg,
.get_clock = former_get_clock,
.switch_fetching_mode = former_switch_fetching_mode,
+ .allocate_resources = ff400_allocate_resources,
.begin_session = ff400_begin_session,
.finish_session = ff400_finish_session,
.dump_status = former_dump_status,
diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c
index b30d02d359b1..0e4c3a9ed5e4 100644
--- a/sound/firewire/fireface/ff-protocol-latter.c
+++ b/sound/firewire/fireface/ff-protocol-latter.c
@@ -97,25 +97,64 @@ static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)
LATTER_FETCH_MODE, &reg, sizeof(reg), 0);
}
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)
{
enum snd_ff_stream_mode mode;
+ unsigned int code;
+ __le32 reg;
+ unsigned int count;
int i;
int err;
- // Check whether the given value is supported or not.
- for (i = 0; i < CIP_SFC_COUNT; i++) {
- if (amdtp_rate_table[i] == rate)
+ // Set the number of data blocks transferred in a second.
+ if (rate % 32000 == 0)
+ code = 0x00;
+ else if (rate % 44100 == 0)
+ code = 0x02;
+ else if (rate % 48000 == 0)
+ code = 0x04;
+ else
+ return -EINVAL;
+
+ if (rate >= 64000 && rate < 128000)
+ code |= 0x08;
+ else if (rate >= 128000 && rate < 192000)
+ code |= 0x10;
+
+ reg = cpu_to_le32(code);
+ err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ LATTER_STF, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ // Confirm to shift transmission clock.
+ count = 0;
+ while (count++ < 10) {
+ unsigned int curr_rate;
+ enum snd_ff_clock_src src;
+
+ err = latter_get_clock(ff, &curr_rate, &src);
+ if (err < 0)
+ return err;
+
+ if (curr_rate == rate)
break;
}
- if (i >= CIP_SFC_COUNT)
+ if (count == 10)
+ return -ETIMEDOUT;
+
+ for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {
+ if (rate == amdtp_rate_table[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(amdtp_rate_table))
return -EINVAL;
err = snd_ff_stream_get_multiplier_mode(i, &mode);
if (err < 0)
return err;
- /* Keep resources for in-stream. */
+ // Keep resources for in-stream.
ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->tx_resources,
amdtp_stream_get_max_payload(&ff->tx_stream),
@@ -123,7 +162,7 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
if (err < 0)
return err;
- /* Keep resources for out-stream. */
+ // Keep resources for out-stream.
ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->rx_resources,
amdtp_stream_get_max_payload(&ff->rx_stream),
@@ -136,60 +175,30 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
{
- static const struct {
- unsigned int stf;
- unsigned int code;
- unsigned int flag;
- } *entry, rate_table[] = {
- { 32000, 0x00, 0x92, },
- { 44100, 0x02, 0x92, },
- { 48000, 0x04, 0x92, },
- { 64000, 0x08, 0x8e, },
- { 88200, 0x0a, 0x8e, },
- { 96000, 0x0c, 0x8e, },
- { 128000, 0x10, 0x8c, },
- { 176400, 0x12, 0x8c, },
- { 192000, 0x14, 0x8c, },
- };
+ unsigned int generation = ff->rx_resources.generation;
+ unsigned int flag;
u32 data;
__le32 reg;
- unsigned int count;
- int i;
int err;
- for (i = 0; i < ARRAY_SIZE(rate_table); ++i) {
- entry = rate_table + i;
- if (entry->stf == rate)
- break;
- }
- if (i == ARRAY_SIZE(rate_table))
+ if (rate >= 32000 && rate <= 48000)
+ flag = 0x92;
+ else if (rate >= 64000 && rate <= 96000)
+ flag = 0x8e;
+ else if (rate >= 128000 && rate <= 192000)
+ flag = 0x8c;
+ else
return -EINVAL;
- reg = cpu_to_le32(entry->code);
- err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
- LATTER_STF, &reg, sizeof(reg), 0);
- if (err < 0)
- return err;
-
- // Confirm to shift transmission clock.
- count = 0;
- while (count++ < 10) {
- unsigned int curr_rate;
- enum snd_ff_clock_src src;
-
- err = latter_get_clock(ff, &curr_rate, &src);
+ if (generation != fw_parent_device(ff->unit)->card->generation) {
+ err = fw_iso_resources_update(&ff->tx_resources);
if (err < 0)
return err;
- if (curr_rate == rate)
- break;
+ err = fw_iso_resources_update(&ff->rx_resources);
+ if (err < 0)
+ return err;
}
- if (count == 10)
- return -ETIMEDOUT;
-
- err = keep_resources(ff, rate);
- if (err < 0)
- return err;
data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;
reg = cpu_to_le32(data);
@@ -200,7 +209,7 @@ static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
// Always use the maximum number of data channels in data block of
// packet.
- reg = cpu_to_le32(entry->flag);
+ reg = cpu_to_le32(flag);
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
LATTER_ISOC_START, &reg, sizeof(reg), 0);
}
@@ -424,6 +433,7 @@ const struct snd_ff_protocol snd_ff_protocol_latter = {
.fill_midi_msg = latter_fill_midi_msg,
.get_clock = latter_get_clock,
.switch_fetching_mode = latter_switch_fetching_mode,
+ .allocate_resources = latter_allocate_resources,
.begin_session = latter_begin_session,
.finish_session = latter_finish_session,
.dump_status = latter_dump_status,
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index 6dfd2efb6646..4208b8004d1a 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -30,14 +30,11 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
return 0;
}
-static void release_resources(struct snd_ff *ff)
-{
- fw_iso_resources_free(&ff->tx_resources);
- fw_iso_resources_free(&ff->rx_resources);
-}
-
static inline void finish_session(struct snd_ff *ff)
{
+ amdtp_stream_stop(&ff->tx_stream);
+ amdtp_stream_stop(&ff->rx_stream);
+
ff->spec->protocol->finish_session(ff);
ff->spec->protocol->switch_fetching_mode(ff, false);
}
@@ -103,37 +100,25 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
destroy_stream(ff, AMDTP_OUT_STREAM);
}
-int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
{
unsigned int curr_rate;
enum snd_ff_clock_src src;
int err;
- if (ff->substreams_counter == 0)
- return 0;
-
err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
if (err < 0)
return err;
- if (curr_rate != rate ||
- amdtp_streaming_error(&ff->tx_stream) ||
- amdtp_streaming_error(&ff->rx_stream)) {
- finish_session(ff);
-
- amdtp_stream_stop(&ff->tx_stream);
- amdtp_stream_stop(&ff->rx_stream);
-
- release_resources(ff);
- }
- /*
- * Regardless of current source of clock signal, drivers transfer some
- * packets. Then, the device transfers packets.
- */
- if (!amdtp_stream_running(&ff->rx_stream)) {
+ if (ff->substreams_counter == 0 || curr_rate != rate) {
enum snd_ff_stream_mode mode;
int i;
+ finish_session(ff);
+
+ fw_iso_resources_free(&ff->tx_resources);
+ fw_iso_resources_free(&ff->rx_resources);
+
for (i = 0; i < CIP_SFC_COUNT; ++i) {
if (amdtp_rate_table[i] == rate)
break;
@@ -155,6 +140,30 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
if (err < 0)
return err;
+ err = ff->spec->protocol->allocate_resources(ff, rate);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+{
+ int err;
+
+ if (ff->substreams_counter == 0)
+ return 0;
+
+ if (amdtp_streaming_error(&ff->tx_stream) ||
+ amdtp_streaming_error(&ff->rx_stream))
+ finish_session(ff);
+
+ /*
+ * Regardless of current source of clock signal, drivers transfer some
+ * packets. Then, the device transfers packets.
+ */
+ if (!amdtp_stream_running(&ff->rx_stream)) {
err = ff->spec->protocol->begin_session(ff, rate);
if (err < 0)
goto error;
@@ -192,37 +201,29 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
return 0;
error:
- amdtp_stream_stop(&ff->tx_stream);
- amdtp_stream_stop(&ff->rx_stream);
-
finish_session(ff);
- release_resources(ff);
return err;
}
void snd_ff_stream_stop_duplex(struct snd_ff *ff)
{
- if (ff->substreams_counter > 0)
- return;
+ if (ff->substreams_counter == 0) {
+ finish_session(ff);
- amdtp_stream_stop(&ff->tx_stream);
- amdtp_stream_stop(&ff->rx_stream);
- finish_session(ff);
- release_resources(ff);
+ fw_iso_resources_free(&ff->tx_resources);
+ fw_iso_resources_free(&ff->rx_resources);
+ }
}
void snd_ff_stream_update_duplex(struct snd_ff *ff)
{
- /* The device discontinue to transfer packets. */
+ // The device discontinue to transfer packets.
amdtp_stream_pcm_abort(&ff->tx_stream);
amdtp_stream_stop(&ff->tx_stream);
amdtp_stream_pcm_abort(&ff->rx_stream);
amdtp_stream_stop(&ff->rx_stream);
-
- fw_iso_resources_update(&ff->tx_resources);
- fw_iso_resources_update(&ff->rx_resources);
}
void snd_ff_stream_lock_changed(struct snd_ff *ff)
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 7fac241c2486..36dd0c75b9f7 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -112,6 +112,7 @@ struct snd_ff_protocol {
int (*get_clock)(struct snd_ff *ff, unsigned int *rate,
enum snd_ff_clock_src *src);
int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
+ int (*allocate_resources)(struct snd_ff *ff, unsigned int rate);
int (*begin_session)(struct snd_ff *ff, unsigned int rate);
void (*finish_session)(struct snd_ff *ff);
void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer);
@@ -136,6 +137,7 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
enum snd_ff_stream_mode *mode);
int snd_ff_stream_init_duplex(struct snd_ff *ff);
void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate);
int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
void snd_ff_stream_stop_duplex(struct snd_ff *ff);
void snd_ff_stream_update_duplex(struct snd_ff *ff);
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index 28df49c3542a..31efd4b53b4f 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -88,8 +88,7 @@ struct snd_efw {
struct amdtp_stream rx_stream;
struct cmp_connection out_conn;
struct cmp_connection in_conn;
- unsigned int capture_substreams;
- unsigned int playback_substreams;
+ unsigned int substreams_counter;
/* hardware metering parameters */
unsigned int phys_out;
@@ -206,7 +205,8 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate);
int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate);
int snd_efw_stream_init_duplex(struct snd_efw *efw);
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate);
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate);
+int snd_efw_stream_start_duplex(struct snd_efw *efw);
void snd_efw_stream_stop_duplex(struct snd_efw *efw);
void snd_efw_stream_update_duplex(struct snd_efw *efw);
void snd_efw_stream_destroy_duplex(struct snd_efw *efw);
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c
index 14b985c4f304..a9f4a9630d15 100644
--- a/sound/firewire/fireworks/fireworks_midi.c
+++ b/sound/firewire/fireworks/fireworks_midi.c
@@ -7,7 +7,7 @@
*/
#include "fireworks.h"
-static int midi_capture_open(struct snd_rawmidi_substream *substream)
+static int midi_open(struct snd_rawmidi_substream *substream)
{
struct snd_efw *efw = substream->rmidi->private_data;
int err;
@@ -17,28 +17,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
goto end;
mutex_lock(&efw->mutex);
- efw->capture_substreams++;
- err = snd_efw_stream_start_duplex(efw, 0);
- mutex_unlock(&efw->mutex);
- if (err < 0)
- snd_efw_stream_lock_release(efw);
-
-end:
- return err;
-}
-
-static int midi_playback_open(struct snd_rawmidi_substream *substream)
-{
- struct snd_efw *efw = substream->rmidi->private_data;
- int err;
-
- err = snd_efw_stream_lock_try(efw);
- if (err < 0)
- goto end;
-
- mutex_lock(&efw->mutex);
- efw->playback_substreams++;
- err = snd_efw_stream_start_duplex(efw, 0);
+ err = snd_efw_stream_reserve_duplex(efw, 0);
+ if (err >= 0) {
+ ++efw->substreams_counter;
+ err = snd_efw_stream_start_duplex(efw);
+ if (err < 0)
+ --efw->substreams_counter;
+ }
mutex_unlock(&efw->mutex);
if (err < 0)
snd_efw_stream_lock_release(efw);
@@ -46,25 +31,12 @@ end:
return err;
}
-static int midi_capture_close(struct snd_rawmidi_substream *substream)
-{
- struct snd_efw *efw = substream->rmidi->private_data;
-
- mutex_lock(&efw->mutex);
- efw->capture_substreams--;
- snd_efw_stream_stop_duplex(efw);
- mutex_unlock(&efw->mutex);
-
- snd_efw_stream_lock_release(efw);
- return 0;
-}
-
-static int midi_playback_close(struct snd_rawmidi_substream *substream)
+static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_efw *efw = substream->rmidi->private_data;
mutex_lock(&efw->mutex);
- efw->playback_substreams--;
+ --efw->substreams_counter;
snd_efw_stream_stop_duplex(efw);
mutex_unlock(&efw->mutex);
@@ -120,13 +92,13 @@ static void set_midi_substream_names(struct snd_efw *efw,
int snd_efw_create_midi_devices(struct snd_efw *efw)
{
static const struct snd_rawmidi_ops capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
+ .open = midi_open,
+ .close = midi_close,
.trigger = midi_capture_trigger,
};
static const struct snd_rawmidi_ops playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
+ .open = midi_open,
+ .close = midi_close,
.trigger = midi_playback_trigger,
};
struct snd_rawmidi *rmidi;
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index affc50fe2e8e..a7025dccc754 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -218,7 +218,7 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
+static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_efw *efw = substream->private_data;
@@ -230,69 +230,40 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&efw->mutex);
- efw->capture_substreams++;
- mutex_unlock(&efw->mutex);
- }
-
- return 0;
-}
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_efw *efw = substream->private_data;
- int err;
+ unsigned int rate = params_rate(hw_params);
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
-
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&efw->mutex);
- efw->playback_substreams++;
+ err = snd_efw_stream_reserve_duplex(efw, rate);
+ if (err >= 0)
+ ++efw->substreams_counter;
mutex_unlock(&efw->mutex);
}
- return 0;
+ return err;
}
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_efw *efw = substream->private_data;
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&efw->mutex);
- efw->capture_substreams--;
- mutex_unlock(&efw->mutex);
- }
-
- snd_efw_stream_stop_duplex(efw);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_efw *efw = substream->private_data;
+ mutex_lock(&efw->mutex);
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&efw->mutex);
- efw->playback_substreams--;
- mutex_unlock(&efw->mutex);
- }
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ --efw->substreams_counter;
snd_efw_stream_stop_duplex(efw);
+ mutex_unlock(&efw->mutex);
+
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_efw *efw = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- err = snd_efw_stream_start_duplex(efw, runtime->rate);
+ err = snd_efw_stream_start_duplex(efw);
if (err >= 0)
amdtp_stream_pcm_prepare(&efw->tx_stream);
@@ -301,10 +272,9 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_efw *efw = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- err = snd_efw_stream_start_duplex(efw, runtime->rate);
+ err = snd_efw_stream_start_duplex(efw);
if (err >= 0)
amdtp_stream_pcm_prepare(&efw->rx_stream);
@@ -377,8 +347,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
@@ -389,8 +359,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 2d3095412427..e659a0b89ba5 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -42,7 +42,6 @@ end:
static void
stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
{
- amdtp_stream_pcm_abort(stream);
amdtp_stream_stop(stream);
if (stream == &efw->tx_stream)
@@ -51,54 +50,37 @@ stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
cmp_connection_break(&efw->in_conn);
}
-static int
-start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
- unsigned int sampling_rate)
+static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
+ unsigned int rate)
{
struct cmp_connection *conn;
- unsigned int mode, pcm_channels, midi_ports;
int err;
- err = snd_efw_get_multiplier_mode(sampling_rate, &mode);
- if (err < 0)
- goto end;
- if (stream == &efw->tx_stream) {
+ if (stream == &efw->tx_stream)
conn = &efw->out_conn;
- pcm_channels = efw->pcm_capture_channels[mode];
- midi_ports = efw->midi_out_ports;
- } else {
+ else
conn = &efw->in_conn;
- pcm_channels = efw->pcm_playback_channels[mode];
- midi_ports = efw->midi_in_ports;
- }
-
- err = amdtp_am824_set_parameters(stream, sampling_rate,
- pcm_channels, midi_ports, false);
- if (err < 0)
- goto end;
- /* establish connection via CMP */
- err = cmp_connection_establish(conn,
- amdtp_stream_get_max_payload(stream));
+ // Establish connection via CMP.
+ err = cmp_connection_establish(conn);
if (err < 0)
- goto end;
+ return err;
- /* start amdtp stream */
- err = amdtp_stream_start(stream,
- conn->resources.channel,
- conn->speed);
+ // Start amdtp stream.
+ err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
if (err < 0) {
- stop_stream(efw, stream);
- goto end;
+ cmp_connection_break(conn);
+ return err;
}
- /* wait first callback */
+ // Wait first callback.
if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
- stop_stream(efw, stream);
- err = -ETIMEDOUT;
+ amdtp_stream_stop(stream);
+ cmp_connection_break(conn);
+ return -ETIMEDOUT;
}
-end:
- return err;
+
+ return 0;
}
/*
@@ -164,13 +146,13 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
(efw->firmware_version == 0x5070000 ||
efw->firmware_version == 0x5070300 ||
efw->firmware_version == 0x5080000))
- efw->tx_stream.tx_first_dbc = 0x02;
+ efw->tx_stream.ctx_data.tx.first_dbc = 0x02;
/* AudioFire9 always reports wrong dbs. */
if (efw->is_af9)
efw->tx_stream.flags |= CIP_WRONG_DBS;
/* Firmware version 5.5 reports fixed interval for dbc. */
if (efw->firmware_version == 0x5050000)
- efw->tx_stream.tx_dbc_interval = 8;
+ efw->tx_stream.ctx_data.tx.dbc_interval = 8;
err = init_stream(efw, &efw->rx_stream);
if (err < 0) {
@@ -188,75 +170,135 @@ end:
return err;
}
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
+static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
+ unsigned int rate, unsigned int mode)
{
- unsigned int curr_rate;
- int err = 0;
+ unsigned int pcm_channels;
+ unsigned int midi_ports;
+ struct cmp_connection *conn;
+ int err;
- /* Need no substreams */
- if (efw->playback_substreams == 0 && efw->capture_substreams == 0)
- goto end;
+ if (stream == &efw->tx_stream) {
+ pcm_channels = efw->pcm_capture_channels[mode];
+ midi_ports = efw->midi_out_ports;
+ conn = &efw->out_conn;
+ } else {
+ pcm_channels = efw->pcm_playback_channels[mode];
+ midi_ports = efw->midi_in_ports;
+ conn = &efw->in_conn;
+ }
- /*
- * Considering JACK/FFADO streaming:
- * TODO: This can be removed hwdep functionality becomes popular.
- */
- err = check_connection_used_by_others(efw, &efw->rx_stream);
+ err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
+ midi_ports, false);
if (err < 0)
- goto end;
+ return err;
- /* packet queueing error */
- if (amdtp_streaming_error(&efw->tx_stream))
- stop_stream(efw, &efw->tx_stream);
- if (amdtp_streaming_error(&efw->rx_stream))
- stop_stream(efw, &efw->rx_stream);
+ return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
+{
+ unsigned int curr_rate;
+ int err;
- /* stop streams if rate is different */
+ // Considering JACK/FFADO streaming:
+ // TODO: This can be removed hwdep functionality becomes popular.
+ err = check_connection_used_by_others(efw, &efw->rx_stream);
+ if (err < 0)
+ return err;
+
+ // stop streams if rate is different.
err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
if (err < 0)
- goto end;
+ return err;
if (rate == 0)
rate = curr_rate;
if (rate != curr_rate) {
stop_stream(efw, &efw->tx_stream);
stop_stream(efw, &efw->rx_stream);
+
+ cmp_connection_release(&efw->out_conn);
+ cmp_connection_release(&efw->in_conn);
}
- /* master should be always running */
- if (!amdtp_stream_running(&efw->rx_stream)) {
+ if (efw->substreams_counter == 0 || rate != curr_rate) {
+ unsigned int mode;
+
err = snd_efw_command_set_sampling_rate(efw, rate);
if (err < 0)
- goto end;
+ return err;
+
+ err = snd_efw_get_multiplier_mode(rate, &mode);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(efw, &efw->tx_stream, rate, mode);
+ if (err < 0)
+ return err;
+ err = keep_resources(efw, &efw->rx_stream, rate, mode);
+ if (err < 0) {
+ cmp_connection_release(&efw->in_conn);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_efw_stream_start_duplex(struct snd_efw *efw)
+{
+ unsigned int rate;
+ int err = 0;
+
+ // Need no substreams.
+ if (efw->substreams_counter == 0)
+ return -EIO;
+
+ err = snd_efw_command_get_sampling_rate(efw, &rate);
+ if (err < 0)
+ return err;
+
+ if (amdtp_streaming_error(&efw->rx_stream) ||
+ amdtp_streaming_error(&efw->tx_stream)) {
+ stop_stream(efw, &efw->rx_stream);
+ stop_stream(efw, &efw->tx_stream);
+ }
+
+ /* master should be always running */
+ if (!amdtp_stream_running(&efw->rx_stream)) {
err = start_stream(efw, &efw->rx_stream, rate);
if (err < 0) {
dev_err(&efw->unit->device,
"fail to start AMDTP master stream:%d\n", err);
- goto end;
+ goto error;
}
}
- /* start slave if needed */
- if (efw->capture_substreams > 0 &&
- !amdtp_stream_running(&efw->tx_stream)) {
+ if (!amdtp_stream_running(&efw->tx_stream)) {
err = start_stream(efw, &efw->tx_stream, rate);
if (err < 0) {
dev_err(&efw->unit->device,
"fail to start AMDTP slave stream:%d\n", err);
- stop_stream(efw, &efw->rx_stream);
+ goto error;
}
}
-end:
+
+ return 0;
+error:
+ stop_stream(efw, &efw->rx_stream);
+ stop_stream(efw, &efw->tx_stream);
return err;
}
void snd_efw_stream_stop_duplex(struct snd_efw *efw)
{
- if (efw->capture_substreams == 0) {
+ if (efw->substreams_counter == 0) {
stop_stream(efw, &efw->tx_stream);
+ stop_stream(efw, &efw->rx_stream);
- if (efw->playback_substreams == 0)
- stop_stream(efw, &efw->rx_stream);
+ cmp_connection_release(&efw->out_conn);
+ cmp_connection_release(&efw->in_conn);
}
}
diff --git a/sound/firewire/motu/amdtp-motu-trace.h b/sound/firewire/motu/amdtp-motu-trace.h
index 4d2351c0e8a3..3d36f125cf6a 100644
--- a/sound/firewire/motu/amdtp-motu-trace.h
+++ b/sound/firewire/motu/amdtp-motu-trace.h
@@ -18,7 +18,7 @@ static void copy_sph(u32 *frame, __be32 *buffer, unsigned int data_blocks,
static void copy_message(u64 *frames, __be32 *buffer, unsigned int data_blocks,
unsigned int data_block_quadlets);
-TRACE_EVENT(in_data_block_sph,
+TRACE_EVENT(data_block_sph,
TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
TP_ARGS(s, data_blocks, buffer),
TP_STRUCT__entry(
@@ -28,8 +28,13 @@ TRACE_EVENT(in_data_block_sph,
__dynamic_array(u32, tstamps, data_blocks)
),
TP_fast_assign(
- __entry->src = fw_parent_device(s->unit)->node_id;
- __entry->dst = fw_parent_device(s->unit)->card->node_id;
+ if (s->direction == AMDTP_IN_STREAM) {
+ __entry->src = fw_parent_device(s->unit)->node_id;
+ __entry->dst = fw_parent_device(s->unit)->card->node_id;
+ } else {
+ __entry->src = fw_parent_device(s->unit)->card->node_id;
+ __entry->dst = fw_parent_device(s->unit)->node_id;
+ }
__entry->data_blocks = data_blocks;
copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets);
),
@@ -42,55 +47,7 @@ TRACE_EVENT(in_data_block_sph,
)
);
-TRACE_EVENT(out_data_block_sph,
- TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
- TP_ARGS(s, data_blocks, buffer),
- TP_STRUCT__entry(
- __field(int, src)
- __field(int, dst)
- __field(unsigned int, data_blocks)
- __dynamic_array(u32, tstamps, data_blocks)
- ),
- TP_fast_assign(
- __entry->src = fw_parent_device(s->unit)->card->node_id;
- __entry->dst = fw_parent_device(s->unit)->node_id;
- __entry->data_blocks = data_blocks;
- copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets);
- ),
- TP_printk(
- "%04x %04x %u %s",
- __entry->src,
- __entry->dst,
- __entry->data_blocks,
- __print_array(__get_dynamic_array(tstamps), __entry->data_blocks, 4)
- )
-);
-
-TRACE_EVENT(in_data_block_message,
- TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
- TP_ARGS(s, data_blocks, buffer),
- TP_STRUCT__entry(
- __field(int, src)
- __field(int, dst)
- __field(unsigned int, data_blocks)
- __dynamic_array(u64, messages, data_blocks)
- ),
- TP_fast_assign(
- __entry->src = fw_parent_device(s->unit)->node_id;
- __entry->dst = fw_parent_device(s->unit)->card->node_id;
- __entry->data_blocks = data_blocks;
- copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets);
- ),
- TP_printk(
- "%04x %04x %u %s",
- __entry->src,
- __entry->dst,
- __entry->data_blocks,
- __print_array(__get_dynamic_array(messages), __entry->data_blocks, 8)
- )
-);
-
-TRACE_EVENT(out_data_block_message,
+TRACE_EVENT(data_block_message,
TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
TP_ARGS(s, data_blocks, buffer),
TP_STRUCT__entry(
@@ -100,8 +57,13 @@ TRACE_EVENT(out_data_block_message,
__dynamic_array(u64, messages, data_blocks)
),
TP_fast_assign(
- __entry->src = fw_parent_device(s->unit)->card->node_id;
- __entry->dst = fw_parent_device(s->unit)->node_id;
+ if (s->direction == AMDTP_IN_STREAM) {
+ __entry->src = fw_parent_device(s->unit)->node_id;
+ __entry->dst = fw_parent_device(s->unit)->card->node_id;
+ } else {
+ __entry->src = fw_parent_device(s->unit)->card->node_id;
+ __entry->dst = fw_parent_device(s->unit)->node_id;
+ }
__entry->data_blocks = data_blocks;
copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets);
),
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c
index 782d1fa024ec..7973dedd31ef 100644
--- a/sound/firewire/motu/amdtp-motu.c
+++ b/sound/firewire/motu/amdtp-motu.c
@@ -305,8 +305,8 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
struct amdtp_motu *p = s->protocol;
struct snd_pcm_substream *pcm;
- trace_in_data_block_sph(s, data_blocks, buffer);
- trace_in_data_block_message(s, data_blocks, buffer);
+ trace_data_block_sph(s, data_blocks, buffer);
+ trace_data_block_message(s, data_blocks, buffer);
if (p->midi_ports)
read_midi_messages(s, buffer, data_blocks);
@@ -383,8 +383,8 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
write_sph(s, buffer, data_blocks);
- trace_out_data_block_sph(s, data_blocks, buffer);
- trace_out_data_block_message(s, data_blocks, buffer);
+ trace_data_block_sph(s, data_blocks, buffer);
+ trace_data_block_message(s, data_blocks, buffer);
return data_blocks;
}
@@ -428,7 +428,7 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
return err;
s->sph = 1;
- s->fdf = MOTU_FDF_AM824;
+ s->ctx_data.rx.fdf = MOTU_FDF_AM824;
return 0;
}
diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c
index 75f6b2e9ca9e..46a0035df31e 100644
--- a/sound/firewire/motu/motu-midi.c
+++ b/sound/firewire/motu/motu-midi.c
@@ -6,7 +6,7 @@
*/
#include "motu.h"
-static int midi_capture_open(struct snd_rawmidi_substream *substream)
+static int midi_open(struct snd_rawmidi_substream *substream)
{
struct snd_motu *motu = substream->rmidi->private_data;
int err;
@@ -17,30 +17,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
mutex_lock(&motu->mutex);
- motu->capture_substreams++;
- err = snd_motu_stream_start_duplex(motu, 0);
-
- mutex_unlock(&motu->mutex);
-
- if (err < 0)
- snd_motu_stream_lock_release(motu);
-
- return err;
-}
-
-static int midi_playback_open(struct snd_rawmidi_substream *substream)
-{
- struct snd_motu *motu = substream->rmidi->private_data;
- int err;
-
- err = snd_motu_stream_lock_try(motu);
- if (err < 0)
- return err;
-
- mutex_lock(&motu->mutex);
-
- motu->playback_substreams++;
- err = snd_motu_stream_start_duplex(motu, 0);
+ err = snd_motu_stream_reserve_duplex(motu, 0);
+ if (err >= 0) {
+ ++motu->substreams_counter;
+ err = snd_motu_stream_start_duplex(motu);
+ if (err < 0)
+ --motu->substreams_counter;
+ }
mutex_unlock(&motu->mutex);
@@ -50,28 +33,13 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
return err;
}
-static int midi_capture_close(struct snd_rawmidi_substream *substream)
-{
- struct snd_motu *motu = substream->rmidi->private_data;
-
- mutex_lock(&motu->mutex);
-
- motu->capture_substreams--;
- snd_motu_stream_stop_duplex(motu);
-
- mutex_unlock(&motu->mutex);
-
- snd_motu_stream_lock_release(motu);
- return 0;
-}
-
-static int midi_playback_close(struct snd_rawmidi_substream *substream)
+static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_motu *motu = substream->rmidi->private_data;
mutex_lock(&motu->mutex);
- motu->playback_substreams--;
+ --motu->substreams_counter;
snd_motu_stream_stop_duplex(motu);
mutex_unlock(&motu->mutex);
@@ -128,13 +96,13 @@ static void set_midi_substream_names(struct snd_motu *motu,
int snd_motu_create_midi_devices(struct snd_motu *motu)
{
static const struct snd_rawmidi_ops capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
+ .open = midi_open,
+ .close = midi_close,
.trigger = midi_capture_trigger,
};
static const struct snd_rawmidi_ops playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
+ .open = midi_open,
+ .close = midi_close,
.trigger = midi_playback_trigger,
};
struct snd_rawmidi *rmidi;
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c
index 5e7db7aa4f08..aa2e584da6fe 100644
--- a/sound/firewire/motu/motu-pcm.c
+++ b/sound/firewire/motu/motu-pcm.c
@@ -189,8 +189,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_motu *motu = substream->private_data;
int err;
@@ -201,57 +201,26 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&motu->mutex);
- motu->capture_substreams++;
- mutex_unlock(&motu->mutex);
- }
-
- return 0;
-}
-static int playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_motu *motu = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
+ unsigned int rate = params_rate(hw_params);
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&motu->mutex);
- motu->playback_substreams++;
+ err = snd_motu_stream_reserve_duplex(motu, rate);
+ if (err >= 0)
+ ++motu->substreams_counter;
mutex_unlock(&motu->mutex);
}
- return 0;
-}
-
-static int capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_motu *motu = substream->private_data;
-
- mutex_lock(&motu->mutex);
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- motu->capture_substreams--;
-
- snd_motu_stream_stop_duplex(motu);
-
- mutex_unlock(&motu->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ return err;
}
-static int playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_motu *motu = substream->private_data;
mutex_lock(&motu->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- motu->playback_substreams--;
+ --motu->substreams_counter;
snd_motu_stream_stop_duplex(motu);
@@ -266,7 +235,7 @@ static int capture_prepare(struct snd_pcm_substream *substream)
int err;
mutex_lock(&motu->mutex);
- err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+ err = snd_motu_stream_start_duplex(motu);
mutex_unlock(&motu->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(&motu->tx_stream);
@@ -279,7 +248,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
int err;
mutex_lock(&motu->mutex);
- err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+ err = snd_motu_stream_start_duplex(motu);
mutex_unlock(&motu->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(&motu->rx_stream);
@@ -355,8 +324,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = capture_hw_params,
- .hw_free = capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = capture_prepare,
.trigger = capture_trigger,
.pointer = capture_pointer,
@@ -367,8 +336,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = playback_hw_params,
- .hw_free = playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = playback_prepare,
.trigger = playback_trigger,
.pointer = playback_pointer,
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
index 81f7edc560d0..2bbb335e8de1 100644
--- a/sound/firewire/motu/motu-stream.c
+++ b/sound/firewire/motu/motu-stream.c
@@ -25,48 +25,47 @@
#define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040
#define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f
-static int start_both_streams(struct snd_motu *motu, unsigned int rate)
+static int keep_resources(struct snd_motu *motu, unsigned int rate,
+ struct amdtp_stream *stream)
{
+ struct fw_iso_resources *resources;
+ struct snd_motu_packet_format *packet_format;
unsigned int midi_ports = 0;
- __be32 reg;
- u32 data;
int err;
- if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
- (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
- midi_ports = 1;
+ if (stream == &motu->rx_stream) {
+ resources = &motu->rx_resources;
+ packet_format = &motu->rx_packet_formats;
- /* Set packet formation to our packet streaming engine. */
- err = amdtp_motu_set_parameters(&motu->rx_stream, rate, midi_ports,
- &motu->rx_packet_formats);
- if (err < 0)
- return err;
+ if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
+ (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
+ midi_ports = 1;
+ } else {
+ resources = &motu->tx_resources;
+ packet_format = &motu->tx_packet_formats;
- if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
- (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
- midi_ports = 1;
- else
- midi_ports = 0;
+ if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
+ (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
+ midi_ports = 1;
+ }
- err = amdtp_motu_set_parameters(&motu->tx_stream, rate, midi_ports,
- &motu->tx_packet_formats);
+ err = amdtp_motu_set_parameters(stream, rate, midi_ports,
+ packet_format);
if (err < 0)
return err;
- /* Get isochronous resources on the bus. */
- err = fw_iso_resources_allocate(&motu->rx_resources,
- amdtp_stream_get_max_payload(&motu->rx_stream),
+ return fw_iso_resources_allocate(resources,
+ amdtp_stream_get_max_payload(stream),
fw_parent_device(motu->unit)->max_speed);
- if (err < 0)
- return err;
+}
- err = fw_iso_resources_allocate(&motu->tx_resources,
- amdtp_stream_get_max_payload(&motu->tx_stream),
- fw_parent_device(motu->unit)->max_speed);
- if (err < 0)
- return err;
+static int begin_session(struct snd_motu *motu)
+{
+ __be32 reg;
+ u32 data;
+ int err;
- /* Configure the unit to start isochronous communication. */
+ // Configure the unit to start isochronous communication.
err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
sizeof(reg));
if (err < 0)
@@ -83,7 +82,7 @@ static int start_both_streams(struct snd_motu *motu, unsigned int rate)
sizeof(reg));
}
-static void stop_both_streams(struct snd_motu *motu)
+static void finish_session(struct snd_motu *motu)
{
__be32 reg;
u32 data;
@@ -93,6 +92,9 @@ static void stop_both_streams(struct snd_motu *motu)
if (err < 0)
return;
+ amdtp_stream_stop(&motu->tx_stream);
+ amdtp_stream_stop(&motu->rx_stream);
+
err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
sizeof(reg));
if (err < 0)
@@ -105,9 +107,6 @@ static void stop_both_streams(struct snd_motu *motu)
reg = cpu_to_be32(data);
snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
sizeof(reg));
-
- fw_iso_resources_free(&motu->tx_resources);
- fw_iso_resources_free(&motu->rx_resources);
}
static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
@@ -125,28 +124,12 @@ static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
if (err < 0)
return err;
- if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
- amdtp_stream_stop(stream);
- fw_iso_resources_free(resources);
+ if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT))
return -ETIMEDOUT;
- }
return 0;
}
-static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
-{
- struct fw_iso_resources *resources;
-
- if (stream == &motu->rx_stream)
- resources = &motu->rx_resources;
- else
- resources = &motu->tx_resources;
-
- amdtp_stream_stop(stream);
- fw_iso_resources_free(resources);
-}
-
int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
{
int err;
@@ -174,6 +157,48 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
return 0;
}
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate)
+{
+ unsigned int curr_rate;
+ int err;
+
+ err = motu->spec->protocol->get_clock_rate(motu, &curr_rate);
+ if (err < 0)
+ return err;
+ if (rate == 0)
+ rate = curr_rate;
+
+ if (motu->substreams_counter == 0 || curr_rate != rate) {
+ finish_session(motu);
+
+ fw_iso_resources_free(&motu->tx_resources);
+ fw_iso_resources_free(&motu->rx_resources);
+
+ err = motu->spec->protocol->set_clock_rate(motu, rate);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to set sampling rate: %d\n", err);
+ return err;
+ }
+
+ err = snd_motu_stream_cache_packet_formats(motu);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(motu, rate, &motu->tx_stream);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(motu, rate, &motu->rx_stream);
+ if (err < 0) {
+ fw_iso_resources_free(&motu->tx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int ensure_packet_formats(struct snd_motu *motu)
{
__be32 reg;
@@ -200,55 +225,34 @@ static int ensure_packet_formats(struct snd_motu *motu)
sizeof(reg));
}
-int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
+int snd_motu_stream_start_duplex(struct snd_motu *motu)
{
- const struct snd_motu_protocol *protocol = motu->spec->protocol;
- unsigned int curr_rate;
+ unsigned int generation = motu->rx_resources.generation;
int err = 0;
- if (motu->capture_substreams == 0 && motu->playback_substreams == 0)
+ if (motu->substreams_counter == 0)
return 0;
- /* Some packet queueing errors. */
if (amdtp_streaming_error(&motu->rx_stream) ||
- amdtp_streaming_error(&motu->tx_stream)) {
- amdtp_stream_stop(&motu->rx_stream);
- amdtp_stream_stop(&motu->tx_stream);
- stop_both_streams(motu);
- }
+ amdtp_streaming_error(&motu->tx_stream))
+ finish_session(motu);
- err = snd_motu_stream_cache_packet_formats(motu);
- if (err < 0)
- return err;
+ if (generation != fw_parent_device(motu->unit)->card->generation) {
+ err = fw_iso_resources_update(&motu->rx_resources);
+ if (err < 0)
+ return err;
- /* Stop stream if rate is different. */
- err = protocol->get_clock_rate(motu, &curr_rate);
- if (err < 0) {
- dev_err(&motu->unit->device,
- "fail to get sampling rate: %d\n", err);
- return err;
- }
- if (rate == 0)
- rate = curr_rate;
- if (rate != curr_rate) {
- amdtp_stream_stop(&motu->rx_stream);
- amdtp_stream_stop(&motu->tx_stream);
- stop_both_streams(motu);
+ err = fw_iso_resources_update(&motu->tx_resources);
+ if (err < 0)
+ return err;
}
if (!amdtp_stream_running(&motu->rx_stream)) {
- err = protocol->set_clock_rate(motu, rate);
- if (err < 0) {
- dev_err(&motu->unit->device,
- "fail to set sampling rate: %d\n", err);
- return err;
- }
-
err = ensure_packet_formats(motu);
if (err < 0)
return err;
- err = start_both_streams(motu, rate);
+ err = begin_session(motu);
if (err < 0) {
dev_err(&motu->unit->device,
"fail to start isochronous comm: %d\n", err);
@@ -262,7 +266,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
goto stop_streams;
}
- err = protocol->switch_fetching_mode(motu, true);
+ err = motu->spec->protocol->switch_fetching_mode(motu, true);
if (err < 0) {
dev_err(&motu->unit->device,
"fail to enable frame fetching: %d\n", err);
@@ -270,13 +274,11 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
}
}
- if (!amdtp_stream_running(&motu->tx_stream) &&
- motu->capture_substreams > 0) {
+ if (!amdtp_stream_running(&motu->tx_stream)) {
err = start_isoc_ctx(motu, &motu->tx_stream);
if (err < 0) {
dev_err(&motu->unit->device,
"fail to start IR context: %d", err);
- amdtp_stream_stop(&motu->rx_stream);
goto stop_streams;
}
}
@@ -284,21 +286,17 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
return 0;
stop_streams:
- stop_both_streams(motu);
+ finish_session(motu);
return err;
}
void snd_motu_stream_stop_duplex(struct snd_motu *motu)
{
- if (motu->capture_substreams == 0) {
- if (amdtp_stream_running(&motu->tx_stream))
- stop_isoc_ctx(motu, &motu->tx_stream);
-
- if (motu->playback_substreams == 0) {
- if (amdtp_stream_running(&motu->rx_stream))
- stop_isoc_ctx(motu, &motu->rx_stream);
- stop_both_streams(motu);
- }
+ if (motu->substreams_counter == 0) {
+ finish_session(motu);
+
+ fw_iso_resources_free(&motu->tx_resources);
+ fw_iso_resources_free(&motu->rx_resources);
}
}
@@ -371,8 +369,7 @@ void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
destroy_stream(motu, AMDTP_IN_STREAM);
destroy_stream(motu, AMDTP_OUT_STREAM);
- motu->playback_substreams = 0;
- motu->capture_substreams = 0;
+ motu->substreams_counter = 0;
}
static void motu_lock_changed(struct snd_motu *motu)
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index 7c795294428d..09d1451d7de4 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -59,8 +59,7 @@ struct snd_motu {
struct amdtp_stream rx_stream;
struct fw_iso_resources tx_resources;
struct fw_iso_resources rx_resources;
- unsigned int capture_substreams;
- unsigned int playback_substreams;
+ unsigned int substreams_counter;
/* For notification. */
struct fw_address_handler async_handler;
@@ -153,7 +152,8 @@ void snd_motu_transaction_unregister(struct snd_motu *motu);
int snd_motu_stream_init_duplex(struct snd_motu *motu);
void snd_motu_stream_destroy_duplex(struct snd_motu *motu);
int snd_motu_stream_cache_packet_formats(struct snd_motu *motu);
-int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate);
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate);
+int snd_motu_stream_start_duplex(struct snd_motu *motu);
void snd_motu_stream_stop_duplex(struct snd_motu *motu);
int snd_motu_stream_lock_try(struct snd_motu *motu);
void snd_motu_stream_lock_release(struct snd_motu *motu);
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
index cbce01308bd1..9bdec08cb8ea 100644
--- a/sound/firewire/oxfw/oxfw-midi.c
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -18,8 +18,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->capture_substreams++;
- err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 0, 0);
+ err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0);
+ if (err >= 0) {
+ ++oxfw->substreams_count;
+ err = snd_oxfw_stream_start_duplex(oxfw);
+ if (err < 0)
+ --oxfw->substreams_count;
+ }
mutex_unlock(&oxfw->mutex);
@@ -40,8 +45,11 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->playback_substreams++;
- err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 0, 0);
+ err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0);
+ if (err >= 0) {
+ ++oxfw->substreams_count;
+ err = snd_oxfw_stream_start_duplex(oxfw);
+ }
mutex_unlock(&oxfw->mutex);
@@ -57,8 +65,8 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->capture_substreams--;
- snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+ --oxfw->substreams_count;
+ snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
@@ -72,8 +80,8 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->playback_substreams--;
- snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+ --oxfw->substreams_count;
+ snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index 94f367cdfdf3..9ea39348cdf5 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -219,12 +219,18 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+ unsigned int channels = params_channels(hw_params);
+
mutex_lock(&oxfw->mutex);
- oxfw->capture_substreams++;
+ err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
+ rate, channels);
+ if (err >= 0)
+ ++oxfw->substreams_count;
mutex_unlock(&oxfw->mutex);
}
- return 0;
+ return err;
}
static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
@@ -238,8 +244,14 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+ unsigned int channels = params_channels(hw_params);
+
mutex_lock(&oxfw->mutex);
- oxfw->playback_substreams++;
+ err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
+ rate, channels);
+ if (err >= 0)
+ ++oxfw->substreams_count;
mutex_unlock(&oxfw->mutex);
}
@@ -253,9 +265,9 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&oxfw->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- oxfw->capture_substreams--;
+ --oxfw->substreams_count;
- snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+ snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
@@ -268,9 +280,9 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&oxfw->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- oxfw->playback_substreams--;
+ --oxfw->substreams_count;
- snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+ snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
@@ -280,12 +292,10 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_oxfw *oxfw = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&oxfw->mutex);
- err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream,
- runtime->rate, runtime->channels);
+ err = snd_oxfw_stream_start_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
if (err < 0)
goto end;
@@ -297,12 +307,10 @@ end:
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_oxfw *oxfw = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&oxfw->mutex);
- err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream,
- runtime->rate, runtime->channels);
+ err = snd_oxfw_stream_start_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
if (err < 0)
goto end;
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 5ffedb0ade3f..74c972d25c66 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -100,85 +100,34 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
return 0;
}
-static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
+static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
{
- amdtp_stream_pcm_abort(stream);
- amdtp_stream_stop(stream);
-
- if (stream == &oxfw->tx_stream)
- cmp_connection_break(&oxfw->out_conn);
- else
- cmp_connection_break(&oxfw->in_conn);
-}
-
-static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
- unsigned int rate, unsigned int pcm_channels)
-{
- u8 **formats;
struct cmp_connection *conn;
- struct snd_oxfw_stream_formation formation;
- unsigned int i, midi_ports;
int err;
- if (stream == &oxfw->rx_stream) {
- formats = oxfw->rx_stream_formats;
+ if (stream == &oxfw->rx_stream)
conn = &oxfw->in_conn;
- } else {
- formats = oxfw->tx_stream_formats;
+ else
conn = &oxfw->out_conn;
- }
-
- /* Get stream format */
- for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
- if (formats[i] == NULL)
- break;
-
- err = snd_oxfw_stream_parse_format(formats[i], &formation);
- if (err < 0)
- goto end;
- if (rate != formation.rate)
- continue;
- if (pcm_channels == 0 || pcm_channels == formation.pcm)
- break;
- }
- if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
- err = -EINVAL;
- goto end;
- }
-
- pcm_channels = formation.pcm;
- midi_ports = formation.midi * 8;
-
- /* The stream should have one pcm channels at least */
- if (pcm_channels == 0) {
- err = -EINVAL;
- goto end;
- }
- err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports,
- false);
- if (err < 0)
- goto end;
- err = cmp_connection_establish(conn,
- amdtp_stream_get_max_payload(stream));
+ err = cmp_connection_establish(conn);
if (err < 0)
- goto end;
+ return err;
- err = amdtp_stream_start(stream,
- conn->resources.channel,
- conn->speed);
+ err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
if (err < 0) {
cmp_connection_break(conn);
- goto end;
+ return err;
}
- /* Wait first packet */
+ // Wait first packet.
if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
- stop_stream(oxfw, stream);
- err = -ETIMEDOUT;
+ amdtp_stream_stop(stream);
+ cmp_connection_break(conn);
+ return -ETIMEDOUT;
}
-end:
- return err;
+
+ return 0;
}
static int check_connection_used_by_others(struct snd_oxfw *oxfw,
@@ -205,8 +154,7 @@ static int check_connection_used_by_others(struct snd_oxfw *oxfw,
return err;
}
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream)
+static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
{
struct cmp_connection *conn;
enum cmp_direction c_dir;
@@ -225,13 +173,12 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
if (err < 0)
- goto end;
+ return err;
err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
if (err < 0) {
- amdtp_stream_destroy(stream);
cmp_connection_destroy(conn);
- goto end;
+ return err;
}
/*
@@ -245,115 +192,195 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
if (oxfw->wrong_dbs)
oxfw->tx_stream.flags |= CIP_WRONG_DBS;
}
-end:
- return err;
+
+ return 0;
}
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream,
- unsigned int rate, unsigned int pcm_channels)
+static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
{
- struct amdtp_stream *opposite;
- struct snd_oxfw_stream_formation formation;
enum avc_general_plug_dir dir;
- unsigned int substreams, opposite_substreams;
- int err = 0;
+ u8 **formats;
+ struct snd_oxfw_stream_formation formation;
+ struct cmp_connection *conn;
+ int i;
+ int err;
- if (stream == &oxfw->tx_stream) {
- substreams = oxfw->capture_substreams;
- opposite = &oxfw->rx_stream;
- opposite_substreams = oxfw->playback_substreams;
- dir = AVC_GENERAL_PLUG_DIR_OUT;
+ if (stream == &oxfw->rx_stream) {
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+ formats = oxfw->rx_stream_formats;
+ conn = &oxfw->in_conn;
} else {
- substreams = oxfw->playback_substreams;
- opposite_substreams = oxfw->capture_substreams;
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ formats = oxfw->tx_stream_formats;
+ conn = &oxfw->out_conn;
+ }
- if (oxfw->has_output)
- opposite = &oxfw->rx_stream;
- else
- opposite = NULL;
+ err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
+ if (err < 0)
+ return err;
- dir = AVC_GENERAL_PLUG_DIR_IN;
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ struct snd_oxfw_stream_formation fmt;
+
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &fmt);
+ if (err < 0)
+ return err;
+
+ if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
+ fmt.midi == formation.midi)
+ break;
}
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
+ return -EINVAL;
- if (substreams == 0)
- goto end;
+ // The stream should have one pcm channels at least.
+ if (formation.pcm == 0)
+ return -EINVAL;
- /*
- * Considering JACK/FFADO streaming:
- * TODO: This can be removed hwdep functionality becomes popular.
- */
- err = check_connection_used_by_others(oxfw, stream);
+ err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
+ formation.midi * 8, false);
if (err < 0)
- goto end;
+ return err;
- /* packet queueing error */
- if (amdtp_streaming_error(stream))
- stop_stream(oxfw, stream);
+ return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ int err;
+
+ // Considering JACK/FFADO streaming:
+ // TODO: This can be removed hwdep functionality becomes popular.
+ err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
+ if (err < 0)
+ return err;
+ if (oxfw->has_output) {
+ err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
+ if (err < 0)
+ return err;
+ }
+
+ if (stream == &oxfw->tx_stream)
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ else
+ dir = AVC_GENERAL_PLUG_DIR_IN;
err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
if (err < 0)
- goto end;
- if (rate == 0)
+ return err;
+ if (rate == 0) {
rate = formation.rate;
- if (pcm_channels == 0)
pcm_channels = formation.pcm;
+ }
+ if (formation.rate != rate || formation.pcm != pcm_channels) {
+ amdtp_stream_stop(&oxfw->rx_stream);
+ cmp_connection_break(&oxfw->in_conn);
+ cmp_connection_release(&oxfw->in_conn);
- if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
- if (opposite != NULL) {
- err = check_connection_used_by_others(oxfw, opposite);
- if (err < 0)
- goto end;
- stop_stream(oxfw, opposite);
+ if (oxfw->has_output) {
+ amdtp_stream_stop(&oxfw->tx_stream);
+ cmp_connection_break(&oxfw->out_conn);
+ cmp_connection_release(&oxfw->out_conn);
}
- stop_stream(oxfw, stream);
+ }
+ if (oxfw->substreams_count == 0 ||
+ formation.rate != rate || formation.pcm != pcm_channels) {
err = set_stream_format(oxfw, stream, rate, pcm_channels);
if (err < 0) {
dev_err(&oxfw->unit->device,
"fail to set stream format: %d\n", err);
- goto end;
+ return err;
}
- /* Start opposite stream if needed. */
- if (opposite && !amdtp_stream_running(opposite) &&
- (opposite_substreams > 0)) {
- err = start_stream(oxfw, opposite, rate, 0);
+ err = keep_resources(oxfw, &oxfw->rx_stream);
+ if (err < 0)
+ return err;
+
+ if (oxfw->has_output) {
+ err = keep_resources(oxfw, &oxfw->tx_stream);
if (err < 0) {
- dev_err(&oxfw->unit->device,
- "fail to restart stream: %d\n", err);
- goto end;
+ cmp_connection_release(&oxfw->in_conn);
+ return err;
}
}
}
- /* Start requested stream. */
- if (!amdtp_stream_running(stream)) {
- err = start_stream(oxfw, stream, rate, pcm_channels);
- if (err < 0)
+ return 0;
+}
+
+int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ if (oxfw->substreams_count == 0)
+ return -EIO;
+
+ if (amdtp_streaming_error(&oxfw->rx_stream) ||
+ amdtp_streaming_error(&oxfw->tx_stream)) {
+ amdtp_stream_stop(&oxfw->rx_stream);
+ cmp_connection_break(&oxfw->in_conn);
+
+ if (oxfw->has_output) {
+ amdtp_stream_stop(&oxfw->tx_stream);
+ cmp_connection_break(&oxfw->out_conn);
+ }
+ }
+
+ if (!amdtp_stream_running(&oxfw->rx_stream)) {
+ err = start_stream(oxfw, &oxfw->rx_stream);
+ if (err < 0) {
dev_err(&oxfw->unit->device,
- "fail to start stream: %d\n", err);
+ "fail to start rx stream: %d\n", err);
+ goto error;
+ }
+ }
+
+ if (oxfw->has_output) {
+ if (!amdtp_stream_running(&oxfw->tx_stream)) {
+ err = start_stream(oxfw, &oxfw->tx_stream);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to start tx stream: %d\n", err);
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+error:
+ amdtp_stream_stop(&oxfw->rx_stream);
+ cmp_connection_break(&oxfw->in_conn);
+ if (oxfw->has_output) {
+ amdtp_stream_stop(&oxfw->tx_stream);
+ cmp_connection_break(&oxfw->out_conn);
}
-end:
return err;
}
-void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream)
+void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
{
- if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
- ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
- return;
+ if (oxfw->substreams_count == 0) {
+ amdtp_stream_stop(&oxfw->rx_stream);
+ cmp_connection_break(&oxfw->in_conn);
+ cmp_connection_release(&oxfw->in_conn);
- stop_stream(oxfw, stream);
+ if (oxfw->has_output) {
+ amdtp_stream_stop(&oxfw->tx_stream);
+ cmp_connection_break(&oxfw->out_conn);
+ cmp_connection_release(&oxfw->out_conn);
+ }
+ }
}
-/*
- * This function should be called before starting the stream or after stopping
- * the streams.
- */
-void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream)
+static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
{
struct cmp_connection *conn;
@@ -366,20 +393,48 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
cmp_connection_destroy(conn);
}
-void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream)
+int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
{
- struct cmp_connection *conn;
+ int err;
- if (stream == &oxfw->tx_stream)
- conn = &oxfw->out_conn;
- else
- conn = &oxfw->in_conn;
+ err = init_stream(oxfw, &oxfw->rx_stream);
+ if (err < 0)
+ return err;
- if (cmp_connection_update(conn) < 0)
- stop_stream(oxfw, stream);
- else
- amdtp_stream_update(stream);
+ if (oxfw->has_output) {
+ err = init_stream(oxfw, &oxfw->tx_stream);
+ if (err < 0) {
+ destroy_stream(oxfw, &oxfw->rx_stream);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+// This function should be called before starting the stream or after stopping
+// the streams.
+void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
+{
+ destroy_stream(oxfw, &oxfw->rx_stream);
+
+ if (oxfw->has_output)
+ destroy_stream(oxfw, &oxfw->tx_stream);
+}
+
+void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
+{
+ amdtp_stream_stop(&oxfw->rx_stream);
+ cmp_connection_break(&oxfw->in_conn);
+
+ amdtp_stream_pcm_abort(&oxfw->rx_stream);
+
+ if (oxfw->has_output) {
+ amdtp_stream_stop(&oxfw->tx_stream);
+ cmp_connection_break(&oxfw->out_conn);
+
+ amdtp_stream_pcm_abort(&oxfw->tx_stream);
+ }
}
int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 9fd145cc4b07..fb6df3fc018e 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -118,9 +118,7 @@ static void oxfw_card_free(struct snd_card *card)
{
struct snd_oxfw *oxfw = card->private_data;
- snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
- if (oxfw->has_output)
- snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+ snd_oxfw_stream_destroy_duplex(oxfw);
}
static int detect_quirks(struct snd_oxfw *oxfw)
@@ -208,14 +206,9 @@ static void do_registration(struct work_struct *work)
if (err < 0)
goto error;
- err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream);
+ err = snd_oxfw_stream_init_duplex(oxfw);
if (err < 0)
goto error;
- if (oxfw->has_output) {
- err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream);
- if (err < 0)
- goto error;
- }
err = snd_oxfw_create_pcm(oxfw);
if (err < 0)
@@ -282,11 +275,7 @@ static void oxfw_bus_reset(struct fw_unit *unit)
if (oxfw->registered) {
mutex_lock(&oxfw->mutex);
-
- snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream);
- if (oxfw->has_output)
- snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
-
+ snd_oxfw_stream_update_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
if (oxfw->entry->vendor_id == OUI_STANTON)
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 36112850ef92..cb69ab87bb14 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -52,8 +52,7 @@ struct snd_oxfw {
struct cmp_connection in_conn;
struct amdtp_stream tx_stream;
struct amdtp_stream rx_stream;
- unsigned int capture_substreams;
- unsigned int playback_substreams;
+ unsigned int substreams_count;
unsigned int midi_input_ports;
unsigned int midi_output_ports;
@@ -99,17 +98,14 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
enum avc_general_plug_dir dir,
unsigned short pid);
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream);
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream,
- unsigned int rate, unsigned int pcm_channels);
-void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream);
-void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream);
-void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
- struct amdtp_stream *stream);
+int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw);
+int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels);
+int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw);
struct snd_oxfw_stream_formation {
unsigned int rate;
diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c
index d9d20ef22f5b..95fb10b7a737 100644
--- a/sound/firewire/tascam/amdtp-tascam.c
+++ b/sound/firewire/tascam/amdtp-tascam.c
@@ -223,7 +223,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
return 0;
/* Use fixed value for FDF field. */
- s->fdf = 0x00;
+ s->ctx_data.rx.fdf = 0x00;
/* This protocol uses fixed number of data channels for PCM samples. */
p = s->protocol;
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index a8cd9b156488..b5ced5415e40 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -83,8 +83,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_tscm *tscm = substream->private_data;
int err;
@@ -95,58 +95,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&tscm->mutex);
- tscm->substreams_counter++;
- mutex_unlock(&tscm->mutex);
- }
-
- return 0;
-}
-
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_tscm *tscm = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
+ unsigned int rate = params_rate(hw_params);
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&tscm->mutex);
- tscm->substreams_counter++;
+ err = snd_tscm_stream_reserve_duplex(tscm, rate);
+ if (err >= 0)
+ ++tscm->substreams_counter;
mutex_unlock(&tscm->mutex);
}
- return 0;
-}
-
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_tscm *tscm = substream->private_data;
-
- mutex_lock(&tscm->mutex);
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- tscm->substreams_counter--;
-
- snd_tscm_stream_stop_duplex(tscm);
-
- mutex_unlock(&tscm->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ return err;
}
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_tscm *tscm = substream->private_data;
mutex_lock(&tscm->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- tscm->substreams_counter--;
+ --tscm->substreams_counter;
snd_tscm_stream_stop_duplex(tscm);
@@ -259,8 +227,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
@@ -271,8 +239,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
index e6fcd9e19961..e852e46ebe6f 100644
--- a/sound/firewire/tascam/tascam-stream.c
+++ b/sound/firewire/tascam/tascam-stream.c
@@ -165,7 +165,7 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
__be32 reg;
int err;
- /* Set an option for unknown purpose. */
+ // Set an option for unknown purpose.
reg = cpu_to_be32(0x00200000);
err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
@@ -173,17 +173,16 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
if (err < 0)
return err;
- err = enable_data_channels(tscm);
- if (err < 0)
- return err;
-
- return set_clock(tscm, rate, INT_MAX);
+ return enable_data_channels(tscm);
}
static void finish_session(struct snd_tscm *tscm)
{
__be32 reg;
+ amdtp_stream_stop(&tscm->rx_stream);
+ amdtp_stream_stop(&tscm->tx_stream);
+
reg = 0;
snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
@@ -194,6 +193,19 @@ static void finish_session(struct snd_tscm *tscm)
TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
&reg, sizeof(reg), 0);
+ // Unregister channels.
+ reg = cpu_to_be32(0x00000000);
+ snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
+ &reg, sizeof(reg), 0);
+ reg = cpu_to_be32(0x00000000);
+ snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+ TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
+ &reg, sizeof(reg), 0);
+ reg = cpu_to_be32(0x00000000);
+ snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
+ &reg, sizeof(reg), 0);
}
static int begin_session(struct snd_tscm *tscm)
@@ -201,6 +213,30 @@ static int begin_session(struct snd_tscm *tscm)
__be32 reg;
int err;
+ // Register the isochronous channel for transmitting stream.
+ reg = cpu_to_be32(tscm->tx_resources.channel);
+ err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
+ &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ // Unknown.
+ reg = cpu_to_be32(0x00000002);
+ err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+ TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
+ &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ // Register the isochronous channel for receiving stream.
+ reg = cpu_to_be32(tscm->rx_resources.channel);
+ err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
+ &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
reg = cpu_to_be32(0x00000001);
err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
@@ -215,7 +251,7 @@ static int begin_session(struct snd_tscm *tscm)
if (err < 0)
return err;
- /* Set an option for unknown purpose. */
+ // Set an option for unknown purpose.
reg = cpu_to_be32(0x00002000);
err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
@@ -223,7 +259,7 @@ static int begin_session(struct snd_tscm *tscm)
if (err < 0)
return err;
- /* Start multiplexing PCM samples on packets. */
+ // Start multiplexing PCM samples on packets.
reg = cpu_to_be32(0x00000001);
return snd_fw_transaction(tscm->unit,
TCODE_WRITE_QUADLET_REQUEST,
@@ -231,82 +267,24 @@ static int begin_session(struct snd_tscm *tscm)
&reg, sizeof(reg), 0);
}
-static void release_resources(struct snd_tscm *tscm)
+static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
+ struct amdtp_stream *stream)
{
- __be32 reg;
-
- /* Unregister channels. */
- reg = cpu_to_be32(0x00000000);
- snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
- &reg, sizeof(reg), 0);
- reg = cpu_to_be32(0x00000000);
- snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
- TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
- &reg, sizeof(reg), 0);
- reg = cpu_to_be32(0x00000000);
- snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
- &reg, sizeof(reg), 0);
-
- /* Release isochronous resources. */
- fw_iso_resources_free(&tscm->tx_resources);
- fw_iso_resources_free(&tscm->rx_resources);
-}
-
-static int keep_resources(struct snd_tscm *tscm, unsigned int rate)
-{
- __be32 reg;
+ struct fw_iso_resources *resources;
int err;
- /* Keep resources for in-stream. */
- err = amdtp_tscm_set_parameters(&tscm->tx_stream, rate);
- if (err < 0)
- return err;
- err = fw_iso_resources_allocate(&tscm->tx_resources,
- amdtp_stream_get_max_payload(&tscm->tx_stream),
- fw_parent_device(tscm->unit)->max_speed);
- if (err < 0)
- goto error;
+ if (stream == &tscm->tx_stream)
+ resources = &tscm->tx_resources;
+ else
+ resources = &tscm->rx_resources;
- /* Keep resources for out-stream. */
- err = amdtp_tscm_set_parameters(&tscm->rx_stream, rate);
- if (err < 0)
- return err;
- err = fw_iso_resources_allocate(&tscm->rx_resources,
- amdtp_stream_get_max_payload(&tscm->rx_stream),
- fw_parent_device(tscm->unit)->max_speed);
+ err = amdtp_tscm_set_parameters(stream, rate);
if (err < 0)
return err;
- /* Register the isochronous channel for transmitting stream. */
- reg = cpu_to_be32(tscm->tx_resources.channel);
- err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
- &reg, sizeof(reg), 0);
- if (err < 0)
- goto error;
-
- /* Unknown */
- reg = cpu_to_be32(0x00000002);
- err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
- TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
- &reg, sizeof(reg), 0);
- if (err < 0)
- goto error;
-
- /* Register the isochronous channel for receiving stream. */
- reg = cpu_to_be32(tscm->rx_resources.channel);
- err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
- &reg, sizeof(reg), 0);
- if (err < 0)
- goto error;
-
- return 0;
-error:
- release_resources(tscm);
- return err;
+ return fw_iso_resources_allocate(resources,
+ amdtp_stream_get_max_payload(stream),
+ fw_parent_device(tscm->unit)->max_speed);
}
int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
@@ -345,7 +323,7 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
return err;
}
-/* At bus reset, streaming is stopped and some registers are clear. */
+// At bus reset, streaming is stopped and some registers are clear.
void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
{
amdtp_stream_pcm_abort(&tscm->tx_stream);
@@ -368,33 +346,62 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
fw_iso_resources_destroy(&tscm->tx_resources);
}
-int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
{
unsigned int curr_rate;
int err;
- if (tscm->substreams_counter == 0)
- return 0;
-
err = snd_tscm_stream_get_rate(tscm, &curr_rate);
if (err < 0)
return err;
- if (curr_rate != rate ||
- amdtp_streaming_error(&tscm->rx_stream) ||
- amdtp_streaming_error(&tscm->tx_stream)) {
+
+ if (tscm->substreams_counter == 0 || rate != curr_rate) {
finish_session(tscm);
- amdtp_stream_stop(&tscm->rx_stream);
- amdtp_stream_stop(&tscm->tx_stream);
+ fw_iso_resources_free(&tscm->tx_resources);
+ fw_iso_resources_free(&tscm->rx_resources);
- release_resources(tscm);
+ err = set_clock(tscm, rate, INT_MAX);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(tscm, rate, &tscm->tx_stream);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(tscm, rate, &tscm->rx_stream);
+ if (err < 0) {
+ fw_iso_resources_free(&tscm->tx_resources);
+ return err;
+ }
}
- if (!amdtp_stream_running(&tscm->rx_stream)) {
- err = keep_resources(tscm, rate);
+ return 0;
+}
+
+int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+{
+ unsigned int generation = tscm->rx_resources.generation;
+ int err;
+
+ if (tscm->substreams_counter == 0)
+ return 0;
+
+ if (amdtp_streaming_error(&tscm->rx_stream) ||
+ amdtp_streaming_error(&tscm->tx_stream))
+ finish_session(tscm);
+
+ if (generation != fw_parent_device(tscm->unit)->card->generation) {
+ err = fw_iso_resources_update(&tscm->tx_resources);
+ if (err < 0)
+ goto error;
+
+ err = fw_iso_resources_update(&tscm->rx_resources);
if (err < 0)
goto error;
+ }
+ if (!amdtp_stream_running(&tscm->rx_stream)) {
err = set_stream_formats(tscm, rate);
if (err < 0)
goto error;
@@ -432,25 +439,19 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
return 0;
error:
- amdtp_stream_stop(&tscm->rx_stream);
- amdtp_stream_stop(&tscm->tx_stream);
-
finish_session(tscm);
- release_resources(tscm);
return err;
}
void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
{
- if (tscm->substreams_counter > 0)
- return;
-
- amdtp_stream_stop(&tscm->tx_stream);
- amdtp_stream_stop(&tscm->rx_stream);
+ if (tscm->substreams_counter == 0) {
+ finish_session(tscm);
- finish_session(tscm);
- release_resources(tscm);
+ fw_iso_resources_free(&tscm->tx_resources);
+ fw_iso_resources_free(&tscm->rx_resources);
+ }
}
void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index 1d003d4cf448..734e5bb9c3da 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -146,6 +146,7 @@ int snd_tscm_stream_get_clock(struct snd_tscm *tscm,
int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate);
int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index b02f74528b66..3b0110545070 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -79,6 +79,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
snd_hdac_chip_writew(bus, RINTCNT, 1);
/* enable rirb dma and response irq */
snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
+ /* Accept unsolicited responses */
+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
@@ -241,6 +243,8 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
for (loopcounter = 0;; loopcounter++) {
spin_lock_irq(&bus->reg_lock);
+ if (bus->polling_mode)
+ snd_hdac_bus_update_rirb(bus);
if (!bus->rirb.cmds[addr]) {
if (res)
*res = bus->rirb.res[addr]; /* the last value */
@@ -415,9 +419,6 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
return -EBUSY;
}
- /* Accept unsolicited responses */
- snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
-
/* detect codecs */
if (!bus->codec_mask) {
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 6907dbefd08c..b26cc93e7e10 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -90,7 +90,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
fg = codec->afg ? codec->afg : codec->mfg;
- err = snd_hdac_refresh_widgets(codec, false);
+ err = snd_hdac_refresh_widgets(codec);
if (err < 0)
goto error;
@@ -395,32 +395,35 @@ static void setup_fg_nodes(struct hdac_device *codec)
/**
* snd_hdac_refresh_widgets - Reset the widget start/end nodes
* @codec: the codec object
- * @sysfs: re-initialize sysfs tree, too
*/
-int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs)
+int snd_hdac_refresh_widgets(struct hdac_device *codec)
{
hda_nid_t start_nid;
- int nums, err;
+ int nums, err = 0;
+ /*
+ * Serialize against multiple threads trying to update the sysfs
+ * widgets array.
+ */
+ mutex_lock(&codec->widget_lock);
nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
if (!start_nid || nums <= 0 || nums >= 0xff) {
dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n",
codec->afg);
- return -EINVAL;
+ err = -EINVAL;
+ goto unlock;
}
- if (sysfs) {
- mutex_lock(&codec->widget_lock);
- err = hda_widget_sysfs_reinit(codec, start_nid, nums);
- mutex_unlock(&codec->widget_lock);
- if (err < 0)
- return err;
- }
+ err = hda_widget_sysfs_reinit(codec, start_nid, nums);
+ if (err < 0)
+ goto unlock;
codec->num_nodes = nums;
codec->start_nid = start_nid;
codec->end_nid = start_nid + nums;
- return 0;
+unlock:
+ mutex_unlock(&codec->widget_lock);
+ return err;
}
EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index 1192c7561d62..3c2db3816029 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -136,10 +136,12 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
if (!acomp)
return -ENODEV;
if (!acomp->ops) {
- request_module("i915");
- /* 60s timeout */
- wait_for_completion_timeout(&bind_complete,
- msecs_to_jiffies(60 * 1000));
+ if (!IS_ENABLED(CONFIG_MODULES) ||
+ !request_module("i915")) {
+ /* 60s timeout */
+ wait_for_completion_timeout(&bind_complete,
+ msecs_to_jiffies(60 * 1000));
+ }
}
if (!acomp->ops) {
dev_info(bus->dev, "couldn't bind with audio component\n");
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c
index 909d5ef1179c..e56e83325903 100644
--- a/sound/hda/hdac_sysfs.c
+++ b/sound/hda/hdac_sysfs.c
@@ -428,7 +428,7 @@ int hda_widget_sysfs_reinit(struct hdac_device *codec,
int i;
if (!codec->widgets)
- return hda_widget_sysfs_init(codec);
+ return 0;
tree = kmemdup(codec->widgets, sizeof(*tree), GFP_KERNEL);
if (!tree)
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index e7234f3d99e2..2a21a3d99719 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1519,7 +1519,6 @@ static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- int change;
u32 h_control = kcontrol->private_value;
short an_gain_mB[HPI_MAX_CHANNELS];
@@ -1530,9 +1529,8 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
/* change = asihpi->mixer_volume[addr][0] != left ||
asihpi->mixer_volume[addr][1] != right;
*/
- change = 1;
hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
- return change;
+ return 1;
}
static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
@@ -1555,13 +1553,12 @@ static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 h_control = kcontrol->private_value;
- int change = 1;
/* HPI currently only supports all or none muting of multichannel volume
ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted
*/
int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;
hpi_handle_error(hpi_volume_set_mute(h_control, mute));
- return change;
+ return 1;
}
static int snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index 73471037d59f..2db183f8826a 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -765,7 +765,7 @@ snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
- int changed = 1, i;
+ int i;
int coord[6];
for (i = 0; i < 6; i++)
coord[i] = ucontrol->value.integer.value[i];
@@ -774,7 +774,7 @@ snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
vortex_a3d_coord2hrtf(a->hrtf[1], coord);
a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);
a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);
- return changed;
+ return 1;
}
static int
@@ -783,7 +783,7 @@ snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
{
a3dsrc_t *a = kcontrol->private_data;
int coord[6];
- int i, changed = 1;
+ int i;
for (i = 0; i < 6; i++)
coord[i] = ucontrol->value.integer.value[i];
/* Translate orientation coordinates to a3d params. */
@@ -793,7 +793,7 @@ snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);
a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);
a3dsrc_SetItdDline(a, a->dline);
- return changed;
+ return 1;
}
static int
@@ -801,7 +801,6 @@ snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
- int changed = 1;
int l, r;
/* There may be some scale tranlation needed here. */
l = ucontrol->value.integer.value[0];
@@ -810,7 +809,7 @@ snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
/* Left Right panning. */
a3dsrc_SetGainTarget(a, l, r);
a3dsrc_SetGainCurrent(a, l, r);
- return changed;
+ return 1;
}
static int
@@ -818,7 +817,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
- int i, changed = 1;
+ int i;
int params[6];
for (i = 0; i < 6; i++)
params[i] = ucontrol->value.integer.value[i];
@@ -831,7 +830,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
a3dsrc_SetAtmosCurrent(a, a->filter[0],
a->filter[1], a->filter[2],
a->filter[3], a->filter[4]);
- return changed;
+ return 1;
}
static const struct snd_kcontrol_new vortex_a3d_kcontrol = {
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index a2cce3ecda6f..04c712647853 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -694,7 +694,7 @@ static int snd_cs4281_trigger(struct snd_pcm_substream *substream, int cmd)
static unsigned int snd_cs4281_rate(unsigned int rate, unsigned int *real_rate)
{
- unsigned int val = ~0;
+ unsigned int val;
if (real_rate)
*real_rate = rate;
@@ -707,9 +707,8 @@ static unsigned int snd_cs4281_rate(unsigned int rate, unsigned int *real_rate)
case 44100: return 1;
case 48000: return 0;
default:
- goto __variable;
+ break;
}
- __variable:
val = 1536000 / rate;
if (real_rate)
*real_rate = 1536000 / val;
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index b181752b8481..50d4a87a6bb3 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -1058,7 +1058,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
{
int i;
u32 channel_mask;
- char is_cyclic;
dev_dbg(chip->card->dev,
"allocate_pipes: ch=%d int=%d\n", pipe_index, interleave);
@@ -1066,8 +1065,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
if (chip->bad_board)
return -EIO;
- is_cyclic = 1; /* This driver uses cyclic buffers only */
-
for (channel_mask = i = 0; i < interleave; i++)
channel_mask |= 1 << (pipe_index + i);
if (chip->pipe_alloc_mask & channel_mask) {
@@ -1078,8 +1075,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
chip->comm_page->position[pipe_index] = 0;
chip->pipe_alloc_mask |= channel_mask;
- if (is_cyclic)
- chip->pipe_cyclic_mask |= channel_mask;
+ /* This driver uses cyclic buffers only */
+ chip->pipe_cyclic_mask |= channel_mask;
pipe->index = pipe_index;
pipe->interleave = interleave;
pipe->state = PIPE_STATE_STOPPED;
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 67d6473ab0cd..9cf81832259c 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1074,7 +1074,6 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
{
struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
unsigned int val;
- int change = 0;
val = ucontrol->value.integer.value[0] ;
@@ -1089,7 +1088,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x1003F);
snd_emu10k1x_gpio_write(emu, 0x1080);
}
- return change;
+ return 0;
}
static const struct snd_kcontrol_new snd_emu10k1x_shared_spdif =
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 6c51b8363f8b..51f10ed9bc43 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -108,7 +108,7 @@ static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
{
struct hda_conn_list *p;
- p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL);
+ p = kmalloc(struct_size(p, conns, len), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->len = len;
@@ -1002,7 +1002,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
hda_nid_t fg;
int err;
- err = snd_hdac_refresh_widgets(&codec->core, true);
+ err = snd_hdac_refresh_widgets(&codec->core);
if (err < 0)
return err;
@@ -2941,15 +2941,19 @@ static int hda_codec_runtime_resume(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int hda_codec_force_resume(struct device *dev)
{
+ struct hda_codec *codec = dev_to_hda_codec(dev);
+ bool forced_resume = !codec->relaxed_resume && codec->jacktbl.used;
int ret;
/* The get/put pair below enforces the runtime resume even if the
* device hasn't been used at suspend time. This trick is needed to
* update the jack state change during the sleep.
*/
- pm_runtime_get_noresume(dev);
+ if (forced_resume)
+ pm_runtime_get_noresume(dev);
ret = pm_runtime_force_resume(dev);
- pm_runtime_put(dev);
+ if (forced_resume)
+ pm_runtime_put(dev);
return ret;
}
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 232a1926758a..c8d1b4316245 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -795,11 +795,11 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
for (loopcounter = 0;; loopcounter++) {
spin_lock_irq(&bus->reg_lock);
- if (chip->polling_mode || do_poll)
+ if (bus->polling_mode || do_poll)
snd_hdac_bus_update_rirb(bus);
if (!bus->rirb.cmds[addr]) {
if (!do_poll)
- chip->poll_count = 0;
+ bus->poll_count = 0;
if (res)
*res = bus->rirb.res[addr]; /* the last value */
spin_unlock_irq(&bus->reg_lock);
@@ -819,21 +819,21 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
if (hbus->no_response_fallback)
return -EIO;
- if (!chip->polling_mode && chip->poll_count < 2) {
+ if (!bus->polling_mode && bus->poll_count < 2) {
dev_dbg(chip->card->dev,
"azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
bus->last_cmd[addr]);
do_poll = 1;
- chip->poll_count++;
+ bus->poll_count++;
goto again;
}
- if (!chip->polling_mode) {
+ if (!bus->polling_mode) {
dev_warn(chip->card->dev,
"azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
bus->last_cmd[addr]);
- chip->polling_mode = 1;
+ bus->polling_mode = 1;
goto again;
}
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index 3aa5c957ffbf..baa15374fbcb 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -133,11 +133,9 @@ struct azx {
/* flags */
int bdl_pos_adj;
- int poll_count;
unsigned int running:1;
unsigned int fallback_to_single_cmd:1;
unsigned int single_cmd:1;
- unsigned int polling_mode:1;
unsigned int msi:1;
unsigned int probing:1; /* codec probing phase */
unsigned int snoop:1;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 50f86f458918..1e14d7270adf 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -313,11 +313,10 @@ enum {
#define AZX_DCAPS_INTEL_SKYLAKE \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
+ AZX_DCAPS_SYNC_WRITE |\
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
-#define AZX_DCAPS_INTEL_BROXTON \
- (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
- AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
+#define AZX_DCAPS_INTEL_BROXTON AZX_DCAPS_INTEL_SKYLAKE
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
@@ -1687,10 +1686,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
else
chip->bdl_pos_adj = bdl_pos_adj[dev];
- /* Workaround for a communication error on CFL (bko#199007) and CNL */
- if (IS_CFL(pci) || IS_CNL(pci))
- chip->polling_mode = 1;
-
err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
if (err < 0) {
kfree(hda);
@@ -1698,6 +1693,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
+ /* Workaround for a communication error on CFL (bko#199007) and CNL */
+ if (IS_CFL(pci) || IS_CNL(pci))
+ azx_bus(chip)->polling_mode = 1;
+
if (chip->driver_type == AZX_DRIVER_NVIDIA) {
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
chip->bus.needs_damn_long_delay = 1;
@@ -2374,6 +2373,9 @@ static const struct pci_device_id azx_ids[] = {
/* Icelake */
{ PCI_DEVICE(0x8086, 0x34c8),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ /* Elkhart Lake */
+ { PCI_DEVICE(0x8086, 0x4b55),
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
/* Broxton-P(Apollolake) */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 6d9acd5c4e41..1fb7b06457ae 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -559,7 +559,7 @@ static void call_jack_callback(struct hda_codec *codec, unsigned int res,
void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct hda_jack_tbl *event;
- int tag = (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x7f;
+ int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT;
event = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (!event)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index c3096796ee05..0d51823d7270 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -2718,7 +2718,7 @@ static bool is_last(const struct dsp_image_seg *p)
static size_t dsp_sizeof(const struct dsp_image_seg *p)
{
- return sizeof(*p) + p->count*sizeof(u32);
+ return struct_size(p, data, p->count);
}
static const struct dsp_image_seg *get_next_seg_ptr(
@@ -5980,7 +5980,7 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol,
int ch = get_amp_channels(kcontrol);
long *valp = ucontrol->value.integer.value;
hda_nid_t vnid = 0;
- int changed = 1;
+ int changed;
switch (nid) {
case 0x02:
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 4f8d0845ee1e..f299f137eaea 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -1083,6 +1083,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
*/
static const struct hda_device_id snd_hda_id_conexant[] = {
+ HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index b7bde55b6adf..bea7b0961080 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1614,7 +1614,8 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
if (jack == NULL)
goto unlock;
snd_jack_report(jack,
- eld->monitor_present ? SND_JACK_AVOUT : 0);
+ (eld->monitor_present && eld->eld_valid) ?
+ SND_JACK_AVOUT : 0);
unlock:
mutex_unlock(&per_pin->lock);
}
@@ -2291,8 +2292,10 @@ static void generic_hdmi_free(struct hda_codec *codec)
struct hdmi_spec *spec = codec->spec;
int pin_idx, pcm_idx;
- if (codec_has_acomp(codec))
+ if (codec_has_acomp(codec)) {
snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
+ codec->relaxed_resume = 0;
+ }
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -2416,7 +2419,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
}
#define INTEL_GET_VENDOR_VERB 0xf81
-#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
@@ -2524,18 +2526,32 @@ static int intel_pin2port(void *audio_ptr, int pin_nid)
return -1;
}
+static int intel_port2pin(struct hda_codec *codec, int port)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (!spec->port_num) {
+ /* we assume only from port-B to port-D */
+ if (port < 1 || port > 3)
+ return 0;
+ /* intel port is 1-based */
+ return port + intel_base_nid(codec) - 1;
+ }
+
+ if (port < 1 || port > spec->port_num)
+ return 0;
+ return spec->port_map[port - 1];
+}
+
static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
{
struct hda_codec *codec = audio_ptr;
int pin_nid;
int dev_id = pipe;
- /* we assume only from port-B to port-D */
- if (port < 1 || port > 3)
+ pin_nid = intel_port2pin(codec, port);
+ if (!pin_nid)
return;
-
- pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
-
/* skip notification during system suspend (but not in runtime PM);
* the state will be updated at resume
*/
@@ -2565,6 +2581,8 @@ static void register_i915_notifier(struct hda_codec *codec)
spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
snd_hdac_acomp_register_notifier(&codec->bus->core,
&spec->drm_audio_ops);
+ /* no need for forcible resume for jack check thanks to notifier */
+ codec->relaxed_resume = 1;
}
/* setup_stream ops override for HSW+ */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 5b3c26991f26..de224cbea7a0 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2448,9 +2448,10 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x96e1, "System76 Oryx Pro (oryp5)", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x97e1, "System76 Oryx Pro (oryp5)", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65d1, "Tuxedo Book XC1509", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
@@ -3254,6 +3255,7 @@ static void alc256_init(struct hda_codec *codec)
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
+ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
}
static void alc256_shutup(struct hda_codec *codec)
@@ -7074,6 +7076,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+ SND_PCI_QUIRK(0x17aa, 0x3111, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x312a, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -7654,9 +7657,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x12, 0x90a60130},
{0x17, 0x90170110},
{0x21, 0x03211020}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
{0x14, 0x90170110},
{0x21, 0x04211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+ {0x14, 0x90170110},
+ {0x21, 0x04211030}),
SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC295_STANDARD_PINS,
{0x17, 0x21014020},
@@ -7823,7 +7829,6 @@ static int patch_alc269(struct hda_codec *codec)
spec->shutup = alc256_shutup;
spec->init_hook = alc256_init;
spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
- alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
break;
case 0x10ec0257:
spec->codec_variant = ALC269_TYPE_ALC257;
@@ -8798,6 +8803,11 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
{0x18, 0x01a19030},
{0x1a, 0x01813040},
{0x21, 0x01014020}),
+ SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+ {0x16, 0x01813030},
+ {0x17, 0x02211010},
+ {0x18, 0x01a19040},
+ {0x21, 0x01014020}),
SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
{0x14, 0x01014010},
{0x18, 0x01a19020},
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 1771a6dcbe18..583ca7384d83 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -253,9 +253,8 @@ exit:
static int lx_pcm_close(struct snd_pcm_substream *substream)
{
- int err = 0;
dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n");
- return err;
+ return 0;
}
static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index 9236a1a8c49b..dd3a873777eb 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -986,8 +986,6 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
* Stat[8] LSB overrun
* */
- u64 orun_mask;
- u64 urun_mask;
int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
@@ -1010,9 +1008,6 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
*r_notified_out_pipe_mask);
}
- orun_mask = ((u64)stat[7] << 32) + stat[8];
- urun_mask = ((u64)stat[5] << 32) + stat[6];
-
/* todo: handle xrun notification */
return err;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 6f5eaa510bbc..81a6f4b2bd3c 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -23,6 +23,9 @@
* Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth
*
* Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth
+ *
+ * Modified 2019-05-23 fix AIO single speed ADAT capture and playback
+ * by Philippe.Bekaert@uhasselt.be
*/
/* ************* Register Documentation *******************************************************
@@ -1091,9 +1094,9 @@ static int hdspm_autosync_ref(struct hdspm *hdspm);
static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
static int snd_hdspm_set_defaults(struct hdspm *hdspm);
static int hdspm_system_clock_mode(struct hdspm *hdspm);
-static void hdspm_set_sgbuf(struct hdspm *hdspm,
- struct snd_pcm_substream *substream,
- unsigned int reg, int channels);
+static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
+ struct snd_pcm_substream *substream,
+ unsigned int reg, int channels);
static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
static int hdspm_wc_sync_check(struct hdspm *hdspm);
@@ -5574,11 +5577,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferOut,
- params_channels(params));
+ for (i = 0; i < params_channels(params); ++i) {
+ int c = hdspm->channel_map_out[i];
- for (i = 0; i < params_channels(params); ++i)
- snd_hdspm_enable_out(hdspm, i, 1);
+ if (c < 0)
+ continue; /* just make sure */
+ hdspm_set_channel_dma_addr(hdspm, substream,
+ HDSPM_pageAddressBufferOut,
+ c);
+ snd_hdspm_enable_out(hdspm, c, 1);
+ }
hdspm->playback_buffer =
(unsigned char *) substream->runtime->dma_area;
@@ -5586,11 +5594,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
"Allocated sample buffer for playback at %p\n",
hdspm->playback_buffer);
} else {
- hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn,
- params_channels(params));
-
- for (i = 0; i < params_channels(params); ++i)
- snd_hdspm_enable_in(hdspm, i, 1);
+ for (i = 0; i < params_channels(params); ++i) {
+ int c = hdspm->channel_map_in[i];
+
+ if (c < 0)
+ continue;
+ hdspm_set_channel_dma_addr(hdspm, substream,
+ HDSPM_pageAddressBufferIn,
+ c);
+ snd_hdspm_enable_in(hdspm, c, 1);
+ }
hdspm->capture_buffer =
(unsigned char *) substream->runtime->dma_area;
@@ -5651,19 +5664,17 @@ static int snd_hdspm_hw_free(struct snd_pcm_substream *substream)
struct hdspm *hdspm = snd_pcm_substream_chip(substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-
- /* params_channels(params) should be enough,
- but to get sure in case of error */
- for (i = 0; i < hdspm->max_channels_out; ++i)
+ /* Just disable all channels. The saving when disabling a */
+ /* smaller set is not worth the trouble. */
+ for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
snd_hdspm_enable_out(hdspm, i, 0);
hdspm->playback_buffer = NULL;
} else {
- for (i = 0; i < hdspm->max_channels_in; ++i)
+ for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
snd_hdspm_enable_in(hdspm, i, 0);
hdspm->capture_buffer = NULL;
-
}
snd_pcm_lib_free_pages(substream);
@@ -6402,17 +6413,17 @@ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm)
return 0;
}
-
-static void hdspm_set_sgbuf(struct hdspm *hdspm,
- struct snd_pcm_substream *substream,
- unsigned int reg, int channels)
+/* Inform the card what DMA addresses to use for the indicated channel. */
+/* Each channel got 16 4K pages allocated for DMA transfers. */
+static void hdspm_set_channel_dma_addr(struct hdspm *hdspm,
+ struct snd_pcm_substream *substream,
+ unsigned int reg, int channel)
{
int i;
- /* continuous memory segment */
- for (i = 0; i < (channels * 16); i++)
+ for (i = channel * 16; i < channel * 16 + 16; i++)
hdspm_write(hdspm, reg + 4 * i,
- snd_pcm_sgbuf_get_addr(substream, 4096 * i));
+ snd_pcm_sgbuf_get_addr(substream, 4096 * i));
}
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index cb9818af5b41..4c851f8dcaf8 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2158,13 +2158,12 @@ static int snd_rme9652_prepare(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
unsigned long flags;
- int result = 0;
spin_lock_irqsave(&rme9652->lock, flags);
if (!rme9652->running)
rme9652_reset_hw_pointer(rme9652);
spin_unlock_irqrestore(&rme9652->lock, flags);
- return result;
+ return 0;
}
static const struct snd_pcm_hardware snd_rme9652_playback_subinfo =
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 71b7fd344c58..c213eb7ca23c 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -628,7 +628,6 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
- int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -665,7 +664,7 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
}
- return ret;
+ return 0;
};
/*
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 9615e786d049..80dab5df9633 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -240,10 +240,8 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
/* For DSP_*, LRCLK's polarity must be inverted */
- if (fmt & SND_SOC_DAIFMT_DSP_A) {
- change_bit(ffs(AD193X_DAC_LEFT_HIGH) - 1,
- (unsigned long *)&dac_fmt);
- }
+ if (fmt & SND_SOC_DAIFMT_DSP_A)
+ dac_fmt ^= AD193X_DAC_LEFT_HIGH;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 47eee18b66a3..29918954e740 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -539,6 +539,29 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
}
/*
+ * Go through all converters and ensure connection is set to
+ * the correct pin as set via kcontrols.
+ */
+static void hdac_hdmi_verify_connect_sel_all_pins(struct hdac_device *hdev)
+{
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+ struct hdac_hdmi_port *port;
+ struct hdac_hdmi_cvt *cvt;
+ int cvt_idx = 0;
+
+ list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+ port = hdac_hdmi_get_port_from_cvt(hdev, hdmi, cvt);
+ if (port && port->pin) {
+ snd_hdac_codec_write(hdev, port->pin->nid, 0,
+ AC_VERB_SET_CONNECT_SEL, cvt_idx);
+ dev_dbg(&hdev->dev, "%s: %s set connect %d -> %d\n",
+ __func__, cvt->name, port->pin->nid, cvt_idx);
+ }
+ ++cvt_idx;
+ }
+}
+
+/*
* This tries to get a valid pin and set the HW constraints based on the
* ELD. Even if a valid pin is not found return success so that device open
* doesn't fail.
@@ -798,6 +821,14 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, pcm->format);
+
+ /*
+ * The connection indices are shared by all converters and
+ * may interfere with each other. Ensure correct
+ * routing for all converters at stream start.
+ */
+ hdac_hdmi_verify_connect_sel_all_pins(hdev);
+
break;
case SND_SOC_DAPM_POST_PMD:
@@ -2041,7 +2072,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
"Failed in parse and map nid with err: %d\n", ret);
return ret;
}
- snd_hdac_refresh_widgets(hdev, true);
+ snd_hdac_refresh_widgets(hdev);
/* ASoC specific initialization */
ret = devm_snd_soc_register_component(&hdev->dev, &hdmi_hda_codec,
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index e5dd05c94f62..9f5aee7de686 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1880,6 +1880,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
NAU8825_JACK_EJECT_DEBOUNCE_MASK,
nau8825->jack_eject_debounce << NAU8825_JACK_EJECT_DEBOUNCE_SFT);
+ /* Pull up IRQ pin */
+ regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+ NAU8825_IRQ_PIN_PULLUP | NAU8825_IRQ_PIN_PULL_EN,
+ NAU8825_IRQ_PIN_PULLUP | NAU8825_IRQ_PIN_PULL_EN);
/* Mask unneeded IRQs: 1 - disable, 0 - enable */
regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, 0x7ff, 0x7ff);
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index 5e60696460de..887bbff03ec6 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -168,6 +168,8 @@
#define NAU8825_JACK_POLARITY (1 << 1) /* 0 - active low, 1 - active high */
/* INTERRUPT_MASK (0xf) */
+#define NAU8825_IRQ_PIN_PULLUP (1 << 14)
+#define NAU8825_IRQ_PIN_PULL_EN (1 << 13)
#define NAU8825_IRQ_OUTPUT_EN (1 << 11)
#define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10)
#define NAU8825_IRQ_RMS_EN (1 << 8)
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index ebf2ca3249cb..288df245b2f0 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -423,9 +423,6 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_get_parent(codec_ep);
- of_node_put(codec_ep);
- of_node_put(codec_port);
-
/* get convert-xxx property */
memset(&adata, 0, sizeof(adata));
graph_parse_convert(dev, codec_ep, &adata);
@@ -445,6 +442,9 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
else
ret = func_noml(priv, cpu_ep, codec_ep, li);
+ of_node_put(codec_ep);
+ of_node_put(codec_port);
+
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 64db00353e18..daeaa396d928 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -551,7 +551,7 @@ static int sof_audio_probe(struct platform_device *pdev)
int dmic_be_num, hdmi_num;
int ret, ssp_amp, ssp_codec;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 7e093fb13c92..3362e71b4563 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -184,6 +184,25 @@ void skl_update_d0i3c(struct device *dev, bool enable)
snd_hdac_chip_readb(bus, VS_D0I3C));
}
+/**
+ * skl_dum_set - set DUM bit in EM2 register
+ * @bus: HD-audio core bus
+ *
+ * Addresses incorrect position reporting for capture streams.
+ * Used on device power up.
+ */
+static void skl_dum_set(struct hdac_bus *bus)
+{
+ /* For the DUM bit to be set, CRST needs to be out of reset state */
+ if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) {
+ skl_enable_miscbdcge(bus->dev, false);
+ snd_hdac_bus_exit_link_reset(bus);
+ skl_enable_miscbdcge(bus->dev, true);
+ }
+
+ snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
+}
+
/* called from IRQ */
static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
{
@@ -291,6 +310,7 @@ static int _skl_resume(struct hdac_bus *bus)
struct skl *skl = bus_to_skl(bus);
skl_init_pci(skl);
+ skl_dum_set(bus);
skl_init_chip(bus, true);
return skl_resume_dsp(skl);
@@ -950,6 +970,7 @@ static int skl_first_init(struct hdac_bus *bus)
/* initialize chip */
skl_init_pci(skl);
+ skl_dum_set(bus);
return skl_init_chip(bus, true);
}
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 6fab1a2e133a..6070666a6392 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -37,6 +37,7 @@
#define DMA_TRANSMITION_START 2
#define DMA_TRANSMITION_STOP 3
+#define AZX_VS_EM2_DUM BIT(23)
#define AZX_REG_VS_EM2_L1SEN BIT(13)
struct skl_dsp_resource {
diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h
index e578b6f40a07..5774ce0916d4 100644
--- a/sound/soc/meson/axg-tdm.h
+++ b/sound/soc/meson/axg-tdm.h
@@ -40,7 +40,7 @@ struct axg_tdm_iface {
static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
{
- return (fmt & SND_SOC_DAIFMT_I2S) ^
+ return ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) ^
!!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
}
diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c
index a790f925a4ef..cb87f17f3e95 100644
--- a/sound/soc/meson/axg-tdmin.c
+++ b/sound/soc/meson/axg-tdmin.c
@@ -121,7 +121,6 @@ static int axg_tdmin_prepare(struct regmap *map,
break;
case SND_SOC_DAIFMT_LEFT_J:
- case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_DSP_B:
break;
diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c
index 527bfc4487e0..86537fc0ecb5 100644
--- a/sound/soc/meson/axg-tdmout.c
+++ b/sound/soc/meson/axg-tdmout.c
@@ -137,7 +137,6 @@ static int axg_tdmout_prepare(struct regmap *map,
break;
case SND_SOC_DAIFMT_LEFT_J:
- case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_DSP_B:
skew += 1;
break;
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 97488b5cc515..2c7348ddbbb3 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -116,6 +116,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
goto err;
}
+ link->nonatomic = 1;
link->dpcm_playback = 1;
link->dpcm_capture = 1;
link->stream_name = link->name;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1486fb2eb921..44f899b970c2 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -165,9 +165,10 @@ static void soc_init_component_debugfs(struct snd_soc_component *component)
component->card->debugfs_card_root);
}
- if (!component->debugfs_root) {
+ if (IS_ERR(component->debugfs_root)) {
dev_warn(component->dev,
- "ASoC: Failed to create component debugfs directory\n");
+ "ASoC: Failed to create component debugfs directory: %ld\n",
+ PTR_ERR(component->debugfs_root));
return;
}
@@ -219,18 +220,21 @@ static void soc_init_card_debugfs(struct snd_soc_card *card)
card->debugfs_card_root = debugfs_create_dir(card->name,
snd_soc_debugfs_root);
- if (!card->debugfs_card_root) {
+ if (IS_ERR(card->debugfs_card_root)) {
dev_warn(card->dev,
- "ASoC: Failed to create card debugfs directory\n");
+ "ASoC: Failed to create card debugfs directory: %ld\n",
+ PTR_ERR(card->debugfs_card_root));
+ card->debugfs_card_root = NULL;
return;
}
card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
card->debugfs_card_root,
&card->pop_time);
- if (!card->debugfs_pop_time)
+ if (IS_ERR(card->debugfs_pop_time))
dev_warn(card->dev,
- "ASoC: Failed to create pop time debugfs file\n");
+ "ASoC: Failed to create pop time debugfs file: %ld\n",
+ PTR_ERR(card->debugfs_pop_time));
}
static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
@@ -2748,14 +2752,12 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
snd_soc_dapm_shutdown(card);
snd_soc_flush_all_delayed_work(card);
- mutex_lock(&client_mutex);
/* remove all components used by DAI links on this card */
for_each_comp_order(order) {
for_each_card_rtds(card, rtd) {
soc_remove_link_components(card, rtd, order);
}
}
- mutex_unlock(&client_mutex);
soc_cleanup_card_resources(card);
if (!unregister)
@@ -2774,7 +2776,9 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
*/
int snd_soc_unregister_card(struct snd_soc_card *card)
{
+ mutex_lock(&client_mutex);
snd_soc_unbind_card(card, true);
+ mutex_unlock(&client_mutex);
dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
return 0;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 656cb5cd9cd8..2790c00735f3 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2156,23 +2156,25 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
{
struct dentry *d;
- if (!parent)
+ if (!parent || IS_ERR(parent))
return;
dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
- if (!dapm->debugfs_dapm) {
+ if (IS_ERR(dapm->debugfs_dapm)) {
dev_warn(dapm->dev,
- "ASoC: Failed to create DAPM debugfs directory\n");
+ "ASoC: Failed to create DAPM debugfs directory %ld\n",
+ PTR_ERR(dapm->debugfs_dapm));
return;
}
d = debugfs_create_file("bias_level", 0444,
dapm->debugfs_dapm, dapm,
&dapm_bias_fops);
- if (!d)
+ if (IS_ERR(d))
dev_warn(dapm->dev,
- "ASoC: Failed to create bias level debugfs file\n");
+ "ASoC: Failed to create bias level debugfs file: %ld\n",
+ PTR_ERR(d));
}
static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
@@ -2186,10 +2188,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
d = debugfs_create_file(w->name, 0444,
dapm->debugfs_dapm, w,
&dapm_widget_power_fops);
- if (!d)
+ if (IS_ERR(d))
dev_warn(w->dapm->dev,
- "ASoC: Failed to create %s debugfs file\n",
- w->name);
+ "ASoC: Failed to create %s debugfs file: %ld\n",
+ w->name, PTR_ERR(d));
}
static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 136f98bf5d7e..7f665392618f 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -34,6 +34,9 @@
/* platform specific devices */
#include "shim.h"
+#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
+#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8)
+
/*
* Debug
*/
@@ -245,6 +248,11 @@ static int hda_init(struct snd_sof_dev *sdev)
ext_ops = snd_soc_hdac_hda_get_ops();
#endif
sof_hda_bus_init(bus, &pci->dev, ext_ops);
+
+ /* Workaround for a communication error on CFL (bko#199007) and CNL */
+ if (IS_CFL(pci) || IS_CNL(pci))
+ bus->polling_mode = 1;
+
bus->use_posbuf = 1;
bus->bdl_pos_adj = 0;
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 44708c8f90d6..bc7bf15ed7a4 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -2297,7 +2297,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = edma_pcm_platform_register(&pdev->dev);
break;
case PCM_SDMA:
- ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+ ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
break;
default:
dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index 1ab3c7df4f8b..26b503bbdb5f 100644
--- a/sound/soc/ti/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -1424,7 +1424,7 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
if (ret)
return ret;
- return sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+ return sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
}
static int asoc_mcbsp_remove(struct platform_device *pdev)
diff --git a/sound/usb/format.c b/sound/usb/format.c
index c02b51a82775..d79db71305f6 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -285,6 +285,33 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
return nr_rates;
}
+/* Line6 Helix series don't support the UAC2_CS_RANGE usb function
+ * call. Return a static table of known clock rates.
+ */
+static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip,
+ struct audioformat *fp)
+{
+ switch (chip->usb_id) {
+ case USB_ID(0x0E41, 0x4241): /* Line6 Helix */
+ case USB_ID(0x0E41, 0x4242): /* Line6 Helix Rack */
+ case USB_ID(0x0E41, 0x4244): /* Line6 Helix LT */
+ case USB_ID(0x0E41, 0x4246): /* Line6 HX-Stomp */
+ /* supported rates: 48Khz */
+ kfree(fp->rate_table);
+ fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL);
+ if (!fp->rate_table)
+ return -ENOMEM;
+ fp->nr_rates = 1;
+ fp->rate_min = 48000;
+ fp->rate_max = 48000;
+ fp->rates = SNDRV_PCM_RATE_48000;
+ fp->rate_table[0] = 48000;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
/*
* parse the format descriptor and stores the possible sample rates
* on the audioformat table (audio class v2 and v3).
@@ -294,7 +321,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
{
struct usb_device *dev = chip->dev;
unsigned char tmp[2], *data;
- int nr_triplets, data_size, ret = 0;
+ int nr_triplets, data_size, ret = 0, ret_l6;
int clock = snd_usb_clock_find_source(chip, fp->protocol,
fp->clock, false);
@@ -313,9 +340,22 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
tmp, sizeof(tmp));
if (ret < 0) {
- dev_err(&dev->dev,
- "%s(): unable to retrieve number of sample rates (clock %d)\n",
+ /* line6 helix devices don't support UAC2_CS_CONTROL_SAM_FREQ call */
+ ret_l6 = line6_parse_audio_format_rates_quirk(chip, fp);
+ if (ret_l6 == -ENODEV) {
+ /* no line6 device found continue showing the error */
+ dev_err(&dev->dev,
+ "%s(): unable to retrieve number of sample rates (clock %d)\n",
+ __func__, clock);
+ goto err;
+ }
+ if (ret_l6 == 0) {
+ dev_info(&dev->dev,
+ "%s(): unable to retrieve number of sample rates: set it to a predefined value (clock %d).\n",
__func__, clock);
+ return 0;
+ }
+ ret = ret_l6;
goto err;
}
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index 84aa265dd802..4c12cc5b53fd 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -63,6 +63,20 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
return NULL;
}
+/* check the validity of pipe and EP types */
+int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe)
+{
+ static const int pipetypes[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+ };
+ struct usb_host_endpoint *ep;
+
+ ep = usb_pipe_endpoint(dev, pipe);
+ if (!ep || usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)])
+ return -EINVAL;
+ return 0;
+}
+
/*
* Wrapper for usb_control_msg().
* Allocates a temp buffer to prevent dmaing from/to the stack.
@@ -75,6 +89,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
void *buf = NULL;
int timeout;
+ if (snd_usb_pipe_sanity_check(dev, pipe))
+ return -EINVAL;
+
if (size > 0) {
buf = kmemdup(data, size, GFP_KERNEL);
if (!buf)
diff --git a/sound/usb/helper.h b/sound/usb/helper.h
index d338bd0e0ca6..6afb70156ec4 100644
--- a/sound/usb/helper.h
+++ b/sound/usb/helper.h
@@ -7,6 +7,7 @@ unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);
void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype);
void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype);
+int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe);
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size);
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index e63a2451c88f..ab2ec896f49c 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -192,17 +192,6 @@ static int line6_send_raw_message_async_part(struct message *msg,
}
/*
- Setup and start timer.
-*/
-void line6_start_timer(struct timer_list *timer, unsigned long msecs,
- void (*function)(struct timer_list *t))
-{
- timer->function = function;
- mod_timer(timer, jiffies + msecs_to_jiffies(msecs));
-}
-EXPORT_SYMBOL_GPL(line6_start_timer);
-
-/*
Asynchronously send raw message.
*/
int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
index a9f7b4aa32c4..e5e572ed5f30 100644
--- a/sound/usb/line6/driver.h
+++ b/sound/usb/line6/driver.h
@@ -64,13 +64,6 @@
#define LINE6_CHANNEL_MASK 0x0f
-#define CHECK_STARTUP_PROGRESS(x, n) \
-do { \
- if ((x) >= (n)) \
- return; \
- x = (n); \
-} while (0)
-
extern const unsigned char line6_midi_id[3];
static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
@@ -197,8 +190,6 @@ extern int line6_send_sysex_message(struct usb_line6 *line6,
const char *buffer, int size);
extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
-extern void line6_start_timer(struct timer_list *timer, unsigned long msecs,
- void (*function)(struct timer_list *t));
extern int line6_version_request_async(struct usb_line6 *line6);
extern int line6_write_data(struct usb_line6 *line6, unsigned address,
void *data, unsigned datalen);
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
index 21127e4958b2..2c03e0f6bf72 100644
--- a/sound/usb/line6/pcm.c
+++ b/sound/usb/line6/pcm.c
@@ -556,6 +556,11 @@ int line6_init_pcm(struct usb_line6 *line6,
line6pcm->max_packet_size_out =
usb_maxpacket(line6->usbdev,
usb_sndisocpipe(line6->usbdev, ep_write), 1);
+ if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) {
+ dev_err(line6pcm->line6->ifcdev,
+ "cannot get proper max packet size\n");
+ return -EINVAL;
+ }
spin_lock_init(&line6pcm->out.lock);
spin_lock_init(&line6pcm->in.lock);
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
index 200ae53adf22..ee4c9d220fdf 100644
--- a/sound/usb/line6/pod.c
+++ b/sound/usb/line6/pod.c
@@ -35,11 +35,9 @@
Stages of POD startup procedure
*/
enum {
- POD_STARTUP_INIT = 1,
POD_STARTUP_VERSIONREQ,
- POD_STARTUP_WORKQUEUE,
POD_STARTUP_SETUP,
- POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
+ POD_STARTUP_DONE,
};
enum {
@@ -59,12 +57,6 @@ struct usb_line6_pod {
/* Instrument monitor level */
int monitor_level;
- /* Timer for device initialization */
- struct timer_list startup_timer;
-
- /* Work handler for device initialization */
- struct work_struct startup_work;
-
/* Current progress in startup procedure */
int startup_progress;
@@ -78,6 +70,8 @@ struct usb_line6_pod {
int device_id;
};
+#define line6_to_pod(x) container_of(x, struct usb_line6_pod, line6)
+
#define POD_SYSEX_CODE 3
/* *INDENT-OFF* */
@@ -169,10 +163,6 @@ static const char pod_version_header[] = {
0xf2, 0x7e, 0x7f, 0x06, 0x02
};
-/* forward declarations: */
-static void pod_startup2(struct timer_list *t);
-static void pod_startup3(struct usb_line6_pod *pod);
-
static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
int size)
{
@@ -185,14 +175,17 @@ static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
*/
static void line6_pod_process_message(struct usb_line6 *line6)
{
- struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+ struct usb_line6_pod *pod = line6_to_pod(line6);
const unsigned char *buf = pod->line6.buffer_message;
if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
(int) buf[10];
- pod_startup3(pod);
+ if (pod->startup_progress == POD_STARTUP_VERSIONREQ) {
+ pod->startup_progress = POD_STARTUP_SETUP;
+ schedule_delayed_work(&line6->startup_work, 0);
+ }
return;
}
@@ -277,47 +270,27 @@ static ssize_t device_id_show(struct device *dev,
context). After the last one has finished, the device is ready to use.
*/
-static void pod_startup1(struct usb_line6_pod *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2);
-}
-
-static void pod_startup2(struct timer_list *t)
-{
- struct usb_line6_pod *pod = from_timer(pod, t, startup_timer);
- struct usb_line6 *line6 = &pod->line6;
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
-
- /* request firmware version: */
- line6_version_request_async(line6);
-}
-
-static void pod_startup3(struct usb_line6_pod *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&pod->startup_work);
-}
-
-static void pod_startup4(struct work_struct *work)
+static void pod_startup(struct usb_line6 *line6)
{
- struct usb_line6_pod *pod =
- container_of(work, struct usb_line6_pod, startup_work);
- struct usb_line6 *line6 = &pod->line6;
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
-
- /* serial number: */
- line6_read_serial_number(&pod->line6, &pod->serial_number);
-
- /* ALSA audio interface: */
- if (snd_card_register(line6->card))
- dev_err(line6->ifcdev, "Failed to register POD card.\n");
+ struct usb_line6_pod *pod = line6_to_pod(line6);
+
+ switch (pod->startup_progress) {
+ case POD_STARTUP_VERSIONREQ:
+ /* request firmware version: */
+ line6_version_request_async(line6);
+ break;
+ case POD_STARTUP_SETUP:
+ /* serial number: */
+ line6_read_serial_number(&pod->line6, &pod->serial_number);
+
+ /* ALSA audio interface: */
+ if (snd_card_register(line6->card))
+ dev_err(line6->ifcdev, "Failed to register POD card.\n");
+ pod->startup_progress = POD_STARTUP_DONE;
+ break;
+ default:
+ break;
+ }
}
/* POD special files: */
@@ -353,7 +326,7 @@ static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+ struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6);
ucontrol->value.integer.value[0] = pod->monitor_level;
return 0;
@@ -364,7 +337,7 @@ static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+ struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6);
if (ucontrol->value.integer.value[0] == pod->monitor_level)
return 0;
@@ -387,30 +360,16 @@ static const struct snd_kcontrol_new pod_control_monitor = {
};
/*
- POD device disconnected.
-*/
-static void line6_pod_disconnect(struct usb_line6 *line6)
-{
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6;
-
- del_timer_sync(&pod->startup_timer);
- cancel_work_sync(&pod->startup_work);
-}
-
-/*
Try to init POD device.
*/
static int pod_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
int err;
- struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+ struct usb_line6_pod *pod = line6_to_pod(line6);
line6->process_message = line6_pod_process_message;
- line6->disconnect = line6_pod_disconnect;
-
- timer_setup(&pod->startup_timer, NULL, 0);
- INIT_WORK(&pod->startup_work, pod_startup4);
+ line6->startup = pod_startup;
/* create sysfs entries: */
err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group);
@@ -443,7 +402,8 @@ static int pod_init(struct usb_line6 *line6,
pod->monitor_level = POD_SYSTEM_INVALID;
/* initiate startup procedure: */
- pod_startup1(pod);
+ schedule_delayed_work(&line6->startup_work,
+ msecs_to_jiffies(POD_STARTUP_DELAY));
}
return 0;
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
index 77a1d55334bb..27bf61c177c0 100644
--- a/sound/usb/line6/podhd.c
+++ b/sound/usb/line6/podhd.c
@@ -18,16 +18,6 @@
#define PODHD_STARTUP_DELAY 500
-/*
- * Stages of POD startup procedure
- */
-enum {
- PODHD_STARTUP_INIT = 1,
- PODHD_STARTUP_SCHEDULE_WORKQUEUE,
- PODHD_STARTUP_SETUP,
- PODHD_STARTUP_LAST = PODHD_STARTUP_SETUP - 1
-};
-
enum {
LINE6_PODHD300,
LINE6_PODHD400,
@@ -43,15 +33,6 @@ struct usb_line6_podhd {
/* Generic Line 6 USB data */
struct usb_line6 line6;
- /* Timer for device initialization */
- struct timer_list startup_timer;
-
- /* Work handler for device initialization */
- struct work_struct startup_work;
-
- /* Current progress in startup procedure */
- int startup_progress;
-
/* Serial number of device */
u32 serial_number;
@@ -59,6 +40,8 @@ struct usb_line6_podhd {
int firmware_version;
};
+#define line6_to_podhd(x) container_of(x, struct usb_line6_podhd, line6)
+
static struct snd_ratden podhd_ratden = {
.num_min = 48000,
.num_max = 48000,
@@ -154,10 +137,6 @@ static struct line6_pcm_properties podx3_pcm_properties = {
};
static struct usb_driver podhd_driver;
-static void podhd_startup_start_workqueue(struct timer_list *t);
-static void podhd_startup_workqueue(struct work_struct *work);
-static int podhd_startup_finalize(struct usb_line6_podhd *pod);
-
static ssize_t serial_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -198,26 +177,6 @@ static const struct attribute_group podhd_dev_attr_group = {
* audio nor bulk interfaces to work.
*/
-static void podhd_startup(struct usb_line6_podhd *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&pod->startup_timer, PODHD_STARTUP_DELAY,
- podhd_startup_start_workqueue);
-}
-
-static void podhd_startup_start_workqueue(struct timer_list *t)
-{
- struct usb_line6_podhd *pod = from_timer(pod, t, startup_timer);
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress,
- PODHD_STARTUP_SCHEDULE_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&pod->startup_work);
-}
-
static int podhd_dev_start(struct usb_line6_podhd *pod)
{
int ret;
@@ -268,37 +227,23 @@ exit:
return ret;
}
-static void podhd_startup_workqueue(struct work_struct *work)
+static void podhd_startup(struct usb_line6 *line6)
{
- struct usb_line6_podhd *pod =
- container_of(work, struct usb_line6_podhd, startup_work);
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_SETUP);
+ struct usb_line6_podhd *pod = line6_to_podhd(line6);
podhd_dev_start(pod);
line6_read_serial_number(&pod->line6, &pod->serial_number);
-
- podhd_startup_finalize(pod);
-}
-
-static int podhd_startup_finalize(struct usb_line6_podhd *pod)
-{
- struct usb_line6 *line6 = &pod->line6;
-
- /* ALSA audio interface: */
- return snd_card_register(line6->card);
+ if (snd_card_register(line6->card))
+ dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
}
static void podhd_disconnect(struct usb_line6 *line6)
{
- struct usb_line6_podhd *pod = (struct usb_line6_podhd *)line6;
+ struct usb_line6_podhd *pod = line6_to_podhd(line6);
if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
struct usb_interface *intf;
- del_timer_sync(&pod->startup_timer);
- cancel_work_sync(&pod->startup_work);
-
intf = usb_ifnum_to_if(line6->usbdev,
pod->line6.properties->ctrl_if);
if (intf)
@@ -313,13 +258,11 @@ static int podhd_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
int err;
- struct usb_line6_podhd *pod = (struct usb_line6_podhd *) line6;
+ struct usb_line6_podhd *pod = line6_to_podhd(line6);
struct usb_interface *intf;
line6->disconnect = podhd_disconnect;
-
- timer_setup(&pod->startup_timer, NULL, 0);
- INIT_WORK(&pod->startup_work, podhd_startup_workqueue);
+ line6->startup = podhd_startup;
if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
/* claim the data interface */
@@ -358,11 +301,12 @@ static int podhd_init(struct usb_line6 *line6,
if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
/* register USB audio system directly */
- return podhd_startup_finalize(pod);
+ return snd_card_register(line6->card);
}
/* init device and delay registering */
- podhd_startup(pod);
+ schedule_delayed_work(&line6->startup_work,
+ msecs_to_jiffies(PODHD_STARTUP_DELAY));
return 0;
}
@@ -424,7 +368,7 @@ static const struct line6_properties podhd_properties_table[] = {
.name = "POD HD500",
.capabilities = LINE6_CAP_PCM
| LINE6_CAP_HWMON,
- .altsetting = 1,
+ .altsetting = 0,
.ep_ctrl_r = 0x81,
.ep_ctrl_w = 0x01,
.ep_audio_r = 0x86,
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index 974ab3e62b68..d0a555dbe324 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -57,6 +57,8 @@ struct usb_line6_toneport {
struct toneport_led leds[2];
};
+#define line6_to_toneport(x) container_of(x, struct usb_line6_toneport, line6)
+
static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
#define TONEPORT_PCM_DELAY 1
@@ -207,8 +209,8 @@ static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6pcm->line6;
+ struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
+
ucontrol->value.enumerated.item[0] = toneport->source;
return 0;
}
@@ -218,8 +220,7 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6pcm->line6;
+ struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
unsigned int source;
source = ucontrol->value.enumerated.item[0];
@@ -393,8 +394,7 @@ static int toneport_setup(struct usb_line6_toneport *toneport)
*/
static void line6_toneport_disconnect(struct usb_line6 *line6)
{
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6;
+ struct usb_line6_toneport *toneport = line6_to_toneport(line6);
if (toneport_has_led(toneport))
toneport_remove_leds(toneport);
@@ -408,7 +408,7 @@ static int toneport_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
int err;
- struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
+ struct usb_line6_toneport *toneport = line6_to_toneport(line6);
toneport->type = id->driver_info;
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c
index e59b97444399..ed158f04de80 100644
--- a/sound/usb/line6/variax.c
+++ b/sound/usb/line6/variax.c
@@ -22,13 +22,9 @@
Stages of Variax startup procedure
*/
enum {
- VARIAX_STARTUP_INIT = 1,
VARIAX_STARTUP_VERSIONREQ,
- VARIAX_STARTUP_WAIT,
VARIAX_STARTUP_ACTIVATE,
- VARIAX_STARTUP_WORKQUEUE,
VARIAX_STARTUP_SETUP,
- VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
};
enum {
@@ -43,17 +39,12 @@ struct usb_line6_variax {
/* Buffer for activation code */
unsigned char *buffer_activate;
- /* Handler for device initialization */
- struct work_struct startup_work;
-
- /* Timers for device initialization */
- struct timer_list startup_timer1;
- struct timer_list startup_timer2;
-
/* Current progress in startup procedure */
int startup_progress;
};
+#define line6_to_variax(x) container_of(x, struct usb_line6_variax, line6)
+
#define VARIAX_OFFSET_ACTIVATE 7
/*
@@ -77,11 +68,6 @@ static const char variax_activate[] = {
0xf7
};
-/* forward declarations: */
-static void variax_startup2(struct timer_list *t);
-static void variax_startup4(struct timer_list *t);
-static void variax_startup5(struct timer_list *t);
-
static void variax_activate_async(struct usb_line6_variax *variax, int a)
{
variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
@@ -96,74 +82,30 @@ static void variax_activate_async(struct usb_line6_variax *variax, int a)
context). After the last one has finished, the device is ready to use.
*/
-static void variax_startup1(struct usb_line6_variax *variax)
-{
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
- variax_startup2);
-}
-
-static void variax_startup2(struct timer_list *t)
-{
- struct usb_line6_variax *variax = from_timer(variax, t, startup_timer1);
- struct usb_line6 *line6 = &variax->line6;
-
- /* schedule another startup procedure until startup is complete: */
- if (variax->startup_progress >= VARIAX_STARTUP_LAST)
- return;
-
- variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
- line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
- variax_startup2);
-
- /* request firmware version: */
- line6_version_request_async(line6);
-}
-
-static void variax_startup3(struct usb_line6_variax *variax)
-{
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
-
- /* delay startup procedure: */
- line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
- variax_startup4);
-}
-
-static void variax_startup4(struct timer_list *t)
+static void variax_startup(struct usb_line6 *line6)
{
- struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2);
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress,
- VARIAX_STARTUP_ACTIVATE);
-
- /* activate device: */
- variax_activate_async(variax, 1);
- line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
- variax_startup5);
-}
-
-static void variax_startup5(struct timer_list *t)
-{
- struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2);
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress,
- VARIAX_STARTUP_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&variax->startup_work);
-}
-
-static void variax_startup6(struct work_struct *work)
-{
- struct usb_line6_variax *variax =
- container_of(work, struct usb_line6_variax, startup_work);
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-
- /* ALSA audio interface: */
- snd_card_register(variax->line6.card);
+ struct usb_line6_variax *variax = line6_to_variax(line6);
+
+ switch (variax->startup_progress) {
+ case VARIAX_STARTUP_VERSIONREQ:
+ /* repeat request until getting the response */
+ schedule_delayed_work(&line6->startup_work,
+ msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
+ /* request firmware version: */
+ line6_version_request_async(line6);
+ break;
+ case VARIAX_STARTUP_ACTIVATE:
+ /* activate device: */
+ variax_activate_async(variax, 1);
+ variax->startup_progress = VARIAX_STARTUP_SETUP;
+ schedule_delayed_work(&line6->startup_work,
+ msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
+ break;
+ case VARIAX_STARTUP_SETUP:
+ /* ALSA audio interface: */
+ snd_card_register(variax->line6.card);
+ break;
+ }
}
/*
@@ -171,7 +113,7 @@ static void variax_startup6(struct work_struct *work)
*/
static void line6_variax_process_message(struct usb_line6 *line6)
{
- struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+ struct usb_line6_variax *variax = line6_to_variax(line6);
const unsigned char *buf = variax->line6.buffer_message;
switch (buf[0]) {
@@ -182,11 +124,19 @@ static void line6_variax_process_message(struct usb_line6 *line6)
case LINE6_SYSEX_BEGIN:
if (memcmp(buf + 1, variax_init_version + 1,
sizeof(variax_init_version) - 1) == 0) {
- variax_startup3(variax);
+ if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
+ break;
+ variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
+ cancel_delayed_work(&line6->startup_work);
+ schedule_delayed_work(&line6->startup_work,
+ msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
} else if (memcmp(buf + 1, variax_init_done + 1,
sizeof(variax_init_done) - 1) == 0) {
/* notify of complete initialization: */
- variax_startup4(&variax->startup_timer2);
+ if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
+ break;
+ cancel_delayed_work(&line6->startup_work);
+ schedule_delayed_work(&line6->startup_work, 0);
}
break;
}
@@ -197,11 +147,7 @@ static void line6_variax_process_message(struct usb_line6 *line6)
*/
static void line6_variax_disconnect(struct usb_line6 *line6)
{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
-
- del_timer(&variax->startup_timer1);
- del_timer(&variax->startup_timer2);
- cancel_work_sync(&variax->startup_work);
+ struct usb_line6_variax *variax = line6_to_variax(line6);
kfree(variax->buffer_activate);
}
@@ -212,15 +158,12 @@ static void line6_variax_disconnect(struct usb_line6 *line6)
static int variax_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
- struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+ struct usb_line6_variax *variax = line6_to_variax(line6);
int err;
line6->process_message = line6_variax_process_message;
line6->disconnect = line6_variax_disconnect;
-
- timer_setup(&variax->startup_timer1, NULL, 0);
- timer_setup(&variax->startup_timer2, NULL, 0);
- INIT_WORK(&variax->startup_work, variax_startup6);
+ line6->startup = variax_startup;
/* initialize USB buffers: */
variax->buffer_activate = kmemdup(variax_activate,
@@ -235,7 +178,8 @@ static int variax_init(struct usb_line6 *line6,
return err;
/* initiate startup procedure: */
- variax_startup1(variax);
+ schedule_delayed_work(&line6->startup_work,
+ msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
return 0;
}
@@ -300,5 +244,5 @@ static struct usb_driver variax_driver = {
module_usb_driver(variax_driver);
-MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_DESCRIPTION("Variax Workbench USB driver");
MODULE_LICENSE("GPL");
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index c703f8534b07..7498b5191b68 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -2303,7 +2303,7 @@ static struct procunit_info extunits[] = {
*/
static int build_audio_procunit(struct mixer_build *state, int unitid,
void *raw_desc, struct procunit_info *list,
- char *name)
+ bool extension_unit)
{
struct uac_processing_unit_descriptor *desc = raw_desc;
int num_ins;
@@ -2320,6 +2320,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
static struct procunit_info default_info = {
0, NULL, default_value_info
};
+ const char *name = extension_unit ?
+ "Extension Unit" : "Processing Unit";
if (desc->bLength < 13) {
usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
@@ -2433,7 +2435,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
} else if (info->name) {
strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
} else {
- nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
+ if (extension_unit)
+ nameid = uac_extension_unit_iExtension(desc, state->mixer->protocol);
+ else
+ nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
len = 0;
if (nameid)
len = snd_usb_copy_string_desc(state->chip,
@@ -2466,10 +2471,10 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid,
case UAC_VERSION_2:
default:
return build_audio_procunit(state, unitid, raw_desc,
- procunits, "Processing Unit");
+ procunits, false);
case UAC_VERSION_3:
return build_audio_procunit(state, unitid, raw_desc,
- uac3_procunits, "Processing Unit");
+ uac3_procunits, false);
}
}
@@ -2480,8 +2485,7 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
* Note that we parse extension units with processing unit descriptors.
* That's ok as the layout is the same.
*/
- return build_audio_procunit(state, unitid, raw_desc,
- extunits, "Extension Unit");
+ return build_audio_procunit(state, unitid, raw_desc, extunits, true);
}
/*
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 1f6011f36bb0..199fa157a411 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -741,7 +741,7 @@ static int snd_ni_control_init_val(struct usb_mixer_interface *mixer,
return err;
}
- kctl->private_value |= (value << 24);
+ kctl->private_value |= ((unsigned int)value << 24);
return 0;
}
@@ -902,7 +902,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
if (err < 0)
return err;
- kctl->private_value |= value[0] << 24;
+ kctl->private_value |= (unsigned int)value[0] << 24;
return 0;
}
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 9e049f60e80e..e918ce346027 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2408,7 +2408,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
USB_DEVICE(0x086a, 0x0001),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.vendor_name = "Emagic",
- /* .product_name = "Unitor8", */
+ .product_name = "Unitor8",
.ifnum = 2,
.type = QUIRK_MIDI_EMAGIC,
.data = & (const struct snd_usb_midi_endpoint_info) {
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index cf5cff10c08e..78858918cbc1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -828,11 +828,13 @@ static int snd_usb_novation_boot_quirk(struct usb_device *dev)
static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
{
int err, actual_length;
-
/* "midi send" enable */
static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
+ void *buf;
- void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
+ if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x05)))
+ return -EINVAL;
+ buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
if (!buf)
return -ENOMEM;
err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
@@ -857,7 +859,11 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
{
- int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ int ret;
+
+ if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
+ return -EINVAL;
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 0, NULL, 0, 1000);
@@ -964,6 +970,8 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n");
+ if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
+ return -EINVAL;
/* If the Axe-Fx III has not fully booted, it will timeout when trying
* to enable the audio streaming interface. A more generous timeout is
* used here to detect when the Axe-Fx III has finished booting as the
@@ -996,6 +1004,8 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
{
int err, actual_length;
+ if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x01)))
+ return -EINVAL;
err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length,
&actual_length, 1000);
if (err < 0)
@@ -1006,6 +1016,8 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
memset(buf, 0, buf_size);
+ if (snd_usb_pipe_sanity_check(dev, usb_rcvintpipe(dev, 0x82)))
+ return -EINVAL;
err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size,
&actual_length, 1000);
if (err < 0)
diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c
index b14ab512c2ce..e01631959ed8 100644
--- a/sound/xen/xen_snd_front_alsa.c
+++ b/sound/xen/xen_snd_front_alsa.c
@@ -196,7 +196,7 @@ static u64 to_sndif_formats_mask(u64 alsa_formats)
mask = 0;
for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
if (pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa) & alsa_formats)
- mask |= 1 << ALSA_SNDIF_FORMATS[i].sndif;
+ mask |= BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif);
return mask;
}
@@ -208,7 +208,7 @@ static u64 to_alsa_formats_mask(u64 sndif_formats)
mask = 0;
for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
- if (1 << ALSA_SNDIF_FORMATS[i].sndif & sndif_formats)
+ if (BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif) & sndif_formats)
mask |= pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa);
return mask;
diff --git a/tools/arch/x86/include/uapi/asm/perf_regs.h b/tools/arch/x86/include/uapi/asm/perf_regs.h
index ac67bbea10ca..7c9d2bb3833b 100644
--- a/tools/arch/x86/include/uapi/asm/perf_regs.h
+++ b/tools/arch/x86/include/uapi/asm/perf_regs.h
@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
/* These include both GPRs and XMMX registers */
PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
};
+
+#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
+
#endif /* _ASM_X86_PERF_REGS_H */
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index b7cd91a9014f..b7321337d100 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -9,7 +9,6 @@
void perf_regs_load(u64 *regs);
#define PERF_REGS_MAX PERF_REG_X86_XMM_MAX
-#define PERF_XMM_REGS_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
#ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index 7886ca5263e3..3666c0076df9 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -277,7 +277,7 @@ uint64_t arch__intr_reg_mask(void)
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_INTR,
- .sample_regs_intr = PERF_XMM_REGS_MASK,
+ .sample_regs_intr = PERF_REG_EXTENDED_MASK,
.precise_ip = 1,
.disabled = 1,
.exclude_kernel = 1,
@@ -293,7 +293,7 @@ uint64_t arch__intr_reg_mask(void)
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd != -1) {
close(fd);
- return (PERF_XMM_REGS_MASK | PERF_REGS_MASK);
+ return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
}
return PERF_REGS_MASK;
diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c
index 698c08f851b8..8995092d541e 100644
--- a/tools/testing/radix-tree/idr-test.c
+++ b/tools/testing/radix-tree/idr-test.c
@@ -279,6 +279,51 @@ static void idr_align_test(struct idr *idr)
}
}
+DEFINE_IDR(find_idr);
+
+static void *idr_throbber(void *arg)
+{
+ time_t start = time(NULL);
+ int id = *(int *)arg;
+
+ rcu_register_thread();
+ do {
+ idr_alloc(&find_idr, xa_mk_value(id), id, id + 1, GFP_KERNEL);
+ idr_remove(&find_idr, id);
+ } while (time(NULL) < start + 10);
+ rcu_unregister_thread();
+
+ return NULL;
+}
+
+void idr_find_test_1(int anchor_id, int throbber_id)
+{
+ pthread_t throbber;
+ time_t start = time(NULL);
+
+ pthread_create(&throbber, NULL, idr_throbber, &throbber_id);
+
+ BUG_ON(idr_alloc(&find_idr, xa_mk_value(anchor_id), anchor_id,
+ anchor_id + 1, GFP_KERNEL) != anchor_id);
+
+ do {
+ int id = 0;
+ void *entry = idr_get_next(&find_idr, &id);
+ BUG_ON(entry != xa_mk_value(id));
+ } while (time(NULL) < start + 11);
+
+ pthread_join(throbber, NULL);
+
+ idr_remove(&find_idr, anchor_id);
+ BUG_ON(!idr_is_empty(&find_idr));
+}
+
+void idr_find_test(void)
+{
+ idr_find_test_1(100000, 0);
+ idr_find_test_1(0, 100000);
+}
+
void idr_checks(void)
{
unsigned long i;
@@ -360,6 +405,7 @@ void idr_checks(void)
idr_u32_test(1);
idr_u32_test(0);
idr_align_test(&idr);
+ idr_find_test();
}
#define module_init(x)
diff --git a/tools/testing/selftests/powerpc/mm/.gitignore b/tools/testing/selftests/powerpc/mm/.gitignore
index ba919308fe30..d503b8764a8e 100644
--- a/tools/testing/selftests/powerpc/mm/.gitignore
+++ b/tools/testing/selftests/powerpc/mm/.gitignore
@@ -3,4 +3,5 @@ subpage_prot
tempfile
prot_sao
segv_errors
-wild_bctr \ No newline at end of file
+wild_bctr
+large_vm_fork_separation \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/mm/Makefile b/tools/testing/selftests/powerpc/mm/Makefile
index 43d68420e363..f1fbc15800c4 100644
--- a/tools/testing/selftests/powerpc/mm/Makefile
+++ b/tools/testing/selftests/powerpc/mm/Makefile
@@ -2,7 +2,8 @@
noarg:
$(MAKE) -C ../
-TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr
+TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr \
+ large_vm_fork_separation
TEST_GEN_FILES := tempfile
top_srcdir = ../../../../..
@@ -13,6 +14,7 @@ $(TEST_GEN_PROGS): ../harness.c
$(OUTPUT)/prot_sao: ../utils.c
$(OUTPUT)/wild_bctr: CFLAGS += -m64
+$(OUTPUT)/large_vm_fork_separation: CFLAGS += -m64
$(OUTPUT)/tempfile:
dd if=/dev/zero of=$@ bs=64k count=1
diff --git a/tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c b/tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c
new file mode 100644
index 000000000000..2363a7f3ab0d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/mm/large_vm_fork_separation.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2019, Michael Ellerman, IBM Corp.
+//
+// Test that allocating memory beyond the memory limit and then forking is
+// handled correctly, ie. the child is able to access the mappings beyond the
+// memory limit and the child's writes are not visible to the parent.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+
+#ifndef MAP_FIXED_NOREPLACE
+#define MAP_FIXED_NOREPLACE MAP_FIXED // "Should be safe" above 512TB
+#endif
+
+
+static int test(void)
+{
+ int p2c[2], c2p[2], rc, status, c, *p;
+ unsigned long page_size;
+ pid_t pid;
+
+ page_size = sysconf(_SC_PAGESIZE);
+ SKIP_IF(page_size != 65536);
+
+ // Create a mapping at 512TB to allocate an extended_id
+ p = mmap((void *)(512ul << 40), page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0);
+ if (p == MAP_FAILED) {
+ perror("mmap");
+ printf("Error: couldn't mmap(), confirm kernel has 4TB support?\n");
+ return 1;
+ }
+
+ printf("parent writing %p = 1\n", p);
+ *p = 1;
+
+ FAIL_IF(pipe(p2c) == -1 || pipe(c2p) == -1);
+
+ pid = fork();
+ if (pid == 0) {
+ FAIL_IF(read(p2c[0], &c, 1) != 1);
+
+ pid = getpid();
+ printf("child writing %p = %d\n", p, pid);
+ *p = pid;
+
+ FAIL_IF(write(c2p[1], &c, 1) != 1);
+ FAIL_IF(read(p2c[0], &c, 1) != 1);
+ exit(0);
+ }
+
+ c = 0;
+ FAIL_IF(write(p2c[1], &c, 1) != 1);
+ FAIL_IF(read(c2p[0], &c, 1) != 1);
+
+ // Prevent compiler optimisation
+ barrier();
+
+ rc = 0;
+ printf("parent reading %p = %d\n", p, *p);
+ if (*p != 1) {
+ printf("Error: BUG! parent saw child's write! *p = %d\n", *p);
+ rc = 1;
+ }
+
+ FAIL_IF(write(p2c[1], &c, 1) != 1);
+ FAIL_IF(waitpid(pid, &status, 0) == -1);
+ FAIL_IF(!WIFEXITED(status) || WEXITSTATUS(status));
+
+ if (rc == 0)
+ printf("success: test completed OK\n");
+
+ return rc;
+}
+
+int main(void)
+{
+ return test_harness(test, "large_vm_fork_separation");
+}