mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
Merge 65f0d2414b ("Merge tag 'sound-5.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound") into android-mainline
Steps on the way to 5.11-rc4 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I807f1d7a7c2f24427f653694a2573d4c4760e6e3
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 Texas Instruments Incorporated
|
||||
# Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/ti,j721e-cpb-audio.yaml#
|
||||
@@ -7,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Texas Instruments J721e Common Processor Board Audio Support
|
||||
|
||||
maintainers:
|
||||
- Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
- Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
|
||||
description: |
|
||||
The audio support on the board is using pcm3168a codec connected to McASP10
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 Texas Instruments Incorporated
|
||||
# Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/ti,j721e-cpb-ivi-audio.yaml#
|
||||
@@ -7,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Texas Instruments J721e Common Processor Board Audio Support
|
||||
|
||||
maintainers:
|
||||
- Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
- Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
|
||||
description: |
|
||||
The Infotainment board plugs into the Common Processor Board, the support of the
|
||||
|
||||
@@ -1501,7 +1501,7 @@ Module for Digigram miXart8 sound cards.
|
||||
|
||||
This module supports multiple cards.
|
||||
Note: One miXart8 board will be represented as 4 alsa cards.
|
||||
See MIXART.txt for details.
|
||||
See Documentation/sound/cards/mixart.rst for details.
|
||||
|
||||
When the driver is compiled as a module and the hotplug firmware
|
||||
is supported, the firmware data is loaded via hotplug automatically.
|
||||
|
||||
@@ -12861,7 +12861,7 @@ F: include/misc/ocxl*
|
||||
F: include/uapi/misc/ocxl.h
|
||||
|
||||
OMAP AUDIO SUPPORT
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
M: Jarkko Nikula <jarkko.nikula@bitmer.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
L: linux-omap@vger.kernel.org
|
||||
@@ -17554,7 +17554,7 @@ F: arch/xtensa/
|
||||
F: drivers/irqchip/irq-xtensa-*
|
||||
|
||||
TEXAS INSTRUMENTS ASoC DRIVERS
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/ti/
|
||||
@@ -17864,7 +17864,7 @@ F: Documentation/devicetree/bindings/net/nfc/trf7970a.txt
|
||||
F: drivers/nfc/trf7970a.c
|
||||
|
||||
TI TWL4030 SERIES SOC CODEC DRIVER
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/twl4030*
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <asm/hyperv-tlfs.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <asm/idtentry.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
@@ -26,6 +27,8 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <clocksource/hyperv_timer.h>
|
||||
|
||||
int hyperv_init_cpuhp;
|
||||
|
||||
void *hv_hypercall_pg;
|
||||
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
|
||||
|
||||
@@ -401,6 +404,7 @@ void __init hyperv_init(void)
|
||||
|
||||
register_syscore_ops(&hv_syscore_ops);
|
||||
|
||||
hyperv_init_cpuhp = cpuhp;
|
||||
return;
|
||||
|
||||
remove_cpuhp_state:
|
||||
|
||||
@@ -66,11 +66,17 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,
|
||||
if (!hv_hypercall_pg)
|
||||
goto do_native;
|
||||
|
||||
if (cpumask_empty(cpus))
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/*
|
||||
* Only check the mask _after_ interrupt has been disabled to avoid the
|
||||
* mask changing under our feet.
|
||||
*/
|
||||
if (cpumask_empty(cpus)) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
|
||||
flush_pcpu = (struct hv_tlb_flush **)
|
||||
this_cpu_ptr(hyperv_pcpu_input_arg);
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ static inline void hv_disable_stimer0_percpu_irq(int irq) {}
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
extern int hyperv_init_cpuhp;
|
||||
|
||||
extern void *hv_hypercall_pg;
|
||||
extern void __percpu **hyperv_pcpu_input_arg;
|
||||
|
||||
|
||||
@@ -135,14 +135,32 @@ static void hv_machine_shutdown(void)
|
||||
{
|
||||
if (kexec_in_progress && hv_kexec_handler)
|
||||
hv_kexec_handler();
|
||||
|
||||
/*
|
||||
* Call hv_cpu_die() on all the CPUs, otherwise later the hypervisor
|
||||
* corrupts the old VP Assist Pages and can crash the kexec kernel.
|
||||
*/
|
||||
if (kexec_in_progress && hyperv_init_cpuhp > 0)
|
||||
cpuhp_remove_state(hyperv_init_cpuhp);
|
||||
|
||||
/* The function calls stop_other_cpus(). */
|
||||
native_machine_shutdown();
|
||||
|
||||
/* Disable the hypercall page when there is only 1 active CPU. */
|
||||
if (kexec_in_progress)
|
||||
hyperv_cleanup();
|
||||
}
|
||||
|
||||
static void hv_machine_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
if (hv_crash_handler)
|
||||
hv_crash_handler(regs);
|
||||
|
||||
/* The function calls crash_smp_send_stop(). */
|
||||
native_machine_crash_shutdown(regs);
|
||||
|
||||
/* Disable the hypercall page when there is only 1 active CPU. */
|
||||
hyperv_cleanup();
|
||||
}
|
||||
#endif /* CONFIG_KEXEC_CORE */
|
||||
#endif /* CONFIG_HYPERV */
|
||||
|
||||
@@ -1256,6 +1256,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
|
||||
{ TEGRA30_CLK_I2S3_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
|
||||
{ TEGRA30_CLK_I2S4_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
|
||||
{ TEGRA30_CLK_VIMCLK_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
|
||||
{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
|
||||
{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
|
||||
/* must be the last entry */
|
||||
{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
|
||||
};
|
||||
|
||||
@@ -2550,7 +2550,6 @@ static void hv_kexec_handler(void)
|
||||
/* Make sure conn_state is set as hv_synic_cleanup checks for it */
|
||||
mb();
|
||||
cpuhp_remove_state(hyperv_cpuhp_online);
|
||||
hyperv_cleanup();
|
||||
};
|
||||
|
||||
static void hv_crash_handler(struct pt_regs *regs)
|
||||
@@ -2566,7 +2565,6 @@ static void hv_crash_handler(struct pt_regs *regs)
|
||||
cpu = smp_processor_id();
|
||||
hv_stimer_cleanup(cpu);
|
||||
hv_synic_disable_regs(cpu);
|
||||
hyperv_cleanup();
|
||||
};
|
||||
|
||||
static int hv_synic_suspend(void)
|
||||
|
||||
@@ -46,60 +46,83 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct xcopy_dev_search_info {
|
||||
const unsigned char *dev_wwn;
|
||||
struct se_device *found_dev;
|
||||
};
|
||||
|
||||
/**
|
||||
* target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers
|
||||
*
|
||||
* @se_dev: device being considered for match
|
||||
* @dev_wwn: XCOPY requested NAA dev_wwn
|
||||
* @return: 1 on match, 0 on no-match
|
||||
*/
|
||||
static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
|
||||
void *data)
|
||||
const unsigned char *dev_wwn)
|
||||
{
|
||||
struct xcopy_dev_search_info *info = data;
|
||||
unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
|
||||
int rc;
|
||||
|
||||
if (!se_dev->dev_attrib.emulate_3pc)
|
||||
if (!se_dev->dev_attrib.emulate_3pc) {
|
||||
pr_debug("XCOPY: emulate_3pc disabled on se_dev %p\n", se_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
|
||||
target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
|
||||
|
||||
rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
|
||||
if (rc != 0)
|
||||
rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
|
||||
if (rc != 0) {
|
||||
pr_debug("XCOPY: skip non-matching: %*ph\n",
|
||||
XCOPY_NAA_IEEE_REGEX_LEN, tmp_dev_wwn);
|
||||
return 0;
|
||||
|
||||
info->found_dev = se_dev;
|
||||
}
|
||||
pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
|
||||
|
||||
rc = target_depend_item(&se_dev->dev_group.cg_item);
|
||||
if (rc != 0) {
|
||||
pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n",
|
||||
rc, se_dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n",
|
||||
se_dev, &se_dev->dev_group);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
|
||||
struct se_device **found_dev)
|
||||
static int target_xcopy_locate_se_dev_e4(struct se_session *sess,
|
||||
const unsigned char *dev_wwn,
|
||||
struct se_device **_found_dev,
|
||||
struct percpu_ref **_found_lun_ref)
|
||||
{
|
||||
struct xcopy_dev_search_info info;
|
||||
int ret;
|
||||
struct se_dev_entry *deve;
|
||||
struct se_node_acl *nacl;
|
||||
struct se_lun *this_lun = NULL;
|
||||
struct se_device *found_dev = NULL;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.dev_wwn = dev_wwn;
|
||||
/* cmd with NULL sess indicates no associated $FABRIC_MOD */
|
||||
if (!sess)
|
||||
goto err_out;
|
||||
|
||||
ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info);
|
||||
if (ret == 1) {
|
||||
*found_dev = info.found_dev;
|
||||
return 0;
|
||||
} else {
|
||||
pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
|
||||
return -EINVAL;
|
||||
pr_debug("XCOPY 0xe4: searching for: %*ph\n",
|
||||
XCOPY_NAA_IEEE_REGEX_LEN, dev_wwn);
|
||||
|
||||
nacl = sess->se_node_acl;
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) {
|
||||
struct se_device *this_dev;
|
||||
int rc;
|
||||
|
||||
this_lun = rcu_dereference(deve->se_lun);
|
||||
this_dev = rcu_dereference_raw(this_lun->lun_se_dev);
|
||||
|
||||
rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn);
|
||||
if (rc) {
|
||||
if (percpu_ref_tryget_live(&this_lun->lun_ref))
|
||||
found_dev = this_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (found_dev == NULL)
|
||||
goto err_out;
|
||||
|
||||
pr_debug("lun_ref held for se_dev: %p se_dev->se_dev_group: %p\n",
|
||||
found_dev, &found_dev->dev_group);
|
||||
*_found_dev = found_dev;
|
||||
*_found_lun_ref = &this_lun->lun_ref;
|
||||
return 0;
|
||||
err_out:
|
||||
pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
|
||||
@@ -246,12 +269,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
|
||||
|
||||
switch (xop->op_origin) {
|
||||
case XCOL_SOURCE_RECV_OP:
|
||||
rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
|
||||
&xop->dst_dev);
|
||||
rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
|
||||
xop->dst_tid_wwn,
|
||||
&xop->dst_dev,
|
||||
&xop->remote_lun_ref);
|
||||
break;
|
||||
case XCOL_DEST_RECV_OP:
|
||||
rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
|
||||
&xop->src_dev);
|
||||
rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
|
||||
xop->src_tid_wwn,
|
||||
&xop->src_dev,
|
||||
&xop->remote_lun_ref);
|
||||
break;
|
||||
default:
|
||||
pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
|
||||
@@ -391,18 +418,12 @@ static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd)
|
||||
|
||||
static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
|
||||
{
|
||||
struct se_device *remote_dev;
|
||||
|
||||
if (xop->op_origin == XCOL_SOURCE_RECV_OP)
|
||||
remote_dev = xop->dst_dev;
|
||||
pr_debug("putting dst lun_ref for %p\n", xop->dst_dev);
|
||||
else
|
||||
remote_dev = xop->src_dev;
|
||||
pr_debug("putting src lun_ref for %p\n", xop->src_dev);
|
||||
|
||||
pr_debug("Calling configfs_undepend_item for"
|
||||
" remote_dev: %p remote_dev->dev_group: %p\n",
|
||||
remote_dev, &remote_dev->dev_group.cg_item);
|
||||
|
||||
target_undepend_item(&remote_dev->dev_group.cg_item);
|
||||
percpu_ref_put(xop->remote_lun_ref);
|
||||
}
|
||||
|
||||
static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
|
||||
|
||||
@@ -27,6 +27,7 @@ struct xcopy_op {
|
||||
struct se_device *dst_dev;
|
||||
unsigned char dst_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
|
||||
unsigned char local_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
|
||||
struct percpu_ref *remote_lun_ref;
|
||||
|
||||
sector_t src_lba;
|
||||
sector_t dst_lba;
|
||||
|
||||
@@ -1457,7 +1457,7 @@ void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info)
|
||||
root = list_first_entry(&fs_info->allocated_roots,
|
||||
struct btrfs_root, leak_list);
|
||||
btrfs_err(fs_info, "leaked root %s refcount %d",
|
||||
btrfs_root_name(root->root_key.objectid, buf),
|
||||
btrfs_root_name(&root->root_key, buf),
|
||||
refcount_read(&root->refs));
|
||||
while (refcount_read(&root->refs) > 1)
|
||||
btrfs_put_root(root);
|
||||
|
||||
@@ -676,9 +676,7 @@ alloc_extent_state_atomic(struct extent_state *prealloc)
|
||||
|
||||
static void extent_io_tree_panic(struct extent_io_tree *tree, int err)
|
||||
{
|
||||
struct inode *inode = tree->private_data;
|
||||
|
||||
btrfs_panic(btrfs_sb(inode->i_sb), err,
|
||||
btrfs_panic(tree->fs_info, err,
|
||||
"locking error: extent tree was modified by another thread while locked");
|
||||
}
|
||||
|
||||
|
||||
@@ -9390,7 +9390,8 @@ static struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode
|
||||
* some fairly slow code that needs optimization. This walks the list
|
||||
* of all the inodes with pending delalloc and forces them to disk.
|
||||
*/
|
||||
static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot,
|
||||
static int start_delalloc_inodes(struct btrfs_root *root,
|
||||
struct writeback_control *wbc, bool snapshot,
|
||||
bool in_reclaim_context)
|
||||
{
|
||||
struct btrfs_inode *binode;
|
||||
@@ -9399,6 +9400,7 @@ static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot
|
||||
struct list_head works;
|
||||
struct list_head splice;
|
||||
int ret = 0;
|
||||
bool full_flush = wbc->nr_to_write == LONG_MAX;
|
||||
|
||||
INIT_LIST_HEAD(&works);
|
||||
INIT_LIST_HEAD(&splice);
|
||||
@@ -9427,18 +9429,24 @@ static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot
|
||||
if (snapshot)
|
||||
set_bit(BTRFS_INODE_SNAPSHOT_FLUSH,
|
||||
&binode->runtime_flags);
|
||||
work = btrfs_alloc_delalloc_work(inode);
|
||||
if (!work) {
|
||||
iput(inode);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&work->list, &works);
|
||||
btrfs_queue_work(root->fs_info->flush_workers,
|
||||
&work->work);
|
||||
if (*nr != U64_MAX) {
|
||||
(*nr)--;
|
||||
if (*nr == 0)
|
||||
if (full_flush) {
|
||||
work = btrfs_alloc_delalloc_work(inode);
|
||||
if (!work) {
|
||||
iput(inode);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&work->list, &works);
|
||||
btrfs_queue_work(root->fs_info->flush_workers,
|
||||
&work->work);
|
||||
} else {
|
||||
ret = sync_inode(inode, wbc);
|
||||
if (!ret &&
|
||||
test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
||||
&BTRFS_I(inode)->runtime_flags))
|
||||
ret = sync_inode(inode, wbc);
|
||||
btrfs_add_delayed_iput(inode);
|
||||
if (ret || wbc->nr_to_write <= 0)
|
||||
goto out;
|
||||
}
|
||||
cond_resched();
|
||||
@@ -9464,18 +9472,29 @@ out:
|
||||
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.nr_to_write = LONG_MAX,
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
.range_start = 0,
|
||||
.range_end = LLONG_MAX,
|
||||
};
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
u64 nr = U64_MAX;
|
||||
|
||||
if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
|
||||
return -EROFS;
|
||||
|
||||
return start_delalloc_inodes(root, &nr, true, false);
|
||||
return start_delalloc_inodes(root, &wbc, true, false);
|
||||
}
|
||||
|
||||
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
bool in_reclaim_context)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.nr_to_write = (nr == U64_MAX) ? LONG_MAX : (unsigned long)nr,
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
.range_start = 0,
|
||||
.range_end = LLONG_MAX,
|
||||
};
|
||||
struct btrfs_root *root;
|
||||
struct list_head splice;
|
||||
int ret;
|
||||
@@ -9489,6 +9508,13 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
spin_lock(&fs_info->delalloc_root_lock);
|
||||
list_splice_init(&fs_info->delalloc_roots, &splice);
|
||||
while (!list_empty(&splice) && nr) {
|
||||
/*
|
||||
* Reset nr_to_write here so we know that we're doing a full
|
||||
* flush.
|
||||
*/
|
||||
if (nr == U64_MAX)
|
||||
wbc.nr_to_write = LONG_MAX;
|
||||
|
||||
root = list_first_entry(&splice, struct btrfs_root,
|
||||
delalloc_root);
|
||||
root = btrfs_grab_root(root);
|
||||
@@ -9497,9 +9523,9 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
&fs_info->delalloc_roots);
|
||||
spin_unlock(&fs_info->delalloc_root_lock);
|
||||
|
||||
ret = start_delalloc_inodes(root, &nr, false, in_reclaim_context);
|
||||
ret = start_delalloc_inodes(root, &wbc, false, in_reclaim_context);
|
||||
btrfs_put_root(root);
|
||||
if (ret < 0)
|
||||
if (ret < 0 || wbc.nr_to_write <= 0)
|
||||
goto out;
|
||||
spin_lock(&fs_info->delalloc_root_lock);
|
||||
}
|
||||
|
||||
@@ -26,22 +26,22 @@ static const struct root_name_map root_map[] = {
|
||||
{ BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" },
|
||||
};
|
||||
|
||||
const char *btrfs_root_name(u64 objectid, char *buf)
|
||||
const char *btrfs_root_name(const struct btrfs_key *key, char *buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
||||
if (key->objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
||||
snprintf(buf, BTRFS_ROOT_NAME_BUF_LEN,
|
||||
"TREE_RELOC offset=%llu", objectid);
|
||||
"TREE_RELOC offset=%llu", key->offset);
|
||||
return buf;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(root_map); i++) {
|
||||
if (root_map[i].id == objectid)
|
||||
if (root_map[i].id == key->objectid)
|
||||
return root_map[i].name;
|
||||
}
|
||||
|
||||
snprintf(buf, BTRFS_ROOT_NAME_BUF_LEN, "%llu", objectid);
|
||||
snprintf(buf, BTRFS_ROOT_NAME_BUF_LEN, "%llu", key->objectid);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
void btrfs_print_leaf(struct extent_buffer *l);
|
||||
void btrfs_print_tree(struct extent_buffer *c, bool follow);
|
||||
const char *btrfs_root_name(u64 objectid, char *buf);
|
||||
const char *btrfs_root_name(const struct btrfs_key *key, char *buf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2975,11 +2975,16 @@ static int delete_v1_space_cache(struct extent_buffer *leaf,
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < btrfs_header_nritems(leaf); i++) {
|
||||
u8 type;
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, i);
|
||||
if (key.type != BTRFS_EXTENT_DATA_KEY)
|
||||
continue;
|
||||
ei = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
|
||||
if (btrfs_file_extent_type(leaf, ei) == BTRFS_FILE_EXTENT_REG &&
|
||||
type = btrfs_file_extent_type(leaf, ei);
|
||||
|
||||
if ((type == BTRFS_FILE_EXTENT_REG ||
|
||||
type == BTRFS_FILE_EXTENT_PREALLOC) &&
|
||||
btrfs_file_extent_disk_bytenr(leaf, ei) == data_bytenr) {
|
||||
found = true;
|
||||
space_cache_ino = key.objectid;
|
||||
|
||||
@@ -532,7 +532,9 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info,
|
||||
|
||||
loops = 0;
|
||||
while ((delalloc_bytes || dio_bytes) && loops < 3) {
|
||||
btrfs_start_delalloc_roots(fs_info, items, true);
|
||||
u64 nr_pages = min(delalloc_bytes, to_reclaim) >> PAGE_SHIFT;
|
||||
|
||||
btrfs_start_delalloc_roots(fs_info, nr_pages, true);
|
||||
|
||||
loops++;
|
||||
if (wait_ordered && !trans) {
|
||||
|
||||
@@ -760,6 +760,7 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = leaf->fs_info;
|
||||
u64 length;
|
||||
u64 chunk_end;
|
||||
u64 stripe_len;
|
||||
u16 num_stripes;
|
||||
u16 sub_stripes;
|
||||
@@ -814,6 +815,12 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
|
||||
"invalid chunk length, have %llu", length);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (unlikely(check_add_overflow(logical, length, &chunk_end))) {
|
||||
chunk_err(leaf, chunk, logical,
|
||||
"invalid chunk logical start and length, have logical start %llu length %llu",
|
||||
logical, length);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (unlikely(!is_power_of_2(stripe_len) || stripe_len != BTRFS_STRIPE_LEN)) {
|
||||
chunk_err(leaf, chunk, logical,
|
||||
"invalid chunk stripe length: %llu",
|
||||
|
||||
@@ -1011,22 +1011,24 @@ nfs_delegation_find_inode_server(struct nfs_server *server,
|
||||
const struct nfs_fh *fhandle)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
struct inode *freeme, *res = NULL;
|
||||
struct super_block *freeme = NULL;
|
||||
struct inode *res = NULL;
|
||||
|
||||
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
|
||||
spin_lock(&delegation->lock);
|
||||
if (delegation->inode != NULL &&
|
||||
!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
|
||||
nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
|
||||
freeme = igrab(delegation->inode);
|
||||
if (freeme && nfs_sb_active(freeme->i_sb))
|
||||
res = freeme;
|
||||
if (nfs_sb_active(server->super)) {
|
||||
freeme = server->super;
|
||||
res = igrab(delegation->inode);
|
||||
}
|
||||
spin_unlock(&delegation->lock);
|
||||
if (res != NULL)
|
||||
return res;
|
||||
if (freeme) {
|
||||
rcu_read_unlock();
|
||||
iput(freeme);
|
||||
nfs_sb_deactive(freeme);
|
||||
rcu_read_lock();
|
||||
}
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
@@ -136,9 +136,29 @@ struct nfs_fs_context {
|
||||
} clone_data;
|
||||
};
|
||||
|
||||
#define nfs_errorf(fc, fmt, ...) errorf(fc, fmt, ## __VA_ARGS__)
|
||||
#define nfs_invalf(fc, fmt, ...) invalf(fc, fmt, ## __VA_ARGS__)
|
||||
#define nfs_warnf(fc, fmt, ...) warnf(fc, fmt, ## __VA_ARGS__)
|
||||
#define nfs_errorf(fc, fmt, ...) ((fc)->log.log ? \
|
||||
errorf(fc, fmt, ## __VA_ARGS__) : \
|
||||
({ dprintk(fmt "\n", ## __VA_ARGS__); }))
|
||||
|
||||
#define nfs_ferrorf(fc, fac, fmt, ...) ((fc)->log.log ? \
|
||||
errorf(fc, fmt, ## __VA_ARGS__) : \
|
||||
({ dfprintk(fac, fmt "\n", ## __VA_ARGS__); }))
|
||||
|
||||
#define nfs_invalf(fc, fmt, ...) ((fc)->log.log ? \
|
||||
invalf(fc, fmt, ## __VA_ARGS__) : \
|
||||
({ dprintk(fmt "\n", ## __VA_ARGS__); -EINVAL; }))
|
||||
|
||||
#define nfs_finvalf(fc, fac, fmt, ...) ((fc)->log.log ? \
|
||||
invalf(fc, fmt, ## __VA_ARGS__) : \
|
||||
({ dfprintk(fac, fmt "\n", ## __VA_ARGS__); -EINVAL; }))
|
||||
|
||||
#define nfs_warnf(fc, fmt, ...) ((fc)->log.log ? \
|
||||
warnf(fc, fmt, ## __VA_ARGS__) : \
|
||||
({ dprintk(fmt "\n", ## __VA_ARGS__); }))
|
||||
|
||||
#define nfs_fwarnf(fc, fac, fmt, ...) ((fc)->log.log ? \
|
||||
warnf(fc, fmt, ## __VA_ARGS__) : \
|
||||
({ dfprintk(fac, fmt "\n", ## __VA_ARGS__); }))
|
||||
|
||||
static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc)
|
||||
{
|
||||
@@ -579,12 +599,14 @@ extern void nfs4_test_session_trunk(struct rpc_clnt *clnt,
|
||||
|
||||
static inline struct inode *nfs_igrab_and_active(struct inode *inode)
|
||||
{
|
||||
inode = igrab(inode);
|
||||
if (inode != NULL && !nfs_sb_active(inode->i_sb)) {
|
||||
iput(inode);
|
||||
inode = NULL;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
if (sb && nfs_sb_active(sb)) {
|
||||
if (igrab(inode))
|
||||
return inode;
|
||||
nfs_sb_deactive(sb);
|
||||
}
|
||||
return inode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void nfs_iput_and_deactive(struct inode *inode)
|
||||
|
||||
@@ -3536,10 +3536,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
||||
trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
|
||||
|
||||
/* Handle Layoutreturn errors */
|
||||
if (pnfs_roc_done(task, calldata->inode,
|
||||
&calldata->arg.lr_args,
|
||||
&calldata->res.lr_res,
|
||||
&calldata->res.lr_ret) == -EAGAIN)
|
||||
if (pnfs_roc_done(task, &calldata->arg.lr_args, &calldata->res.lr_res,
|
||||
&calldata->res.lr_ret) == -EAGAIN)
|
||||
goto out_restart;
|
||||
|
||||
/* hmm. we are done with the inode, and in the process of freeing
|
||||
@@ -6384,10 +6382,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
|
||||
trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
|
||||
|
||||
/* Handle Layoutreturn errors */
|
||||
if (pnfs_roc_done(task, data->inode,
|
||||
&data->args.lr_args,
|
||||
&data->res.lr_res,
|
||||
&data->res.lr_ret) == -EAGAIN)
|
||||
if (pnfs_roc_done(task, &data->args.lr_args, &data->res.lr_res,
|
||||
&data->res.lr_ret) == -EAGAIN)
|
||||
goto out_restart;
|
||||
|
||||
switch (task->tk_status) {
|
||||
@@ -6441,10 +6437,10 @@ static void nfs4_delegreturn_release(void *calldata)
|
||||
struct nfs4_delegreturndata *data = calldata;
|
||||
struct inode *inode = data->inode;
|
||||
|
||||
if (data->lr.roc)
|
||||
pnfs_roc_release(&data->lr.arg, &data->lr.res,
|
||||
data->res.lr_ret);
|
||||
if (inode) {
|
||||
if (data->lr.roc)
|
||||
pnfs_roc_release(&data->lr.arg, &data->lr.res,
|
||||
data->res.lr_ret);
|
||||
nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
|
||||
nfs_iput_and_deactive(inode);
|
||||
}
|
||||
@@ -6520,16 +6516,14 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
|
||||
nfs_fattr_init(data->res.fattr);
|
||||
data->timestamp = jiffies;
|
||||
data->rpc_status = 0;
|
||||
data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res, cred);
|
||||
data->inode = nfs_igrab_and_active(inode);
|
||||
if (data->inode) {
|
||||
if (data->inode || issync) {
|
||||
data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res,
|
||||
cred);
|
||||
if (data->lr.roc) {
|
||||
data->args.lr_args = &data->lr.arg;
|
||||
data->res.lr_res = &data->lr.res;
|
||||
}
|
||||
} else if (data->lr.roc) {
|
||||
pnfs_roc_release(&data->lr.arg, &data->lr.res, 0);
|
||||
data->lr.roc = false;
|
||||
}
|
||||
|
||||
task_setup_data.callback_data = data;
|
||||
@@ -7111,9 +7105,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
|
||||
data->arg.new_lock_owner, ret);
|
||||
} else
|
||||
data->cancelled = true;
|
||||
trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
|
||||
rpc_put_task(task);
|
||||
dprintk("%s: done, ret = %d!\n", __func__, ret);
|
||||
trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ int nfs4_try_get_tree(struct fs_context *fc)
|
||||
fc, ctx->nfs_server.hostname,
|
||||
ctx->nfs_server.export_path);
|
||||
if (err) {
|
||||
nfs_errorf(fc, "NFS4: Couldn't follow remote path");
|
||||
nfs_ferrorf(fc, MOUNT, "NFS4: Couldn't follow remote path");
|
||||
dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err);
|
||||
} else {
|
||||
dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
|
||||
@@ -250,7 +250,7 @@ int nfs4_get_referral_tree(struct fs_context *fc)
|
||||
fc, ctx->nfs_server.hostname,
|
||||
ctx->nfs_server.export_path);
|
||||
if (err) {
|
||||
nfs_errorf(fc, "NFS4: Couldn't follow remote path");
|
||||
nfs_ferrorf(fc, MOUNT, "NFS4: Couldn't follow remote path");
|
||||
dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err);
|
||||
} else {
|
||||
dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");
|
||||
|
||||
@@ -1152,7 +1152,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
|
||||
LIST_HEAD(freeme);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (!pnfs_layout_is_valid(lo) || !arg_stateid ||
|
||||
if (!pnfs_layout_is_valid(lo) ||
|
||||
!nfs4_stateid_match_other(&lo->plh_stateid, arg_stateid))
|
||||
goto out_unlock;
|
||||
if (stateid) {
|
||||
@@ -1509,10 +1509,8 @@ out_noroc:
|
||||
return false;
|
||||
}
|
||||
|
||||
int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
|
||||
struct nfs4_layoutreturn_args **argpp,
|
||||
struct nfs4_layoutreturn_res **respp,
|
||||
int *ret)
|
||||
int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp,
|
||||
struct nfs4_layoutreturn_res **respp, int *ret)
|
||||
{
|
||||
struct nfs4_layoutreturn_args *arg = *argpp;
|
||||
int retval = -EAGAIN;
|
||||
@@ -1545,7 +1543,7 @@ int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
|
||||
return 0;
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
if (!nfs4_layout_refresh_old_stateid(&arg->stateid,
|
||||
&arg->range, inode))
|
||||
&arg->range, arg->inode))
|
||||
break;
|
||||
*ret = -NFS4ERR_NOMATCHING_LAYOUT;
|
||||
return -EAGAIN;
|
||||
@@ -1560,23 +1558,28 @@ void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
|
||||
int ret)
|
||||
{
|
||||
struct pnfs_layout_hdr *lo = args->layout;
|
||||
const nfs4_stateid *arg_stateid = NULL;
|
||||
struct inode *inode = args->inode;
|
||||
const nfs4_stateid *res_stateid = NULL;
|
||||
struct nfs4_xdr_opaque_data *ld_private = args->ld_private;
|
||||
|
||||
switch (ret) {
|
||||
case -NFS4ERR_NOMATCHING_LAYOUT:
|
||||
spin_lock(&inode->i_lock);
|
||||
if (pnfs_layout_is_valid(lo) &&
|
||||
nfs4_stateid_match_other(&args->stateid, &lo->plh_stateid))
|
||||
pnfs_set_plh_return_info(lo, args->range.iomode, 0);
|
||||
pnfs_clear_layoutreturn_waitbit(lo);
|
||||
spin_unlock(&inode->i_lock);
|
||||
break;
|
||||
case 0:
|
||||
if (res->lrs_present)
|
||||
res_stateid = &res->stateid;
|
||||
fallthrough;
|
||||
default:
|
||||
arg_stateid = &args->stateid;
|
||||
pnfs_layoutreturn_free_lsegs(lo, &args->stateid, &args->range,
|
||||
res_stateid);
|
||||
}
|
||||
trace_nfs4_layoutreturn_on_close(args->inode, &args->stateid, ret);
|
||||
pnfs_layoutreturn_free_lsegs(lo, arg_stateid, &args->range,
|
||||
res_stateid);
|
||||
if (ld_private && ld_private->ops && ld_private->ops->free)
|
||||
ld_private->ops->free(ld_private);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
@@ -2015,6 +2018,27 @@ lookup_again:
|
||||
goto lookup_again;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we free lsegs when sending LAYOUTRETURN, we need to wait
|
||||
* for LAYOUTRETURN.
|
||||
*/
|
||||
if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) {
|
||||
spin_unlock(&ino->i_lock);
|
||||
dprintk("%s wait for layoutreturn\n", __func__);
|
||||
lseg = ERR_PTR(pnfs_prepare_to_retry_layoutget(lo));
|
||||
if (!IS_ERR(lseg)) {
|
||||
pnfs_put_layout_hdr(lo);
|
||||
dprintk("%s retrying\n", __func__);
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo,
|
||||
lseg,
|
||||
PNFS_UPDATE_LAYOUT_RETRY);
|
||||
goto lookup_again;
|
||||
}
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
|
||||
PNFS_UPDATE_LAYOUT_RETURN);
|
||||
goto out_put_layout_hdr;
|
||||
}
|
||||
|
||||
lseg = pnfs_find_lseg(lo, &arg, strict_iomode);
|
||||
if (lseg) {
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
|
||||
@@ -2067,28 +2091,6 @@ lookup_again:
|
||||
nfs4_stateid_copy(&stateid, &lo->plh_stateid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we free lsegs before sending LAYOUTRETURN, we need to wait
|
||||
* for LAYOUTRETURN even if first is true.
|
||||
*/
|
||||
if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) {
|
||||
spin_unlock(&ino->i_lock);
|
||||
dprintk("%s wait for layoutreturn\n", __func__);
|
||||
lseg = ERR_PTR(pnfs_prepare_to_retry_layoutget(lo));
|
||||
if (!IS_ERR(lseg)) {
|
||||
if (first)
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
dprintk("%s retrying\n", __func__);
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo,
|
||||
lseg, PNFS_UPDATE_LAYOUT_RETRY);
|
||||
goto lookup_again;
|
||||
}
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
|
||||
PNFS_UPDATE_LAYOUT_RETURN);
|
||||
goto out_put_layout_hdr;
|
||||
}
|
||||
|
||||
if (pnfs_layoutgets_blocked(lo)) {
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
|
||||
PNFS_UPDATE_LAYOUT_BLOCKED);
|
||||
@@ -2242,6 +2244,7 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data,
|
||||
&rng, GFP_KERNEL);
|
||||
if (!lgp) {
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
nfs_layoutget_end(lo);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -297,10 +297,8 @@ bool pnfs_roc(struct inode *ino,
|
||||
struct nfs4_layoutreturn_args *args,
|
||||
struct nfs4_layoutreturn_res *res,
|
||||
const struct cred *cred);
|
||||
int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
|
||||
struct nfs4_layoutreturn_args **argpp,
|
||||
struct nfs4_layoutreturn_res **respp,
|
||||
int *ret);
|
||||
int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp,
|
||||
struct nfs4_layoutreturn_res **respp, int *ret);
|
||||
void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
|
||||
struct nfs4_layoutreturn_res *res,
|
||||
int ret);
|
||||
@@ -772,7 +770,7 @@ pnfs_roc(struct inode *ino,
|
||||
}
|
||||
|
||||
static inline int
|
||||
pnfs_roc_done(struct rpc_task *task, struct inode *inode,
|
||||
pnfs_roc_done(struct rpc_task *task,
|
||||
struct nfs4_layoutreturn_args **argpp,
|
||||
struct nfs4_layoutreturn_res **respp,
|
||||
int *ret)
|
||||
|
||||
@@ -78,22 +78,18 @@ void
|
||||
pnfs_generic_clear_request_commit(struct nfs_page *req,
|
||||
struct nfs_commit_info *cinfo)
|
||||
{
|
||||
struct pnfs_layout_segment *freeme = NULL;
|
||||
struct pnfs_commit_bucket *bucket = NULL;
|
||||
|
||||
if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
|
||||
goto out;
|
||||
cinfo->ds->nwritten--;
|
||||
if (list_is_singular(&req->wb_list)) {
|
||||
struct pnfs_commit_bucket *bucket;
|
||||
|
||||
if (list_is_singular(&req->wb_list))
|
||||
bucket = list_first_entry(&req->wb_list,
|
||||
struct pnfs_commit_bucket,
|
||||
written);
|
||||
freeme = pnfs_free_bucket_lseg(bucket);
|
||||
}
|
||||
struct pnfs_commit_bucket, written);
|
||||
out:
|
||||
nfs_request_remove_commit_list(req, cinfo);
|
||||
pnfs_put_lseg(freeme);
|
||||
if (bucket)
|
||||
pnfs_put_lseg(pnfs_free_bucket_lseg(bucket));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);
|
||||
|
||||
@@ -407,12 +403,16 @@ pnfs_bucket_get_committing(struct list_head *head,
|
||||
struct pnfs_commit_bucket *bucket,
|
||||
struct nfs_commit_info *cinfo)
|
||||
{
|
||||
struct pnfs_layout_segment *lseg;
|
||||
struct list_head *pos;
|
||||
|
||||
list_for_each(pos, &bucket->committing)
|
||||
cinfo->ds->ncommitting--;
|
||||
list_splice_init(&bucket->committing, head);
|
||||
return pnfs_free_bucket_lseg(bucket);
|
||||
lseg = pnfs_free_bucket_lseg(bucket);
|
||||
if (!lseg)
|
||||
lseg = pnfs_get_lseg(bucket->lseg);
|
||||
return lseg;
|
||||
}
|
||||
|
||||
static struct nfs_commit_data *
|
||||
@@ -424,8 +424,6 @@ pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket,
|
||||
if (!data)
|
||||
return NULL;
|
||||
data->lseg = pnfs_bucket_get_committing(&data->pages, bucket, cinfo);
|
||||
if (!data->lseg)
|
||||
data->lseg = pnfs_get_lseg(bucket->lseg);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@
|
||||
#include "pnfs.h"
|
||||
#include "trace.h"
|
||||
|
||||
static bool inter_copy_offload_enable;
|
||||
module_param(inter_copy_offload_enable, bool, 0644);
|
||||
MODULE_PARM_DESC(inter_copy_offload_enable,
|
||||
"Enable inter server to server copy offload. Default: false");
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#include <linux/security.h>
|
||||
|
||||
|
||||
@@ -147,6 +147,25 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
|
||||
return p;
|
||||
}
|
||||
|
||||
static void *
|
||||
svcxdr_savemem(struct nfsd4_compoundargs *argp, __be32 *p, u32 len)
|
||||
{
|
||||
__be32 *tmp;
|
||||
|
||||
/*
|
||||
* The location of the decoded data item is stable,
|
||||
* so @p is OK to use. This is the common case.
|
||||
*/
|
||||
if (p != argp->xdr->scratch.iov_base)
|
||||
return p;
|
||||
|
||||
tmp = svcxdr_tmpalloc(argp, len);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
memcpy(tmp, p, len);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* NFSv4 basic data type decoders
|
||||
*/
|
||||
@@ -183,11 +202,10 @@ nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
|
||||
p = xdr_inline_decode(argp->xdr, len);
|
||||
if (!p)
|
||||
return nfserr_bad_xdr;
|
||||
o->data = svcxdr_tmpalloc(argp, len);
|
||||
o->data = svcxdr_savemem(argp, p, len);
|
||||
if (!o->data)
|
||||
return nfserr_jukebox;
|
||||
o->len = len;
|
||||
memcpy(o->data, p, len);
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
@@ -205,10 +223,9 @@ nfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp)
|
||||
status = check_filename((char *)p, *lenp);
|
||||
if (status)
|
||||
return status;
|
||||
*namp = svcxdr_tmpalloc(argp, *lenp);
|
||||
*namp = svcxdr_savemem(argp, p, *lenp);
|
||||
if (!*namp)
|
||||
return nfserr_jukebox;
|
||||
memcpy(*namp, p, *lenp);
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
@@ -1200,10 +1217,9 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
|
||||
p = xdr_inline_decode(argp->xdr, putfh->pf_fhlen);
|
||||
if (!p)
|
||||
return nfserr_bad_xdr;
|
||||
putfh->pf_fhval = svcxdr_tmpalloc(argp, putfh->pf_fhlen);
|
||||
putfh->pf_fhval = svcxdr_savemem(argp, p, putfh->pf_fhlen);
|
||||
if (!putfh->pf_fhval)
|
||||
return nfserr_jukebox;
|
||||
memcpy(putfh->pf_fhval, p, putfh->pf_fhlen);
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
@@ -1318,24 +1334,20 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
|
||||
p = xdr_inline_decode(argp->xdr, setclientid->se_callback_netid_len);
|
||||
if (!p)
|
||||
return nfserr_bad_xdr;
|
||||
setclientid->se_callback_netid_val = svcxdr_tmpalloc(argp,
|
||||
setclientid->se_callback_netid_val = svcxdr_savemem(argp, p,
|
||||
setclientid->se_callback_netid_len);
|
||||
if (!setclientid->se_callback_netid_val)
|
||||
return nfserr_jukebox;
|
||||
memcpy(setclientid->se_callback_netid_val, p,
|
||||
setclientid->se_callback_netid_len);
|
||||
|
||||
if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_addr_len) < 0)
|
||||
return nfserr_bad_xdr;
|
||||
p = xdr_inline_decode(argp->xdr, setclientid->se_callback_addr_len);
|
||||
if (!p)
|
||||
return nfserr_bad_xdr;
|
||||
setclientid->se_callback_addr_val = svcxdr_tmpalloc(argp,
|
||||
setclientid->se_callback_addr_val = svcxdr_savemem(argp, p,
|
||||
setclientid->se_callback_addr_len);
|
||||
if (!setclientid->se_callback_addr_val)
|
||||
return nfserr_jukebox;
|
||||
memcpy(setclientid->se_callback_addr_val, p,
|
||||
setclientid->se_callback_addr_len);
|
||||
if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_ident) < 0)
|
||||
return nfserr_bad_xdr;
|
||||
|
||||
@@ -1375,10 +1387,9 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
|
||||
p = xdr_inline_decode(argp->xdr, verify->ve_attrlen);
|
||||
if (!p)
|
||||
return nfserr_bad_xdr;
|
||||
verify->ve_attrval = svcxdr_tmpalloc(argp, verify->ve_attrlen);
|
||||
verify->ve_attrval = svcxdr_savemem(argp, p, verify->ve_attrlen);
|
||||
if (!verify->ve_attrval)
|
||||
return nfserr_jukebox;
|
||||
memcpy(verify->ve_attrval, p, verify->ve_attrlen);
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
@@ -2333,10 +2344,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
|
||||
p = xdr_inline_decode(argp->xdr, argp->taglen);
|
||||
if (!p)
|
||||
return 0;
|
||||
argp->tag = svcxdr_tmpalloc(argp, argp->taglen);
|
||||
argp->tag = svcxdr_savemem(argp, p, argp->taglen);
|
||||
if (!argp->tag)
|
||||
return 0;
|
||||
memcpy(argp->tag, p, argp->taglen);
|
||||
max_reply += xdr_align_size(argp->taglen);
|
||||
}
|
||||
|
||||
@@ -4756,6 +4766,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
|
||||
resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
xdr_truncate_encode(xdr, starting_len + 16 + xdr_align_size(*maxcount));
|
||||
|
||||
tmp = htonl(NFS4_CONTENT_DATA);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
|
||||
@@ -4763,6 +4774,10 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8);
|
||||
tmp = htonl(*maxcount);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4);
|
||||
|
||||
tmp = xdr_zero;
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 16 + *maxcount, &tmp,
|
||||
xdr_pad_size(*maxcount));
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
@@ -4855,14 +4870,15 @@ out:
|
||||
if (nfserr && segments == 0)
|
||||
xdr_truncate_encode(xdr, starting_len);
|
||||
else {
|
||||
if (nfserr) {
|
||||
xdr_truncate_encode(xdr, last_segment);
|
||||
nfserr = nfs_ok;
|
||||
eof = 0;
|
||||
}
|
||||
tmp = htonl(eof);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
|
||||
tmp = htonl(segments);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
|
||||
if (nfserr) {
|
||||
xdr_truncate_encode(xdr, last_segment);
|
||||
nfserr = nfs_ok;
|
||||
}
|
||||
}
|
||||
|
||||
return nfserr;
|
||||
|
||||
@@ -33,12 +33,6 @@
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_SVC
|
||||
|
||||
bool inter_copy_offload_enable;
|
||||
EXPORT_SYMBOL_GPL(inter_copy_offload_enable);
|
||||
module_param(inter_copy_offload_enable, bool, 0644);
|
||||
MODULE_PARM_DESC(inter_copy_offload_enable,
|
||||
"Enable inter server to server copy offload. Default: false");
|
||||
|
||||
extern struct svc_program nfsd_program;
|
||||
static int nfsd(void *vrqstp);
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
||||
|
||||
@@ -568,7 +568,6 @@ struct nfsd4_copy {
|
||||
struct nfs_fh c_fh;
|
||||
nfs4_stateid stateid;
|
||||
};
|
||||
extern bool inter_copy_offload_enable;
|
||||
|
||||
struct nfsd4_seek {
|
||||
/* request */
|
||||
|
||||
@@ -538,7 +538,7 @@ config KPROBE_EVENTS
|
||||
config KPROBE_EVENTS_ON_NOTRACE
|
||||
bool "Do NOT protect notrace function from kprobe events"
|
||||
depends on KPROBE_EVENTS
|
||||
depends on KPROBES_ON_FTRACE
|
||||
depends on DYNAMIC_FTRACE
|
||||
default n
|
||||
help
|
||||
This is only for the developers who want to debug ftrace itself
|
||||
|
||||
@@ -434,7 +434,7 @@ static int disable_trace_kprobe(struct trace_event_call *call,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_KPROBES_ON_FTRACE) && \
|
||||
#if defined(CONFIG_DYNAMIC_FTRACE) && \
|
||||
!defined(CONFIG_KPROBE_EVENTS_ON_NOTRACE)
|
||||
static bool __within_notrace_func(unsigned long addr)
|
||||
{
|
||||
|
||||
@@ -185,7 +185,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf,
|
||||
scope_id = dev->ifindex;
|
||||
dev_put(dev);
|
||||
} else {
|
||||
if (kstrtou32(p, 10, &scope_id) == 0) {
|
||||
if (kstrtou32(p, 10, &scope_id) != 0) {
|
||||
kfree(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1062,6 +1062,90 @@ err_noclose:
|
||||
return 0; /* record not complete */
|
||||
}
|
||||
|
||||
static int svc_tcp_send_kvec(struct socket *sock, const struct kvec *vec,
|
||||
int flags)
|
||||
{
|
||||
return kernel_sendpage(sock, virt_to_page(vec->iov_base),
|
||||
offset_in_page(vec->iov_base),
|
||||
vec->iov_len, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* kernel_sendpage() is used exclusively to reduce the number of
|
||||
* copy operations in this path. Therefore the caller must ensure
|
||||
* that the pages backing @xdr are unchanging.
|
||||
*
|
||||
* In addition, the logic assumes that * .bv_len is never larger
|
||||
* than PAGE_SIZE.
|
||||
*/
|
||||
static int svc_tcp_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
struct xdr_buf *xdr, rpc_fraghdr marker,
|
||||
unsigned int *sentp)
|
||||
{
|
||||
const struct kvec *head = xdr->head;
|
||||
const struct kvec *tail = xdr->tail;
|
||||
struct kvec rm = {
|
||||
.iov_base = &marker,
|
||||
.iov_len = sizeof(marker),
|
||||
};
|
||||
int flags, ret;
|
||||
|
||||
*sentp = 0;
|
||||
xdr_alloc_bvec(xdr, GFP_KERNEL);
|
||||
|
||||
msg->msg_flags = MSG_MORE;
|
||||
ret = kernel_sendmsg(sock, msg, &rm, 1, rm.iov_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*sentp += ret;
|
||||
if (ret != rm.iov_len)
|
||||
return -EAGAIN;
|
||||
|
||||
flags = head->iov_len < xdr->len ? MSG_MORE | MSG_SENDPAGE_NOTLAST : 0;
|
||||
ret = svc_tcp_send_kvec(sock, head, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*sentp += ret;
|
||||
if (ret != head->iov_len)
|
||||
goto out;
|
||||
|
||||
if (xdr->page_len) {
|
||||
unsigned int offset, len, remaining;
|
||||
struct bio_vec *bvec;
|
||||
|
||||
bvec = xdr->bvec;
|
||||
offset = xdr->page_base;
|
||||
remaining = xdr->page_len;
|
||||
flags = MSG_MORE | MSG_SENDPAGE_NOTLAST;
|
||||
while (remaining > 0) {
|
||||
if (remaining <= PAGE_SIZE && tail->iov_len == 0)
|
||||
flags = 0;
|
||||
len = min(remaining, bvec->bv_len);
|
||||
ret = kernel_sendpage(sock, bvec->bv_page,
|
||||
bvec->bv_offset + offset,
|
||||
len, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*sentp += ret;
|
||||
if (ret != len)
|
||||
goto out;
|
||||
remaining -= len;
|
||||
offset = 0;
|
||||
bvec++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tail->iov_len) {
|
||||
ret = svc_tcp_send_kvec(sock, tail, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*sentp += ret;
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_tcp_sendto - Send out a reply on a TCP socket
|
||||
* @rqstp: completed svc_rqst
|
||||
@@ -1089,7 +1173,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
|
||||
mutex_lock(&xprt->xpt_mutex);
|
||||
if (svc_xprt_is_dead(xprt))
|
||||
goto out_notconn;
|
||||
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, marker, &sent);
|
||||
err = svc_tcp_sendmsg(svsk->sk_sock, &msg, xdr, marker, &sent);
|
||||
xdr_free_bvec(xdr);
|
||||
trace_svcsock_tcp_send(xprt, err < 0 ? err : sent);
|
||||
if (err < 0 || sent != (xdr->len + sizeof(marker)))
|
||||
|
||||
@@ -88,7 +88,7 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
|
||||
|
||||
/* Set interval to next transaction. */
|
||||
ff->next_ktime[port] = ktime_add_ns(ktime_get(),
|
||||
ff->rx_bytes[port] * 8 * NSEC_PER_SEC / 31250);
|
||||
ff->rx_bytes[port] * 8 * (NSEC_PER_SEC / 31250));
|
||||
|
||||
if (quad_count == 1)
|
||||
tcode = TCODE_WRITE_QUADLET_REQUEST;
|
||||
|
||||
@@ -209,7 +209,7 @@ static void midi_port_work(struct work_struct *work)
|
||||
|
||||
/* Set interval to next transaction. */
|
||||
port->next_ktime = ktime_add_ns(ktime_get(),
|
||||
port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
|
||||
port->consume_bytes * 8 * (NSEC_PER_SEC / 31250));
|
||||
|
||||
/* Start this transaction. */
|
||||
port->idling = false;
|
||||
|
||||
@@ -2598,7 +2598,8 @@ static const struct pci_device_id azx_ids[] = {
|
||||
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
|
||||
/* ATI HDMI */
|
||||
{ PCI_DEVICE(0x1002, 0x0002),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
{ PCI_DEVICE(0x1002, 0x1308),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
{ PCI_DEVICE(0x1002, 0x157a),
|
||||
@@ -2660,9 +2661,11 @@ static const struct pci_device_id azx_ids[] = {
|
||||
{ PCI_DEVICE(0x1002, 0xaab0),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
{ PCI_DEVICE(0x1002, 0xaac0),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
{ PCI_DEVICE(0x1002, 0xaac8),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
{ PCI_DEVICE(0x1002, 0xaad8),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
|
||||
@@ -388,7 +388,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
|
||||
* in powers of 2, next available ratio is 16 which can be
|
||||
* used as a limiting factor here.
|
||||
*/
|
||||
if (of_device_is_compatible(np, "nvidia,tegra194-hda"))
|
||||
if (of_device_is_compatible(np, "nvidia,tegra30-hda"))
|
||||
chip->bus.core.sdo_limit = 16;
|
||||
|
||||
/* codec detection */
|
||||
|
||||
@@ -7970,6 +7970,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8780, "HP ZBook Fury 17 G7 Mobile Workstation",
|
||||
ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
|
||||
ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
|
||||
@@ -140,21 +140,14 @@ static int snd_acp3x_probe(struct pci_dev *pci,
|
||||
goto release_regions;
|
||||
}
|
||||
|
||||
/* check for msi interrupt support */
|
||||
ret = pci_enable_msi(pci);
|
||||
if (ret)
|
||||
/* msi is not enabled */
|
||||
irqflags = IRQF_SHARED;
|
||||
else
|
||||
/* msi is enabled */
|
||||
irqflags = 0;
|
||||
irqflags = IRQF_SHARED;
|
||||
|
||||
addr = pci_resource_start(pci, 0);
|
||||
adata->acp3x_base = devm_ioremap(&pci->dev, addr,
|
||||
pci_resource_len(pci, 0));
|
||||
if (!adata->acp3x_base) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_msi;
|
||||
goto release_regions;
|
||||
}
|
||||
pci_set_master(pci);
|
||||
pci_set_drvdata(pci, adata);
|
||||
@@ -162,7 +155,7 @@ static int snd_acp3x_probe(struct pci_dev *pci,
|
||||
adata->pme_en = rv_readl(adata->acp3x_base + mmACP_PME_EN);
|
||||
ret = acp3x_init(adata);
|
||||
if (ret)
|
||||
goto disable_msi;
|
||||
goto release_regions;
|
||||
|
||||
val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
|
||||
switch (val) {
|
||||
@@ -251,8 +244,6 @@ unregister_devs:
|
||||
de_init:
|
||||
if (acp3x_deinit(adata->acp3x_base))
|
||||
dev_err(&pci->dev, "ACP de-init failed\n");
|
||||
disable_msi:
|
||||
pci_disable_msi(pci);
|
||||
release_regions:
|
||||
pci_release_regions(pci);
|
||||
disable_pci:
|
||||
@@ -311,7 +302,6 @@ static void snd_acp3x_remove(struct pci_dev *pci)
|
||||
dev_err(&pci->dev, "ACP de-init failed\n");
|
||||
pm_runtime_forbid(&pci->dev);
|
||||
pm_runtime_get_noresume(&pci->dev);
|
||||
pci_disable_msi(pci);
|
||||
pci_release_regions(pci);
|
||||
pci_disable_device(pci);
|
||||
}
|
||||
|
||||
@@ -171,6 +171,20 @@ static const struct dmi_system_id rn_acp_quirk_table[] = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "LNVNB161216"),
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Lenovo ThinkPad E14 Gen 2 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "20T6CTO1WW"),
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Lenovo ThinkPad X395 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "20NLCTO1WW"),
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ config SND_MCHP_SOC_SPDIFTX
|
||||
- sama7g5
|
||||
|
||||
This S/PDIF TX driver is compliant with IEC-60958 standard and
|
||||
includes programable User Data and Channel Status fields.
|
||||
includes programmable User Data and Channel Status fields.
|
||||
|
||||
config SND_MCHP_SOC_SPDIFRX
|
||||
tristate "Microchip ASoC driver for boards using S/PDIF RX"
|
||||
@@ -157,5 +157,5 @@ config SND_MCHP_SOC_SPDIFRX
|
||||
- sama7g5
|
||||
|
||||
This S/PDIF RX driver is compliant with IEC-60958 standard and
|
||||
includes programable User Data and Channel Status fields.
|
||||
includes programmable User Data and Channel Status fields.
|
||||
endif
|
||||
|
||||
@@ -457,7 +457,7 @@ config SND_SOC_ADAU7118_HW
|
||||
help
|
||||
Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
|
||||
Converter. In this mode, the device works in standalone mode which
|
||||
means that there is no bus to comunicate with it. Stereo mode is not
|
||||
means that there is no bus to communicate with it. Stereo mode is not
|
||||
supported in this mode.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
#include <sound/tlv.h>
|
||||
#include "max98373.h"
|
||||
|
||||
static const u32 max98373_i2c_cache_reg[] = {
|
||||
MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
|
||||
MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
|
||||
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
|
||||
};
|
||||
|
||||
static struct reg_default max98373_reg[] = {
|
||||
{MAX98373_R2000_SW_RESET, 0x00},
|
||||
{MAX98373_R2001_INT_RAW1, 0x00},
|
||||
@@ -472,6 +478,11 @@ static struct snd_soc_dai_driver max98373_dai[] = {
|
||||
static int max98373_suspend(struct device *dev)
|
||||
{
|
||||
struct max98373_priv *max98373 = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
/* cache feedback register values before suspend */
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
|
||||
|
||||
regcache_cache_only(max98373->regmap, true);
|
||||
regcache_mark_dirty(max98373->regmap);
|
||||
@@ -509,6 +520,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
||||
{
|
||||
int ret = 0;
|
||||
int reg = 0;
|
||||
int i;
|
||||
struct max98373_priv *max98373 = NULL;
|
||||
|
||||
max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL);
|
||||
@@ -534,6 +546,14 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
max98373->cache_num = ARRAY_SIZE(max98373_i2c_cache_reg);
|
||||
max98373->cache = devm_kcalloc(&i2c->dev, max98373->cache_num,
|
||||
sizeof(*max98373->cache),
|
||||
GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
max98373->cache[i].reg = max98373_i2c_cache_reg[i];
|
||||
|
||||
/* voltage/current slot & gpio configuration */
|
||||
max98373_slot_config(&i2c->dev, max98373);
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ struct sdw_stream_data {
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
};
|
||||
|
||||
static const u32 max98373_sdw_cache_reg[] = {
|
||||
MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
|
||||
MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
|
||||
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
|
||||
};
|
||||
|
||||
static struct reg_default max98373_reg[] = {
|
||||
{MAX98373_R0040_SCP_INIT_STAT_1, 0x00},
|
||||
{MAX98373_R0041_SCP_INIT_MASK_1, 0x00},
|
||||
@@ -245,6 +251,11 @@ static const struct regmap_config max98373_sdw_regmap = {
|
||||
static __maybe_unused int max98373_suspend(struct device *dev)
|
||||
{
|
||||
struct max98373_priv *max98373 = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
/* cache feedback register values before suspend */
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
|
||||
|
||||
regcache_cache_only(max98373->regmap, true);
|
||||
|
||||
@@ -757,6 +768,7 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
|
||||
{
|
||||
struct max98373_priv *max98373;
|
||||
int ret;
|
||||
int i;
|
||||
struct device *dev = &slave->dev;
|
||||
|
||||
/* Allocate and assign private driver data structure */
|
||||
@@ -768,6 +780,14 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
|
||||
max98373->regmap = regmap;
|
||||
max98373->slave = slave;
|
||||
|
||||
max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
|
||||
max98373->cache = devm_kcalloc(dev, max98373->cache_num,
|
||||
sizeof(*max98373->cache),
|
||||
GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
max98373->cache[i].reg = max98373_sdw_cache_reg[i];
|
||||
|
||||
/* Read voltage and slot configuration */
|
||||
max98373_slot_config(dev, max98373);
|
||||
|
||||
|
||||
@@ -168,6 +168,31 @@ static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
|
||||
MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
|
||||
max98373_ADC_samplerate_text);
|
||||
|
||||
static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
|
||||
int i;
|
||||
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
|
||||
/*
|
||||
* Register values will be cached before suspend. The cached value
|
||||
* will be a valid value and userspace will happy with that.
|
||||
*/
|
||||
for (i = 0; i < max98373->cache_num; i++) {
|
||||
if (mc->reg == max98373->cache[i].reg) {
|
||||
ucontrol->value.integer.value[0] = max98373->cache[i].val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return snd_soc_put_volsw(kcontrol, ucontrol);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new max98373_snd_controls[] = {
|
||||
SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
|
||||
MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
|
||||
@@ -209,8 +234,10 @@ SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
|
||||
MAX98373_FLT_EN_SHIFT, 1, 0),
|
||||
SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
|
||||
MAX98373_FLT_EN_SHIFT, 1, 0),
|
||||
SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
|
||||
SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
|
||||
SOC_SINGLE_EXT("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0,
|
||||
max98373_feedback_get, NULL),
|
||||
SOC_SINGLE_EXT("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0,
|
||||
max98373_feedback_get, NULL),
|
||||
SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
|
||||
0, 0x3, 0),
|
||||
SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
|
||||
@@ -226,7 +253,8 @@ SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
|
||||
SOC_SINGLE_EXT("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0,
|
||||
max98373_feedback_get, NULL),
|
||||
SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
|
||||
SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
|
||||
|
||||
@@ -203,6 +203,11 @@
|
||||
/* MAX98373_R2000_SW_RESET */
|
||||
#define MAX98373_SOFT_RESET (0x1 << 0)
|
||||
|
||||
struct max98373_cache {
|
||||
u32 reg;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct max98373_priv {
|
||||
struct regmap *regmap;
|
||||
int reset_gpio;
|
||||
@@ -212,6 +217,9 @@ struct max98373_priv {
|
||||
bool interleave_mode;
|
||||
unsigned int ch_size;
|
||||
bool tdm_mode;
|
||||
/* cache for reading a valid fake feedback value */
|
||||
struct max98373_cache *cache;
|
||||
int cache_num;
|
||||
/* variables to support soundwire */
|
||||
struct sdw_slave *slave;
|
||||
bool hw_init;
|
||||
|
||||
@@ -462,6 +462,8 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
|
||||
unsigned int read_ll, read_rl;
|
||||
int i;
|
||||
|
||||
mutex_lock(&rt711->calibrate_mutex);
|
||||
|
||||
/* Can't use update bit function, so read the original value first */
|
||||
addr_h = mc->reg;
|
||||
addr_l = mc->rreg;
|
||||
@@ -547,6 +549,8 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
|
||||
if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
|
||||
regmap_write(rt711->regmap,
|
||||
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
|
||||
|
||||
mutex_unlock(&rt711->calibrate_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -859,9 +863,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component,
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
mutex_lock(&rt711->calibrate_mutex);
|
||||
regmap_write(rt711->regmap,
|
||||
RT711_SET_AUDIO_POWER_STATE,
|
||||
AC_PWRST_D3);
|
||||
mutex_unlock(&rt711->calibrate_mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -164,6 +164,7 @@ static int imx_hdmi_probe(struct platform_device *pdev)
|
||||
|
||||
if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) {
|
||||
dev_err(&pdev->dev, "Invalid HDMI DAI link\n");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +189,7 @@ static struct platform_driver haswell_audio = {
|
||||
.probe = haswell_audio_probe,
|
||||
.driver = {
|
||||
.name = "haswell-audio",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -224,6 +224,7 @@ static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
||||
"dsp boot timeout, status=%#x error=%#x\n",
|
||||
sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
|
||||
sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
|
||||
ret = -ETIMEDOUT;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -467,8 +467,20 @@ static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget axg_tdm_iface_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SIGGEN("Playback Signal"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route axg_tdm_iface_dapm_routes[] = {
|
||||
{ "Loopback", NULL, "Playback Signal" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver axg_tdm_iface_component_drv = {
|
||||
.set_bias_level = axg_tdm_iface_set_bias_level,
|
||||
.dapm_widgets = axg_tdm_iface_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(axg_tdm_iface_dapm_widgets),
|
||||
.dapm_routes = axg_tdm_iface_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(axg_tdm_iface_dapm_routes),
|
||||
.set_bias_level = axg_tdm_iface_set_bias_level,
|
||||
};
|
||||
|
||||
static const struct of_device_id axg_tdm_iface_of_match[] = {
|
||||
|
||||
@@ -224,15 +224,6 @@ static const struct axg_tdm_formatter_ops axg_tdmin_ops = {
|
||||
};
|
||||
|
||||
static const struct axg_tdm_formatter_driver axg_tdmin_drv = {
|
||||
.component_drv = &axg_tdmin_component_drv,
|
||||
.regmap_cfg = &axg_tdmin_regmap_cfg,
|
||||
.ops = &axg_tdmin_ops,
|
||||
.quirks = &(const struct axg_tdm_formatter_hw) {
|
||||
.skew_offset = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct axg_tdm_formatter_driver g12a_tdmin_drv = {
|
||||
.component_drv = &axg_tdmin_component_drv,
|
||||
.regmap_cfg = &axg_tdmin_regmap_cfg,
|
||||
.ops = &axg_tdmin_ops,
|
||||
@@ -247,10 +238,10 @@ static const struct of_device_id axg_tdmin_of_match[] = {
|
||||
.data = &axg_tdmin_drv,
|
||||
}, {
|
||||
.compatible = "amlogic,g12a-tdmin",
|
||||
.data = &g12a_tdmin_drv,
|
||||
.data = &axg_tdmin_drv,
|
||||
}, {
|
||||
.compatible = "amlogic,sm1-tdmin",
|
||||
.data = &g12a_tdmin_drv,
|
||||
.data = &axg_tdmin_drv,
|
||||
}, {}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axg_tdmin_of_match);
|
||||
|
||||
@@ -270,18 +270,6 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
|
||||
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
|
||||
unsigned int id = dai->driver->id;
|
||||
int ret = -EINVAL;
|
||||
unsigned int val = 0;
|
||||
|
||||
ret = regmap_read(drvdata->lpaif_map,
|
||||
LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), &val);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "error reading from i2sctl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (val == LPAIF_I2SCTL_RESET_STATE) {
|
||||
dev_err(dai->dev, "error in i2sctl register state\n");
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
@@ -454,20 +442,16 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < v->i2s_ports; ++i)
|
||||
if (reg == LPAIF_I2SCTL_REG(v, i))
|
||||
return true;
|
||||
for (i = 0; i < v->irq_ports; ++i)
|
||||
if (reg == LPAIF_IRQSTAT_REG(v, i))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < v->rdma_channels; ++i)
|
||||
if (reg == LPAIF_RDMACURR_REG(v, i) || reg == LPAIF_RDMACTL_REG(v, i))
|
||||
if (reg == LPAIF_RDMACURR_REG(v, i))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < v->wrdma_channels; ++i)
|
||||
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start) ||
|
||||
reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
|
||||
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -452,7 +452,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
unsigned int reg_irqclr = 0, val_irqclr = 0;
|
||||
unsigned int reg_irqen = 0, val_irqen = 0, val_mask = 0;
|
||||
unsigned int dai_id = cpu_dai->driver->id;
|
||||
unsigned int dma_ctrl_reg = 0;
|
||||
|
||||
ch = pcm_data->dma_ch;
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
@@ -469,17 +468,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
id = pcm_data->dma_ch - v->wrdma_channel_start;
|
||||
map = drvdata->lpaif_map;
|
||||
}
|
||||
ret = regmap_read(map, LPAIF_DMACTL_REG(v, ch, dir, dai_id), &dma_ctrl_reg);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "error reading from rdmactl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dma_ctrl_reg == LPAIF_DMACTL_RESET_STATE ||
|
||||
dma_ctrl_reg == LPAIF_DMACTL_RESET_STATE + 1) {
|
||||
dev_err(soc_runtime->dev, "error in rdmactl register state\n");
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
@@ -500,7 +489,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
"error writing to rdmactl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
map = drvdata->hdmiif_map;
|
||||
reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
|
||||
val_irqclr = (LPAIF_IRQ_ALL(ch) |
|
||||
LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
|
||||
@@ -519,7 +507,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
break;
|
||||
case MI2S_PRIMARY:
|
||||
case MI2S_SECONDARY:
|
||||
map = drvdata->lpaif_map;
|
||||
reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
|
||||
val_irqclr = LPAIF_IRQ_ALL(ch);
|
||||
|
||||
@@ -563,7 +550,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
"error writing to rdmactl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
map = drvdata->hdmiif_map;
|
||||
reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
|
||||
val_mask = (LPAIF_IRQ_ALL(ch) |
|
||||
LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
|
||||
@@ -573,7 +559,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
||||
break;
|
||||
case MI2S_PRIMARY:
|
||||
case MI2S_SECONDARY:
|
||||
map = drvdata->lpaif_map;
|
||||
reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
|
||||
val_mask = LPAIF_IRQ_ALL(ch);
|
||||
val_irqen = 0;
|
||||
@@ -838,6 +823,39 @@ static void lpass_platform_pcm_free(struct snd_soc_component *component,
|
||||
}
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct regmap *map;
|
||||
unsigned int dai_id = component->id;
|
||||
|
||||
if (dai_id == LPASS_DP_RX)
|
||||
map = drvdata->hdmiif_map;
|
||||
else
|
||||
map = drvdata->lpaif_map;
|
||||
|
||||
regcache_cache_only(map, true);
|
||||
regcache_mark_dirty(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct regmap *map;
|
||||
unsigned int dai_id = component->id;
|
||||
|
||||
if (dai_id == LPASS_DP_RX)
|
||||
map = drvdata->hdmiif_map;
|
||||
else
|
||||
map = drvdata->lpaif_map;
|
||||
|
||||
regcache_cache_only(map, false);
|
||||
return regcache_sync(map);
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_soc_component_driver lpass_component_driver = {
|
||||
.name = DRV_NAME,
|
||||
.open = lpass_platform_pcmops_open,
|
||||
@@ -850,6 +868,8 @@ static const struct snd_soc_component_driver lpass_component_driver = {
|
||||
.mmap = lpass_platform_pcmops_mmap,
|
||||
.pcm_construct = lpass_platform_pcm_new,
|
||||
.pcm_destruct = lpass_platform_pcm_free,
|
||||
.suspend = lpass_platform_pcmops_suspend,
|
||||
.resume = lpass_platform_pcmops_resume,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -366,25 +366,27 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct clk *clk;
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_clk(clk, adg, i) {
|
||||
ret = 0;
|
||||
if (enable) {
|
||||
ret = clk_prepare_enable(clk);
|
||||
int ret = clk_prepare_enable(clk);
|
||||
|
||||
/*
|
||||
* We shouldn't use clk_get_rate() under
|
||||
* atomic context. Let's keep it when
|
||||
* rsnd_adg_clk_enable() was called
|
||||
*/
|
||||
adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
|
||||
adg->clk_rate[i] = 0;
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "can't use clk %d\n", i);
|
||||
else
|
||||
adg->clk_rate[i] = clk_get_rate(clk);
|
||||
} else {
|
||||
clk_disable_unprepare(clk);
|
||||
if (adg->clk_rate[i])
|
||||
clk_disable_unprepare(clk);
|
||||
adg->clk_rate[i] = 0;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "can't use clk %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2486,6 +2486,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
|
||||
enum snd_soc_dapm_direction dir;
|
||||
|
||||
list_del(&w->list);
|
||||
list_del(&w->dirty);
|
||||
/*
|
||||
* remove source and sink paths associated to this widget.
|
||||
* While removing the path, remove reference to it from both
|
||||
|
||||
@@ -122,7 +122,7 @@ config SND_SOC_SOF_DEBUG_XRUN_STOP
|
||||
bool "SOF stop on XRUN"
|
||||
help
|
||||
This option forces PCMs to stop on any XRUN event. This is useful to
|
||||
preserve any trace data ond pipeline status prior to the XRUN.
|
||||
preserve any trace data and pipeline status prior to the XRUN.
|
||||
Say Y if you are debugging SOF FW pipeline XRUNs.
|
||||
If unsure select "N".
|
||||
|
||||
|
||||
@@ -450,10 +450,8 @@ lookup_device_name(u32 id)
|
||||
static void snd_usb_audio_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_usb_audio *chip = card->private_data;
|
||||
struct snd_usb_endpoint *ep, *n;
|
||||
|
||||
list_for_each_entry_safe(ep, n, &chip->ep_list, list)
|
||||
snd_usb_endpoint_free(ep);
|
||||
snd_usb_endpoint_free_all(chip);
|
||||
|
||||
mutex_destroy(&chip->mutex);
|
||||
if (!atomic_read(&chip->shutdown))
|
||||
@@ -611,6 +609,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
|
||||
chip->usb_id = usb_id;
|
||||
INIT_LIST_HEAD(&chip->pcm_list);
|
||||
INIT_LIST_HEAD(&chip->ep_list);
|
||||
INIT_LIST_HEAD(&chip->iface_ref_list);
|
||||
INIT_LIST_HEAD(&chip->midi_list);
|
||||
INIT_LIST_HEAD(&chip->mixer_list);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ struct audioformat {
|
||||
unsigned int frame_size; /* samples per frame for non-audio */
|
||||
unsigned char iface; /* interface number */
|
||||
unsigned char altsetting; /* corresponding alternate setting */
|
||||
unsigned char ep_idx; /* endpoint array index */
|
||||
unsigned char altset_idx; /* array index of altenate setting */
|
||||
unsigned char attributes; /* corresponding attributes of cs endpoint */
|
||||
unsigned char endpoint; /* endpoint */
|
||||
@@ -42,6 +43,7 @@ struct audioformat {
|
||||
};
|
||||
|
||||
struct snd_usb_substream;
|
||||
struct snd_usb_iface_ref;
|
||||
struct snd_usb_endpoint;
|
||||
struct snd_usb_power_domain;
|
||||
|
||||
@@ -58,6 +60,7 @@ struct snd_urb_ctx {
|
||||
|
||||
struct snd_usb_endpoint {
|
||||
struct snd_usb_audio *chip;
|
||||
struct snd_usb_iface_ref *iface_ref;
|
||||
|
||||
int opened; /* open refcount; protect with chip->mutex */
|
||||
atomic_t running; /* running status */
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
#define EP_FLAG_RUNNING 1
|
||||
#define EP_FLAG_STOPPING 2
|
||||
|
||||
/* interface refcounting */
|
||||
struct snd_usb_iface_ref {
|
||||
unsigned char iface;
|
||||
bool need_setup;
|
||||
int opened;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/*
|
||||
* snd_usb_endpoint is a model that abstracts everything related to an
|
||||
* USB endpoint and its streaming.
|
||||
@@ -488,6 +496,28 @@ exit_clear:
|
||||
clear_bit(ctx->index, &ep->active_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find or create a refcount object for the given interface
|
||||
*
|
||||
* The objects are released altogether in snd_usb_endpoint_free_all()
|
||||
*/
|
||||
static struct snd_usb_iface_ref *
|
||||
iface_ref_find(struct snd_usb_audio *chip, int iface)
|
||||
{
|
||||
struct snd_usb_iface_ref *ip;
|
||||
|
||||
list_for_each_entry(ip, &chip->iface_ref_list, list)
|
||||
if (ip->iface == iface)
|
||||
return ip;
|
||||
|
||||
ip = kzalloc(sizeof(*ip), GFP_KERNEL);
|
||||
if (!ip)
|
||||
return NULL;
|
||||
ip->iface = iface;
|
||||
list_add_tail(&ip->list, &chip->iface_ref_list);
|
||||
return ip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the existing endpoint object corresponding EP
|
||||
* Returns NULL if not present.
|
||||
@@ -520,8 +550,8 @@ snd_usb_get_endpoint(struct snd_usb_audio *chip, int ep_num)
|
||||
*
|
||||
* Returns zero on success or a negative error code.
|
||||
*
|
||||
* New endpoints will be added to chip->ep_list and must be freed by
|
||||
* calling snd_usb_endpoint_free().
|
||||
* New endpoints will be added to chip->ep_list and freed by
|
||||
* calling snd_usb_endpoint_free_all().
|
||||
*
|
||||
* For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that
|
||||
* bNumEndpoints > 1 beforehand.
|
||||
@@ -653,11 +683,17 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
|
||||
} else {
|
||||
ep->iface = fp->iface;
|
||||
ep->altsetting = fp->altsetting;
|
||||
ep->ep_idx = 0;
|
||||
ep->ep_idx = fp->ep_idx;
|
||||
}
|
||||
usb_audio_dbg(chip, "Open EP 0x%x, iface=%d:%d, idx=%d\n",
|
||||
ep_num, ep->iface, ep->altsetting, ep->ep_idx);
|
||||
|
||||
ep->iface_ref = iface_ref_find(chip, ep->iface);
|
||||
if (!ep->iface_ref) {
|
||||
ep = NULL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ep->cur_audiofmt = fp;
|
||||
ep->cur_channels = fp->channels;
|
||||
ep->cur_rate = params_rate(params);
|
||||
@@ -681,6 +717,11 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
|
||||
ep->implicit_fb_sync);
|
||||
|
||||
} else {
|
||||
if (WARN_ON(!ep->iface_ref)) {
|
||||
ep = NULL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!endpoint_compatible(ep, fp, params)) {
|
||||
usb_audio_err(chip, "Incompatible EP setup for 0x%x\n",
|
||||
ep_num);
|
||||
@@ -692,6 +733,9 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
|
||||
ep_num, ep->opened);
|
||||
}
|
||||
|
||||
if (!ep->iface_ref->opened++)
|
||||
ep->iface_ref->need_setup = true;
|
||||
|
||||
ep->opened++;
|
||||
|
||||
unlock:
|
||||
@@ -760,12 +804,16 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
|
||||
mutex_lock(&chip->mutex);
|
||||
usb_audio_dbg(chip, "Closing EP 0x%x (count %d)\n",
|
||||
ep->ep_num, ep->opened);
|
||||
if (!--ep->opened) {
|
||||
|
||||
if (!--ep->iface_ref->opened)
|
||||
endpoint_set_interface(chip, ep, false);
|
||||
|
||||
if (!--ep->opened) {
|
||||
ep->iface = 0;
|
||||
ep->altsetting = 0;
|
||||
ep->cur_audiofmt = NULL;
|
||||
ep->cur_rate = 0;
|
||||
ep->iface_ref = NULL;
|
||||
usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num);
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
@@ -775,6 +823,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
|
||||
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
|
||||
{
|
||||
ep->need_setup = true;
|
||||
if (ep->iface_ref)
|
||||
ep->iface_ref->need_setup = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1195,11 +1245,13 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
if (WARN_ON(!ep->iface_ref))
|
||||
goto unlock;
|
||||
if (!ep->need_setup)
|
||||
goto unlock;
|
||||
|
||||
/* No need to (re-)configure the sync EP belonging to the same altset */
|
||||
if (ep->ep_idx) {
|
||||
/* If the interface has been already set up, just set EP parameters */
|
||||
if (!ep->iface_ref->need_setup) {
|
||||
err = snd_usb_endpoint_set_params(chip, ep);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
@@ -1242,6 +1294,8 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ep->iface_ref->need_setup = false;
|
||||
|
||||
done:
|
||||
ep->need_setup = false;
|
||||
err = 1;
|
||||
@@ -1387,15 +1441,21 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
|
||||
* snd_usb_endpoint_free_all: Free the resources of an snd_usb_endpoint
|
||||
* @card: The chip
|
||||
*
|
||||
* @ep: the endpoint to free
|
||||
*
|
||||
* This free all resources of the given ep.
|
||||
* This free all endpoints and those resources
|
||||
*/
|
||||
void snd_usb_endpoint_free(struct snd_usb_endpoint *ep)
|
||||
void snd_usb_endpoint_free_all(struct snd_usb_audio *chip)
|
||||
{
|
||||
kfree(ep);
|
||||
struct snd_usb_endpoint *ep, *en;
|
||||
struct snd_usb_iface_ref *ip, *in;
|
||||
|
||||
list_for_each_entry_safe(ep, en, &chip->ep_list, list)
|
||||
kfree(ep);
|
||||
|
||||
list_for_each_entry_safe(ip, in, &chip->iface_ref_list, list)
|
||||
kfree(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -42,7 +42,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep);
|
||||
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_free_all(struct snd_usb_audio *chip);
|
||||
|
||||
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
|
||||
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
|
||||
|
||||
@@ -58,8 +58,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
|
||||
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */
|
||||
IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x2b73, 0x000a, 0x82, 0), /* Pioneer DJ DJM-900NXS2 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x2b73, 0x0017, 0x82, 0), /* Pioneer DJ DJM-250MK2 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */
|
||||
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172a, 0x86, 2), /* Yamaha MODX */
|
||||
@@ -100,7 +98,7 @@ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
|
||||
/* set up sync EP information on the audioformat */
|
||||
static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip,
|
||||
struct audioformat *fmt,
|
||||
int ep, int ifnum,
|
||||
int ep, int ep_idx, int ifnum,
|
||||
const struct usb_host_interface *alts)
|
||||
{
|
||||
struct usb_interface *iface;
|
||||
@@ -115,7 +113,7 @@ static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip,
|
||||
fmt->sync_ep = ep;
|
||||
fmt->sync_iface = ifnum;
|
||||
fmt->sync_altsetting = alts->desc.bAlternateSetting;
|
||||
fmt->sync_ep_idx = 0;
|
||||
fmt->sync_ep_idx = ep_idx;
|
||||
fmt->implicit_fb = 1;
|
||||
usb_audio_dbg(chip,
|
||||
"%d:%d: added %s implicit_fb sync_ep %x, iface %d:%d\n",
|
||||
@@ -147,7 +145,7 @@ static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip,
|
||||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB)
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
|
||||
ifnum, alts);
|
||||
}
|
||||
|
||||
@@ -173,10 +171,32 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip,
|
||||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB)
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
|
||||
ifnum, alts);
|
||||
}
|
||||
|
||||
/* Pioneer devices: playback and capture streams sharing the same iface/altset
|
||||
*/
|
||||
static int add_pioneer_implicit_fb(struct snd_usb_audio *chip,
|
||||
struct audioformat *fmt,
|
||||
struct usb_host_interface *alts)
|
||||
{
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
|
||||
if (alts->desc.bNumEndpoints != 2)
|
||||
return 0;
|
||||
|
||||
epd = get_endpoint(alts, 1);
|
||||
if (!usb_endpoint_is_isoc_in(epd) ||
|
||||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC ||
|
||||
((epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_DATA &&
|
||||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB))
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 1,
|
||||
alts->desc.bInterfaceNumber, alts);
|
||||
}
|
||||
|
||||
static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
|
||||
struct audioformat *fmt,
|
||||
@@ -197,7 +217,7 @@ static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
|
||||
if (!usb_endpoint_is_isoc_in(epd) ||
|
||||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
|
||||
iface, alts);
|
||||
}
|
||||
|
||||
@@ -250,7 +270,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
|
||||
case IMPLICIT_FB_NONE:
|
||||
return 0; /* No quirk */
|
||||
case IMPLICIT_FB_FIXED:
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
|
||||
p->iface, NULL);
|
||||
}
|
||||
}
|
||||
@@ -278,6 +298,14 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Pioneer devices implicit feedback with vendor spec class */
|
||||
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
|
||||
alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
USB_ID_VENDOR(chip->usb_id) == 0x2b73 /* Pioneer */) {
|
||||
if (add_pioneer_implicit_fb(chip, fmt, alts))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try the generic implicit fb if available */
|
||||
if (chip->generic_implicit_fb)
|
||||
return add_generic_implicit_fb(chip, fmt, alts);
|
||||
@@ -295,8 +323,8 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip,
|
||||
|
||||
p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts);
|
||||
if (p && p->type == IMPLICIT_FB_FIXED)
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, p->iface,
|
||||
NULL);
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
|
||||
p->iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -378,20 +406,19 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
|
||||
int stream)
|
||||
{
|
||||
struct snd_usb_substream *subs;
|
||||
const struct audioformat *fp, *sync_fmt;
|
||||
const struct audioformat *fp, *sync_fmt = NULL;
|
||||
int score, high_score;
|
||||
|
||||
/* When sharing the same altset, use the original audioformat */
|
||||
/* Use the original audioformat as fallback for the shared altset */
|
||||
if (target->iface == target->sync_iface &&
|
||||
target->altsetting == target->sync_altsetting)
|
||||
return target;
|
||||
sync_fmt = target;
|
||||
|
||||
subs = find_matching_substream(chip, stream, target->sync_ep,
|
||||
target->fmt_type);
|
||||
if (!subs)
|
||||
return NULL;
|
||||
return sync_fmt;
|
||||
|
||||
sync_fmt = NULL;
|
||||
high_score = 0;
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
score = match_endpoint_audioformats(subs, fp,
|
||||
|
||||
@@ -3362,6 +3362,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x86,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
@@ -3450,6 +3451,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
@@ -3506,6 +3508,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
@@ -3562,6 +3565,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
@@ -3619,6 +3623,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
@@ -3679,6 +3684,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
||||
@@ -120,6 +120,40 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create the audio stream and the corresponding endpoints from the fixed
|
||||
* audioformat object; this is used for quirks with the fixed EPs
|
||||
*/
|
||||
static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp)
|
||||
{
|
||||
int stream, err;
|
||||
|
||||
stream = (fp->endpoint & USB_DIR_IN) ?
|
||||
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
snd_usb_audioformat_set_sync_ep(chip, fp);
|
||||
|
||||
err = snd_usb_add_audio_stream(chip, stream, fp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_usb_add_endpoint(chip, fp->endpoint,
|
||||
SND_USB_ENDPOINT_TYPE_DATA);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (fp->sync_ep) {
|
||||
err = snd_usb_add_endpoint(chip, fp->sync_ep,
|
||||
fp->implicit_fb ?
|
||||
SND_USB_ENDPOINT_TYPE_DATA :
|
||||
SND_USB_ENDPOINT_TYPE_SYNC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* create a stream for an endpoint/altsetting without proper descriptors
|
||||
*/
|
||||
@@ -131,8 +165,8 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp;
|
||||
struct usb_host_interface *alts;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
int stream, err;
|
||||
unsigned *rate_table = NULL;
|
||||
int err;
|
||||
|
||||
fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
|
||||
if (!fp)
|
||||
@@ -153,11 +187,6 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
||||
fp->rate_table = rate_table;
|
||||
}
|
||||
|
||||
stream = (fp->endpoint & USB_DIR_IN)
|
||||
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
||||
err = snd_usb_add_audio_stream(chip, stream, fp);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
|
||||
fp->altset_idx >= iface->num_altsetting) {
|
||||
err = -EINVAL;
|
||||
@@ -165,7 +194,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
||||
}
|
||||
alts = &iface->altsetting[fp->altset_idx];
|
||||
altsd = get_iface_desc(alts);
|
||||
if (altsd->bNumEndpoints < 1) {
|
||||
if (altsd->bNumEndpoints <= fp->ep_idx) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
@@ -175,7 +204,14 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
||||
if (fp->datainterval == 0)
|
||||
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
|
||||
if (fp->maxpacksize == 0)
|
||||
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
|
||||
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, fp->ep_idx)->wMaxPacketSize);
|
||||
if (!fp->fmt_type)
|
||||
fp->fmt_type = UAC_FORMAT_TYPE_I;
|
||||
|
||||
err = add_audio_stream_from_fixed_fmt(chip, fp);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
usb_set_interface(chip->dev, fp->iface, 0);
|
||||
snd_usb_init_pitch(chip, fp);
|
||||
snd_usb_init_sample_rate(chip, fp, fp->rate_max);
|
||||
@@ -417,7 +453,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_host_interface *alts;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
struct audioformat *fp;
|
||||
int stream, err;
|
||||
int err;
|
||||
|
||||
/* both PCM and MIDI interfaces have 2 or more altsettings */
|
||||
if (iface->num_altsetting < 2)
|
||||
@@ -482,9 +518,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
stream = (fp->endpoint & USB_DIR_IN)
|
||||
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
||||
err = snd_usb_add_audio_stream(chip, stream, fp);
|
||||
err = add_audio_stream_from_fixed_fmt(chip, fp);
|
||||
if (err < 0) {
|
||||
list_del(&fp->list); /* unlink for avoiding double-free */
|
||||
kfree(fp);
|
||||
|
||||
@@ -44,6 +44,7 @@ struct snd_usb_audio {
|
||||
|
||||
struct list_head pcm_list; /* list of pcm streams */
|
||||
struct list_head ep_list; /* list of audio-related endpoints */
|
||||
struct list_head iface_ref_list; /* list of interface refcounts */
|
||||
int pcm_devs;
|
||||
|
||||
struct list_head midi_list; /* list of midi interfaces */
|
||||
|
||||
Reference in New Issue
Block a user