From: Sasha Levin Date: Wed, 12 Feb 2020 03:57:54 +0000 (-0500) Subject: fixes for 4.14 X-Git-Tag: v4.4.214~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eb0ceec3e095b7f068b29c1c8f2afc291c21cbb5;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 4.14 Signed-off-by: Sasha Levin --- diff --git a/queue-4.14/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch b/queue-4.14/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch new file mode 100644 index 00000000000..cb029d37cc0 --- /dev/null +++ b/queue-4.14/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch @@ -0,0 +1,185 @@ +From c0942f363b3af1f8cdc56ea2d3682647edceb514 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Nov 2019 14:48:11 -0800 +Subject: ASoC: pcm: update FE/BE trigger order based on the command + +From: Ranjani Sridharan + +[ Upstream commit acbf27746ecfa96b290b54cc7f05273482ea128a ] + +Currently, the trigger orders SND_SOC_DPCM_TRIGGER_PRE/POST +determine the order in which FE DAI and BE DAI are triggered. +In the case of SND_SOC_DPCM_TRIGGER_PRE, the FE DAI is +triggered before the BE DAI and in the case of +SND_SOC_DPCM_TRIGGER_POST, the BE DAI is triggered before +the FE DAI. And this order remains the same irrespective of the +trigger command. + +In the case of the SOF driver, during playback, the FW +expects the BE DAI to be triggered before the FE DAI during +the START trigger. The BE DAI trigger handles the starting of +Link DMA and so it must be started before the FE DAI is started +to prevent xruns during pause/release. This can be addressed +by setting the trigger order for the FE dai link to +SND_SOC_DPCM_TRIGGER_POST. But during the STOP trigger, +the FW expects the FE DAI to be triggered before the BE DAI. +Retaining the same order during the START and STOP commands, +results in FW error as the DAI component in the FW is still +active. + +The issue can be fixed by mirroring the trigger order of +FE and BE DAI's during the START and STOP trigger. So, with the +trigger order set to SND_SOC_DPCM_TRIGGER_PRE, the FE DAI will be +trigger first during SNDRV_PCM_TRIGGER_START/STOP/RESUME +and the BE DAI will be triggered first during the +STOP/SUSPEND/PAUSE commands. Conversely, with the trigger order +set to SND_SOC_DPCM_TRIGGER_POST, the BE DAI will be triggered +first during the SNDRV_PCM_TRIGGER_START/STOP/RESUME commands +and the FE DAI will be triggered first during the +SNDRV_PCM_TRIGGER_STOP/SUSPEND/PAUSE commands. + +Signed-off-by: Ranjani Sridharan +Signed-off-by: Pierre-Louis Bossart +Link: https://lore.kernel.org/r/20191104224812.3393-2-ranjani.sridharan@linux.intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/soc-pcm.c | 95 ++++++++++++++++++++++++++++++++------------- + 1 file changed, 68 insertions(+), 27 deletions(-) + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 70e1a60a2e980..89f772ed47053 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -2123,42 +2123,81 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, + } + EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); + ++static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, ++ int cmd, bool fe_first) ++{ ++ struct snd_soc_pcm_runtime *fe = substream->private_data; ++ int ret; ++ ++ /* call trigger on the frontend before the backend. */ ++ if (fe_first) { ++ dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", ++ fe->dai_link->name, cmd); ++ ++ ret = soc_pcm_trigger(substream, cmd); ++ if (ret < 0) ++ return ret; ++ ++ ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); ++ return ret; ++ } ++ ++ /* call trigger on the frontend after the backend. */ ++ ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", ++ fe->dai_link->name, cmd); ++ ++ ret = soc_pcm_trigger(substream, cmd); ++ ++ return ret; ++} ++ + static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) + { + struct snd_soc_pcm_runtime *fe = substream->private_data; +- int stream = substream->stream, ret; ++ int stream = substream->stream; ++ int ret = 0; + enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + switch (trigger) { + case SND_SOC_DPCM_TRIGGER_PRE: +- /* call trigger on the frontend before the backend. */ +- +- dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", +- fe->dai_link->name, cmd); +- +- ret = soc_pcm_trigger(substream, cmd); +- if (ret < 0) { +- dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); +- goto out; ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ ret = dpcm_dai_trigger_fe_be(substream, cmd, true); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ ret = dpcm_dai_trigger_fe_be(substream, cmd, false); ++ break; ++ default: ++ ret = -EINVAL; ++ break; + } +- +- ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + break; + case SND_SOC_DPCM_TRIGGER_POST: +- /* call trigger on the frontend after the backend. */ +- +- ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); +- if (ret < 0) { +- dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); +- goto out; ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ ret = dpcm_dai_trigger_fe_be(substream, cmd, false); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ ret = dpcm_dai_trigger_fe_be(substream, cmd, true); ++ break; ++ default: ++ ret = -EINVAL; ++ break; + } +- +- dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", +- fe->dai_link->name, cmd); +- +- ret = soc_pcm_trigger(substream, cmd); + break; + case SND_SOC_DPCM_TRIGGER_BESPOKE: + /* bespoke trigger() - handles both FE and BEs */ +@@ -2167,10 +2206,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) + fe->dai_link->name, cmd); + + ret = soc_pcm_bespoke_trigger(substream, cmd); +- if (ret < 0) { +- dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); +- goto out; +- } + break; + default: + dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, +@@ -2179,6 +2214,12 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) + goto out; + } + ++ if (ret < 0) { ++ dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", ++ cmd, ret); ++ goto out; ++ } ++ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: +-- +2.20.1 + diff --git a/queue-4.14/hv_sock-remove-the-accept-port-restriction.patch b/queue-4.14/hv_sock-remove-the-accept-port-restriction.patch new file mode 100644 index 00000000000..764ff68f5d1 --- /dev/null +++ b/queue-4.14/hv_sock-remove-the-accept-port-restriction.patch @@ -0,0 +1,168 @@ +From d7c1e55fdece37f1454987722615dbc0c3c713ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jan 2020 03:08:18 +0000 +Subject: hv_sock: Remove the accept port restriction + +From: Sunil Muthuswamy + +[ Upstream commit c742c59e1fbd022b64d91aa9a0092b3a699d653c ] + +Currently, hv_sock restricts the port the guest socket can accept +connections on. hv_sock divides the socket port namespace into two parts +for server side (listening socket), 0-0x7FFFFFFF & 0x80000000-0xFFFFFFFF +(there are no restrictions on client port namespace). The first part +(0-0x7FFFFFFF) is reserved for sockets where connections can be accepted. +The second part (0x80000000-0xFFFFFFFF) is reserved for allocating ports +for the peer (host) socket, once a connection is accepted. +This reservation of the port namespace is specific to hv_sock and not +known by the generic vsock library (ex: af_vsock). This is problematic +because auto-binds/ephemeral ports are handled by the generic vsock +library and it has no knowledge of this port reservation and could +allocate a port that is not compatible with hv_sock (and legitimately so). +The issue hasn't surfaced so far because the auto-bind code of vsock +(__vsock_bind_stream) prior to the change 'VSOCK: bind to random port for +VMADDR_PORT_ANY' would start walking up from LAST_RESERVED_PORT (1023) and +start assigning ports. That will take a large number of iterations to hit +0x7FFFFFFF. But, after the above change to randomize port selection, the +issue has started coming up more frequently. +There has really been no good reason to have this port reservation logic +in hv_sock from the get go. Reserving a local port for peer ports is not +how things are handled generally. Peer ports should reflect the peer port. +This fixes the issue by lifting the port reservation, and also returns the +right peer port. Since the code converts the GUID to the peer port (by +using the first 4 bytes), there is a possibility of conflicts, but that +seems like a reasonable risk to take, given this is limited to vsock and +that only applies to all local sockets. + +Signed-off-by: Sunil Muthuswamy +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/hyperv_transport.c | 68 +++++--------------------------- + 1 file changed, 9 insertions(+), 59 deletions(-) + +diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c +index 6614512f81800..736b76ec8cf01 100644 +--- a/net/vmw_vsock/hyperv_transport.c ++++ b/net/vmw_vsock/hyperv_transport.c +@@ -144,28 +144,15 @@ struct hvsock { + **************************************************************************** + * The only valid Service GUIDs, from the perspectives of both the host and * + * Linux VM, that can be connected by the other end, must conform to this * +- * format: -facb-11e6-bd58-64006a7986d3, and the "port" must be in * +- * this range [0, 0x7FFFFFFF]. * ++ * format: -facb-11e6-bd58-64006a7986d3. * + **************************************************************************** + * + * When we write apps on the host to connect(), the GUID ServiceID is used. + * When we write apps in Linux VM to connect(), we only need to specify the + * port and the driver will form the GUID and use that to request the host. + * +- * From the perspective of Linux VM: +- * 1. the local ephemeral port (i.e. the local auto-bound port when we call +- * connect() without explicit bind()) is generated by __vsock_bind_stream(), +- * and the range is [1024, 0xFFFFFFFF). +- * 2. the remote ephemeral port (i.e. the auto-generated remote port for +- * a connect request initiated by the host's connect()) is generated by +- * hvs_remote_addr_init() and the range is [0x80000000, 0xFFFFFFFF). + */ + +-#define MAX_LISTEN_PORT ((u32)0x7FFFFFFF) +-#define MAX_VM_LISTEN_PORT MAX_LISTEN_PORT +-#define MAX_HOST_LISTEN_PORT MAX_LISTEN_PORT +-#define MIN_HOST_EPHEMERAL_PORT (MAX_HOST_LISTEN_PORT + 1) +- + /* 00000000-facb-11e6-bd58-64006a7986d3 */ + static const uuid_le srv_id_template = + UUID_LE(0x00000000, 0xfacb, 0x11e6, 0xbd, 0x58, +@@ -188,33 +175,6 @@ static void hvs_addr_init(struct sockaddr_vm *addr, const uuid_le *svr_id) + vsock_addr_init(addr, VMADDR_CID_ANY, port); + } + +-static void hvs_remote_addr_init(struct sockaddr_vm *remote, +- struct sockaddr_vm *local) +-{ +- static u32 host_ephemeral_port = MIN_HOST_EPHEMERAL_PORT; +- struct sock *sk; +- +- vsock_addr_init(remote, VMADDR_CID_ANY, VMADDR_PORT_ANY); +- +- while (1) { +- /* Wrap around ? */ +- if (host_ephemeral_port < MIN_HOST_EPHEMERAL_PORT || +- host_ephemeral_port == VMADDR_PORT_ANY) +- host_ephemeral_port = MIN_HOST_EPHEMERAL_PORT; +- +- remote->svm_port = host_ephemeral_port++; +- +- sk = vsock_find_connected_socket(remote, local); +- if (!sk) { +- /* Found an available ephemeral port */ +- return; +- } +- +- /* Release refcnt got in vsock_find_connected_socket */ +- sock_put(sk); +- } +-} +- + static void hvs_set_channel_pending_send_size(struct vmbus_channel *chan) + { + set_channel_pending_send_size(chan, +@@ -342,12 +302,7 @@ static void hvs_open_connection(struct vmbus_channel *chan) + if_type = &chan->offermsg.offer.if_type; + if_instance = &chan->offermsg.offer.if_instance; + conn_from_host = chan->offermsg.offer.u.pipe.user_def[0]; +- +- /* The host or the VM should only listen on a port in +- * [0, MAX_LISTEN_PORT] +- */ +- if (!is_valid_srv_id(if_type) || +- get_port_by_srv_id(if_type) > MAX_LISTEN_PORT) ++ if (!is_valid_srv_id(if_type)) + return; + + hvs_addr_init(&addr, conn_from_host ? if_type : if_instance); +@@ -372,6 +327,13 @@ static void hvs_open_connection(struct vmbus_channel *chan) + + new->sk_state = TCP_SYN_SENT; + vnew = vsock_sk(new); ++ ++ hvs_addr_init(&vnew->local_addr, if_type); ++ ++ /* Remote peer is always the host */ ++ vsock_addr_init(&vnew->remote_addr, ++ VMADDR_CID_HOST, VMADDR_PORT_ANY); ++ vnew->remote_addr.svm_port = get_port_by_srv_id(if_instance); + hvs_new = vnew->trans; + hvs_new->chan = chan; + } else { +@@ -411,8 +373,6 @@ static void hvs_open_connection(struct vmbus_channel *chan) + sk->sk_ack_backlog++; + + hvs_addr_init(&vnew->local_addr, if_type); +- hvs_remote_addr_init(&vnew->remote_addr, &vnew->local_addr); +- + hvs_new->vm_srv_id = *if_type; + hvs_new->host_srv_id = *if_instance; + +@@ -717,16 +677,6 @@ static bool hvs_stream_is_active(struct vsock_sock *vsk) + + static bool hvs_stream_allow(u32 cid, u32 port) + { +- /* The host's port range [MIN_HOST_EPHEMERAL_PORT, 0xFFFFFFFF) is +- * reserved as ephemeral ports, which are used as the host's ports +- * when the host initiates connections. +- * +- * Perform this check in the guest so an immediate error is produced +- * instead of a timeout. +- */ +- if (port > MAX_HOST_LISTEN_PORT) +- return false; +- + if (cid == VMADDR_CID_HOST) + return true; + +-- +2.20.1 + diff --git a/queue-4.14/series b/queue-4.14/series index e2ea4938be4..2a0c5d401c3 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -138,3 +138,5 @@ cifs-fail-i-o-on-soft-mounts-if-sessionsetup-errors-out.patch clocksource-prevent-double-add_timer_on-for-watchdog_timer.patch perf-core-fix-mlock-accounting-in-perf_mmap.patch rxrpc-fix-service-call-disconnection.patch +asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch +hv_sock-remove-the-accept-port-restriction.patch