summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2019-06-15 05:11:01 -0400
committerTakashi Iwai <tiwai@suse.de>2019-06-17 02:18:36 -0400
commit7bc93821a70adc621df443c8b7a4745023c36e7c (patch)
tree0474e9b97389716fb9e1320d6ceeba6b61be03d2
parentc6b84ffbd5e78d6cf4aaafe5502e1bc99eb9657c (diff)
ALSA: firewire-lib: split allocation of isochronous resources from establishment of connection
In current implementation, establishment connection corresponds to allocation of isochronous resources. Although this is an ideal implementation of CMP described in IEC 61883-1, it's not enough efficient to recover PCM substream multiplexed in packet streaming. The packet streaming can always restart on the same allocated isochronous resources even if the previous packet streaming corrupted. This commit splits allocation of isochronous resources from establishment of connection so that CMP runs with allocated isochronous resources. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/firewire/bebob/bebob_stream.c30
-rw-r--r--sound/firewire/cmp.c74
-rw-r--r--sound/firewire/cmp.h7
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c22
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c18
5 files changed, 100 insertions, 51 deletions
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index 9ef4663d13e5..1070a675179d 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -404,13 +404,11 @@ static int make_both_connections(struct snd_bebob *bebob)
404{ 404{
405 int err = 0; 405 int err = 0;
406 406
407 err = cmp_connection_establish(&bebob->out_conn, 407 err = cmp_connection_establish(&bebob->out_conn);
408 amdtp_stream_get_max_payload(&bebob->tx_stream));
409 if (err < 0) 408 if (err < 0)
410 return err; 409 return err;
411 410
412 err = cmp_connection_establish(&bebob->in_conn, 411 err = cmp_connection_establish(&bebob->in_conn);
413 amdtp_stream_get_max_payload(&bebob->rx_stream));
414 if (err < 0) { 412 if (err < 0) {
415 cmp_connection_break(&bebob->out_conn); 413 cmp_connection_break(&bebob->out_conn);
416 return err; 414 return err;
@@ -533,14 +531,23 @@ static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
533 unsigned int rate, unsigned int index) 531 unsigned int rate, unsigned int index)
534{ 532{
535 struct snd_bebob_stream_formation *formation; 533 struct snd_bebob_stream_formation *formation;
534 struct cmp_connection *conn;
535 int err;
536 536
537 if (stream == &bebob->tx_stream) 537 if (stream == &bebob->tx_stream) {
538 formation = bebob->tx_stream_formations + index; 538 formation = bebob->tx_stream_formations + index;
539 else 539 conn = &bebob->out_conn;
540 } else {
540 formation = bebob->rx_stream_formations + index; 541 formation = bebob->rx_stream_formations + index;
542 conn = &bebob->in_conn;
543 }
544
545 err = amdtp_am824_set_parameters(stream, rate, formation->pcm,
546 formation->midi, false);
547 if (err < 0)
548 return err;
541 549
542 return amdtp_am824_set_parameters(stream, rate, formation->pcm, 550 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
543 formation->midi, false);
544} 551}
545 552
546int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) 553int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
@@ -591,8 +598,10 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
591 return err; 598 return err;
592 599
593 err = keep_resources(bebob, &bebob->rx_stream, rate, index); 600 err = keep_resources(bebob, &bebob->rx_stream, rate, index);
594 if (err < 0) 601 if (err < 0) {
602 cmp_connection_release(&bebob->out_conn);
595 return err; 603 return err;
604 }
596 } 605 }
597 606
598 return 0; 607 return 0;
@@ -685,6 +694,9 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
685 amdtp_stream_stop(&bebob->tx_stream); 694 amdtp_stream_stop(&bebob->tx_stream);
686 695
687 break_both_connections(bebob); 696 break_both_connections(bebob);
697
698 cmp_connection_release(&bebob->out_conn);
699 cmp_connection_release(&bebob->in_conn);
688 } 700 }
689} 701}
690 702
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index ae3bc1940efa..5dedc4f31842 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -185,6 +185,37 @@ void cmp_connection_destroy(struct cmp_connection *c)
185} 185}
186EXPORT_SYMBOL(cmp_connection_destroy); 186EXPORT_SYMBOL(cmp_connection_destroy);
187 187
188int cmp_connection_reserve(struct cmp_connection *c,
189 unsigned int max_payload_bytes)
190{
191 int err;
192
193 mutex_lock(&c->mutex);
194
195 if (WARN_ON(c->resources.allocated)) {
196 err = -EBUSY;
197 goto end;
198 }
199
200 c->speed = min(c->max_speed,
201 fw_parent_device(c->resources.unit)->max_speed);
202
203 err = fw_iso_resources_allocate(&c->resources, max_payload_bytes,
204 c->speed);
205end:
206 mutex_unlock(&c->mutex);
207
208 return err;
209}
210EXPORT_SYMBOL(cmp_connection_reserve);
211
212void cmp_connection_release(struct cmp_connection *c)
213{
214 mutex_lock(&c->mutex);
215 fw_iso_resources_free(&c->resources);
216 mutex_unlock(&c->mutex);
217}
218EXPORT_SYMBOL(cmp_connection_release);
188 219
189static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) 220static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr)
190{ 221{
@@ -270,25 +301,18 @@ static int pcr_set_check(struct cmp_connection *c, __be32 pcr)
270 * When this function succeeds, the caller is responsible for starting 301 * When this function succeeds, the caller is responsible for starting
271 * transmitting packets. 302 * transmitting packets.
272 */ 303 */
273int cmp_connection_establish(struct cmp_connection *c, 304int cmp_connection_establish(struct cmp_connection *c)
274 unsigned int max_payload_bytes)
275{ 305{
276 int err; 306 int err;
277 307
278 if (WARN_ON(c->connected))
279 return -EISCONN;
280
281 c->speed = min(c->max_speed,
282 fw_parent_device(c->resources.unit)->max_speed);
283
284 mutex_lock(&c->mutex); 308 mutex_lock(&c->mutex);
285 309
286retry_after_bus_reset: 310 if (WARN_ON(c->connected)) {
287 err = fw_iso_resources_allocate(&c->resources, 311 mutex_unlock(&c->mutex);
288 max_payload_bytes, c->speed); 312 return -EISCONN;
289 if (err < 0) 313 }
290 goto err_mutex;
291 314
315retry_after_bus_reset:
292 if (c->direction == CMP_OUTPUT) 316 if (c->direction == CMP_OUTPUT)
293 err = pcr_modify(c, opcr_set_modify, pcr_set_check, 317 err = pcr_modify(c, opcr_set_modify, pcr_set_check,
294 ABORT_ON_BUS_RESET); 318 ABORT_ON_BUS_RESET);
@@ -297,21 +321,13 @@ retry_after_bus_reset:
297 ABORT_ON_BUS_RESET); 321 ABORT_ON_BUS_RESET);
298 322
299 if (err == -EAGAIN) { 323 if (err == -EAGAIN) {
300 fw_iso_resources_free(&c->resources); 324 err = fw_iso_resources_update(&c->resources);
301 goto retry_after_bus_reset; 325 if (err >= 0)
326 goto retry_after_bus_reset;
302 } 327 }
303 if (err < 0) 328 if (err >= 0)
304 goto err_resources; 329 c->connected = true;
305
306 c->connected = true;
307
308 mutex_unlock(&c->mutex);
309
310 return 0;
311 330
312err_resources:
313 fw_iso_resources_free(&c->resources);
314err_mutex:
315 mutex_unlock(&c->mutex); 331 mutex_unlock(&c->mutex);
316 332
317 return err; 333 return err;
@@ -351,14 +367,12 @@ int cmp_connection_update(struct cmp_connection *c)
351 SUCCEED_ON_BUS_RESET); 367 SUCCEED_ON_BUS_RESET);
352 368
353 if (err < 0) 369 if (err < 0)
354 goto err_resources; 370 goto err_unconnect;
355 371
356 mutex_unlock(&c->mutex); 372 mutex_unlock(&c->mutex);
357 373
358 return 0; 374 return 0;
359 375
360err_resources:
361 fw_iso_resources_free(&c->resources);
362err_unconnect: 376err_unconnect:
363 c->connected = false; 377 c->connected = false;
364 mutex_unlock(&c->mutex); 378 mutex_unlock(&c->mutex);
@@ -395,8 +409,6 @@ void cmp_connection_break(struct cmp_connection *c)
395 if (err < 0) 409 if (err < 0)
396 cmp_error(c, "plug is still connected\n"); 410 cmp_error(c, "plug is still connected\n");
397 411
398 fw_iso_resources_free(&c->resources);
399
400 c->connected = false; 412 c->connected = false;
401 413
402 mutex_unlock(&c->mutex); 414 mutex_unlock(&c->mutex);
diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h
index b60b415caa8f..26ab88000e34 100644
--- a/sound/firewire/cmp.h
+++ b/sound/firewire/cmp.h
@@ -42,8 +42,11 @@ int cmp_connection_init(struct cmp_connection *connection,
42int cmp_connection_check_used(struct cmp_connection *connection, bool *used); 42int cmp_connection_check_used(struct cmp_connection *connection, bool *used);
43void cmp_connection_destroy(struct cmp_connection *connection); 43void cmp_connection_destroy(struct cmp_connection *connection);
44 44
45int cmp_connection_establish(struct cmp_connection *connection, 45int cmp_connection_reserve(struct cmp_connection *connection,
46 unsigned int max_payload); 46 unsigned int max_payload);
47void cmp_connection_release(struct cmp_connection *connection);
48
49int cmp_connection_establish(struct cmp_connection *connection);
47int cmp_connection_update(struct cmp_connection *connection); 50int cmp_connection_update(struct cmp_connection *connection);
48void cmp_connection_break(struct cmp_connection *connection); 51void cmp_connection_break(struct cmp_connection *connection);
49 52
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 61342c49dc38..81c1bb209a89 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -63,8 +63,7 @@ static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
63 conn = &efw->in_conn; 63 conn = &efw->in_conn;
64 64
65 // Establish connection via CMP. 65 // Establish connection via CMP.
66 err = cmp_connection_establish(conn, 66 err = cmp_connection_establish(conn);
67 amdtp_stream_get_max_payload(stream));
68 if (err < 0) 67 if (err < 0)
69 return err; 68 return err;
70 69
@@ -177,17 +176,25 @@ static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
177{ 176{
178 unsigned int pcm_channels; 177 unsigned int pcm_channels;
179 unsigned int midi_ports; 178 unsigned int midi_ports;
179 struct cmp_connection *conn;
180 int err;
180 181
181 if (stream == &efw->tx_stream) { 182 if (stream == &efw->tx_stream) {
182 pcm_channels = efw->pcm_capture_channels[mode]; 183 pcm_channels = efw->pcm_capture_channels[mode];
183 midi_ports = efw->midi_out_ports; 184 midi_ports = efw->midi_out_ports;
185 conn = &efw->out_conn;
184 } else { 186 } else {
185 pcm_channels = efw->pcm_playback_channels[mode]; 187 pcm_channels = efw->pcm_playback_channels[mode];
186 midi_ports = efw->midi_in_ports; 188 midi_ports = efw->midi_in_ports;
189 conn = &efw->in_conn;
187 } 190 }
188 191
189 return amdtp_am824_set_parameters(stream, rate, pcm_channels, 192 err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
190 midi_ports, false); 193 midi_ports, false);
194 if (err < 0)
195 return err;
196
197 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
191} 198}
192 199
193int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) 200int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
@@ -228,8 +235,10 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
228 return err; 235 return err;
229 236
230 err = keep_resources(efw, &efw->rx_stream, rate, mode); 237 err = keep_resources(efw, &efw->rx_stream, rate, mode);
231 if (err < 0) 238 if (err < 0) {
239 cmp_connection_release(&efw->in_conn);
232 return err; 240 return err;
241 }
233 } 242 }
234 243
235 return 0; 244 return 0;
@@ -285,6 +294,9 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw)
285 if (efw->substreams_counter == 0) { 294 if (efw->substreams_counter == 0) {
286 stop_stream(efw, &efw->tx_stream); 295 stop_stream(efw, &efw->tx_stream);
287 stop_stream(efw, &efw->rx_stream); 296 stop_stream(efw, &efw->rx_stream);
297
298 cmp_connection_release(&efw->out_conn);
299 cmp_connection_release(&efw->in_conn);
288 } 300 }
289} 301}
290 302
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 837733f10736..a8bc798731ff 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -111,8 +111,7 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
111 else 111 else
112 conn = &oxfw->out_conn; 112 conn = &oxfw->out_conn;
113 113
114 err = cmp_connection_establish(conn, 114 err = cmp_connection_establish(conn);
115 amdtp_stream_get_max_payload(stream));
116 if (err < 0) 115 if (err < 0)
117 return err; 116 return err;
118 117
@@ -203,15 +202,18 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
203 enum avc_general_plug_dir dir; 202 enum avc_general_plug_dir dir;
204 u8 **formats; 203 u8 **formats;
205 struct snd_oxfw_stream_formation formation; 204 struct snd_oxfw_stream_formation formation;
205 struct cmp_connection *conn;
206 int i; 206 int i;
207 int err; 207 int err;
208 208
209 if (stream == &oxfw->rx_stream) { 209 if (stream == &oxfw->rx_stream) {
210 dir = AVC_GENERAL_PLUG_DIR_IN; 210 dir = AVC_GENERAL_PLUG_DIR_IN;
211 formats = oxfw->rx_stream_formats; 211 formats = oxfw->rx_stream_formats;
212 conn = &oxfw->in_conn;
212 } else { 213 } else {
213 dir = AVC_GENERAL_PLUG_DIR_OUT; 214 dir = AVC_GENERAL_PLUG_DIR_OUT;
214 formats = oxfw->tx_stream_formats; 215 formats = oxfw->tx_stream_formats;
216 conn = &oxfw->out_conn;
215 } 217 }
216 218
217 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); 219 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
@@ -239,8 +241,12 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
239 if (formation.pcm == 0) 241 if (formation.pcm == 0)
240 return -EINVAL; 242 return -EINVAL;
241 243
242 return amdtp_am824_set_parameters(stream, formation.rate, formation.pcm, 244 err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
243 formation.midi * 8, false); 245 formation.midi * 8, false);
246 if (err < 0)
247 return err;
248
249 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
244} 250}
245 251
246int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, 252int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
@@ -299,8 +305,10 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
299 305
300 if (oxfw->has_output) { 306 if (oxfw->has_output) {
301 err = keep_resources(oxfw, &oxfw->tx_stream); 307 err = keep_resources(oxfw, &oxfw->tx_stream);
302 if (err < 0) 308 if (err < 0) {
309 cmp_connection_release(&oxfw->in_conn);
303 return err; 310 return err;
311 }
304 } 312 }
305 } 313 }
306 314
@@ -361,10 +369,12 @@ void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
361 if (oxfw->substreams_count == 0) { 369 if (oxfw->substreams_count == 0) {
362 amdtp_stream_stop(&oxfw->rx_stream); 370 amdtp_stream_stop(&oxfw->rx_stream);
363 cmp_connection_break(&oxfw->in_conn); 371 cmp_connection_break(&oxfw->in_conn);
372 cmp_connection_release(&oxfw->in_conn);
364 373
365 if (oxfw->has_output) { 374 if (oxfw->has_output) {
366 amdtp_stream_stop(&oxfw->tx_stream); 375 amdtp_stream_stop(&oxfw->tx_stream);
367 cmp_connection_break(&oxfw->out_conn); 376 cmp_connection_break(&oxfw->out_conn);
377 cmp_connection_release(&oxfw->out_conn);
368 } 378 }
369 } 379 }
370} 380}