Update Linux to v5.4.2

Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index 7888092..e8e6f9f 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -1,132 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * ff-stream.c - a part of driver for RME Fireface series
  *
  * Copyright (c) 2015-2017 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
  */
 
 #include "ff.h"
 
 #define CALLBACK_TIMEOUT_MS	200
 
-static int get_rate_mode(unsigned int rate, unsigned int *mode)
+int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
+				      enum snd_ff_stream_mode *mode)
 {
-	int i;
+	static const enum snd_ff_stream_mode modes[] = {
+		[CIP_SFC_32000] = SND_FF_STREAM_MODE_LOW,
+		[CIP_SFC_44100] = SND_FF_STREAM_MODE_LOW,
+		[CIP_SFC_48000] = SND_FF_STREAM_MODE_LOW,
+		[CIP_SFC_88200] = SND_FF_STREAM_MODE_MID,
+		[CIP_SFC_96000] = SND_FF_STREAM_MODE_MID,
+		[CIP_SFC_176400] = SND_FF_STREAM_MODE_HIGH,
+		[CIP_SFC_192000] = SND_FF_STREAM_MODE_HIGH,
+	};
 
-	for (i = 0; i < CIP_SFC_COUNT; i++) {
-		if (amdtp_rate_table[i] == rate)
-			break;
-	}
-
-	if (i == CIP_SFC_COUNT)
+	if (sfc >= CIP_SFC_COUNT)
 		return -EINVAL;
 
-	*mode = ((int)i - 1) / 2;
+	*mode = modes[sfc];
 
 	return 0;
 }
 
-/*
- * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
- * we can allocate between 0 and 7 channel.
- */
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
-{
-	int mode;
-	int err;
-
-	err = get_rate_mode(rate, &mode);
-	if (err < 0)
-		return err;
-
-	/* Keep resources for in-stream. */
-	err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
-				      ff->spec->pcm_capture_channels[mode]);
-	if (err < 0)
-		return err;
-	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
-	err = fw_iso_resources_allocate(&ff->tx_resources,
-			amdtp_stream_get_max_payload(&ff->tx_stream),
-			fw_parent_device(ff->unit)->max_speed);
-	if (err < 0)
-		return err;
-
-	/* Keep resources for out-stream. */
-	err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
-				      ff->spec->pcm_playback_channels[mode]);
-	if (err < 0)
-		return err;
-	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
-	err = fw_iso_resources_allocate(&ff->rx_resources,
-			amdtp_stream_get_max_payload(&ff->rx_stream),
-			fw_parent_device(ff->unit)->max_speed);
-	if (err < 0)
-		fw_iso_resources_free(&ff->tx_resources);
-
-	return err;
-}
-
-static void release_resources(struct snd_ff *ff)
-{
-	fw_iso_resources_free(&ff->tx_resources);
-	fw_iso_resources_free(&ff->rx_resources);
-}
-
 static inline void finish_session(struct snd_ff *ff)
 {
 	ff->spec->protocol->finish_session(ff);
 	ff->spec->protocol->switch_fetching_mode(ff, false);
 }
 
-static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
+static int init_stream(struct snd_ff *ff, struct amdtp_stream *s)
 {
-	int err;
 	struct fw_iso_resources *resources;
-	struct amdtp_stream *stream;
+	enum amdtp_stream_direction dir;
+	int err;
 
-	if (dir == AMDTP_IN_STREAM) {
+	if (s == &ff->tx_stream) {
 		resources = &ff->tx_resources;
-		stream = &ff->tx_stream;
+		dir = AMDTP_IN_STREAM;
 	} else {
 		resources = &ff->rx_resources;
-		stream = &ff->rx_stream;
+		dir = AMDTP_OUT_STREAM;
 	}
 
 	err = fw_iso_resources_init(resources, ff->unit);
 	if (err < 0)
 		return err;
 
-	err = amdtp_ff_init(stream, ff->unit, dir);
+	err = amdtp_ff_init(s, ff->unit, dir);
 	if (err < 0)
 		fw_iso_resources_destroy(resources);
 
 	return err;
 }
 
-static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
+static void destroy_stream(struct snd_ff *ff, struct amdtp_stream *s)
 {
-	if (dir == AMDTP_IN_STREAM) {
-		amdtp_stream_destroy(&ff->tx_stream);
+	amdtp_stream_destroy(s);
+
+	if (s == &ff->tx_stream)
 		fw_iso_resources_destroy(&ff->tx_resources);
-	} else {
-		amdtp_stream_destroy(&ff->rx_stream);
+	else
 		fw_iso_resources_destroy(&ff->rx_resources);
-	}
 }
 
 int snd_ff_stream_init_duplex(struct snd_ff *ff)
 {
 	int err;
 
-	err = init_stream(ff, AMDTP_OUT_STREAM);
+	err = init_stream(ff, &ff->rx_stream);
 	if (err < 0)
-		goto end;
+		return err;
 
-	err = init_stream(ff, AMDTP_IN_STREAM);
-	if (err < 0)
-		destroy_stream(ff, AMDTP_OUT_STREAM);
-end:
+	err = init_stream(ff, &ff->tx_stream);
+	if (err < 0) {
+		destroy_stream(ff, &ff->rx_stream);
+		return err;
+	}
+
+	err = amdtp_domain_init(&ff->domain);
+	if (err < 0) {
+		destroy_stream(ff, &ff->rx_stream);
+		destroy_stream(ff, &ff->tx_stream);
+	}
+
 	return err;
 }
 
@@ -136,31 +100,72 @@
  */
 void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
 {
-	destroy_stream(ff, AMDTP_IN_STREAM);
-	destroy_stream(ff, AMDTP_OUT_STREAM);
+	amdtp_domain_destroy(&ff->domain);
+
+	destroy_stream(ff, &ff->rx_stream);
+	destroy_stream(ff, &ff->tx_stream);
 }
 
-int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
 {
 	unsigned int curr_rate;
 	enum snd_ff_clock_src src;
 	int err;
 
-	if (ff->substreams_counter == 0)
-		return 0;
-
 	err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
 	if (err < 0)
 		return err;
-	if (curr_rate != rate ||
-	    amdtp_streaming_error(&ff->tx_stream) ||
-	    amdtp_streaming_error(&ff->rx_stream)) {
+
+	if (ff->substreams_counter == 0 || curr_rate != rate) {
+		enum snd_ff_stream_mode mode;
+		int i;
+
+		amdtp_domain_stop(&ff->domain);
 		finish_session(ff);
 
-		amdtp_stream_stop(&ff->tx_stream);
-		amdtp_stream_stop(&ff->rx_stream);
+		fw_iso_resources_free(&ff->tx_resources);
+		fw_iso_resources_free(&ff->rx_resources);
 
-		release_resources(ff);
+		for (i = 0; i < CIP_SFC_COUNT; ++i) {
+			if (amdtp_rate_table[i] == rate)
+				break;
+		}
+		if (i >= CIP_SFC_COUNT)
+			return -EINVAL;
+
+		err = snd_ff_stream_get_multiplier_mode(i, &mode);
+		if (err < 0)
+			return err;
+
+		err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
+					ff->spec->pcm_capture_channels[mode]);
+		if (err < 0)
+			return err;
+
+		err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
+					ff->spec->pcm_playback_channels[mode]);
+		if (err < 0)
+			return err;
+
+		err = ff->spec->protocol->allocate_resources(ff, rate);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+{
+	int err;
+
+	if (ff->substreams_counter == 0)
+		return 0;
+
+	if (amdtp_streaming_error(&ff->tx_stream) ||
+	    amdtp_streaming_error(&ff->rx_stream)) {
+		amdtp_domain_stop(&ff->domain);
+		finish_session(ff);
 	}
 
 	/*
@@ -168,21 +173,29 @@
 	 * packets. Then, the device transfers packets.
 	 */
 	if (!amdtp_stream_running(&ff->rx_stream)) {
-		err = keep_resources(ff, rate);
-		if (err < 0)
-			goto error;
+		int spd = fw_parent_device(ff->unit)->max_speed;
 
 		err = ff->spec->protocol->begin_session(ff, rate);
 		if (err < 0)
 			goto error;
 
-		err = amdtp_stream_start(&ff->rx_stream,
-					 ff->rx_resources.channel,
-					 fw_parent_device(ff->unit)->max_speed);
+		err = amdtp_domain_add_stream(&ff->domain, &ff->rx_stream,
+					      ff->rx_resources.channel, spd);
+		if (err < 0)
+			goto error;
+
+		err = amdtp_domain_add_stream(&ff->domain, &ff->tx_stream,
+					      ff->tx_resources.channel, spd);
+		if (err < 0)
+			goto error;
+
+		err = amdtp_domain_start(&ff->domain);
 		if (err < 0)
 			goto error;
 
 		if (!amdtp_stream_wait_callback(&ff->rx_stream,
+						CALLBACK_TIMEOUT_MS) ||
+		    !amdtp_stream_wait_callback(&ff->tx_stream,
 						CALLBACK_TIMEOUT_MS)) {
 			err = -ETIMEDOUT;
 			goto error;
@@ -193,53 +206,32 @@
 			goto error;
 	}
 
-	if (!amdtp_stream_running(&ff->tx_stream)) {
-		err = amdtp_stream_start(&ff->tx_stream,
-					 ff->tx_resources.channel,
-					 fw_parent_device(ff->unit)->max_speed);
-		if (err < 0)
-			goto error;
-
-		if (!amdtp_stream_wait_callback(&ff->tx_stream,
-						CALLBACK_TIMEOUT_MS)) {
-			err = -ETIMEDOUT;
-			goto error;
-		}
-	}
-
 	return 0;
 error:
-	amdtp_stream_stop(&ff->tx_stream);
-	amdtp_stream_stop(&ff->rx_stream);
-
+	amdtp_domain_stop(&ff->domain);
 	finish_session(ff);
-	release_resources(ff);
 
 	return err;
 }
 
 void snd_ff_stream_stop_duplex(struct snd_ff *ff)
 {
-	if (ff->substreams_counter > 0)
-		return;
+	if (ff->substreams_counter == 0) {
+		amdtp_domain_stop(&ff->domain);
+		finish_session(ff);
 
-	amdtp_stream_stop(&ff->tx_stream);
-	amdtp_stream_stop(&ff->rx_stream);
-	finish_session(ff);
-	release_resources(ff);
+		fw_iso_resources_free(&ff->tx_resources);
+		fw_iso_resources_free(&ff->rx_resources);
+	}
 }
 
 void snd_ff_stream_update_duplex(struct snd_ff *ff)
 {
-	/* The device discontinue to transfer packets.  */
+	amdtp_domain_stop(&ff->domain);
+
+	// The device discontinue to transfer packets.
 	amdtp_stream_pcm_abort(&ff->tx_stream);
-	amdtp_stream_stop(&ff->tx_stream);
-
 	amdtp_stream_pcm_abort(&ff->rx_stream);
-	amdtp_stream_stop(&ff->rx_stream);
-
-	fw_iso_resources_update(&ff->tx_resources);
-	fw_iso_resources_update(&ff->rx_resources);
 }
 
 void snd_ff_stream_lock_changed(struct snd_ff *ff)