Skip to content

Commit 7498ab8

Browse files
committed
drm: apple: audio: Rework audio service handling
'open' and 'close' the service/link in iomfb's power-on and shutdown and on HPD deassert. This avoids leaking DCPAVAudioInterface services over display power cycles and tears the service properly down. For unknown reasons this is only observed with DCPs connected to atc phys as for DP altmode and the HDMI ports on Macbook Pros. Signed-off-by: Janne Grunau <j@jannau.net> drm: apple: Rework audio service initialization Signed-off-by: Janne Grunau <j@jannau.net>
1 parent ff8f8d2 commit 7498ab8

3 files changed

Lines changed: 100 additions & 18 deletions

File tree

drivers/gpu/drm/apple/av.c

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313

1414
#include "audio.h"
1515
#include "afk.h"
16+
#include "av.h"
1617
#include "dcp.h"
1718
#include "dcp-internal.h"
1819

1920
struct dcp_av_audio_cmds {
2021
/* commands in group 0*/
2122
u32 open;
23+
u32 close;
2224
u32 prepare;
2325
u32 start_link;
2426
u32 stop_link;
@@ -30,6 +32,7 @@ struct dcp_av_audio_cmds {
3032

3133
static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v12_3 = {
3234
.open = 6,
35+
.close = 7,
3336
.prepare = 8,
3437
.start_link = 9,
3538
.stop_link = 12,
@@ -40,6 +43,7 @@ static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v12_3 = {
4043

4144
static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v13_5 = {
4245
.open = 4,
46+
.close = 5,
4347
.prepare = 6,
4448
.start_link = 7,
4549
.stop_link = 10,
@@ -62,6 +66,7 @@ struct audiosrv_data {
6266

6367
bool warned_get_elements;
6468
bool warned_get_product_attrs;
69+
bool is_open;
6570
};
6671

6772
static void av_interface_init(struct apple_epic_service *service, const char *name,
@@ -285,34 +290,89 @@ static const struct apple_epic_service_ops avep_ops[] = {
285290
{}
286291
};
287292

288-
static void av_work_service_start(struct work_struct *work)
293+
void av_service_connect(struct apple_dcp *dcp)
289294
{
295+
struct apple_epic_service *service;
296+
struct audiosrv_data *asrv = dcp->audiosrv;
290297
int ret;
291-
struct audiosrv_data *audiosrv_data;
292-
struct apple_dcp *dcp;
293298

294-
audiosrv_data = container_of(work, struct audiosrv_data, start_av_service_wq);
295-
if (!audiosrv_data->srv ||
296-
!audiosrv_data->srv->ep ||
297-
!audiosrv_data->srv->ep->dcp) {
298-
pr_err("%s: dcp: av: NULL ptr during startup\n", __func__);
299-
return;
299+
scoped_guard(rwsem_write, &asrv->srv_rwsem) {
300+
if (!asrv->srv)
301+
return;
302+
service = asrv->srv;
300303
}
301-
dcp = audiosrv_data->srv->ep->dcp;
302304

303305
/* open AV audio service */
304-
dev_info(dcp->dev, "%s: starting audio service\n", __func__);
305-
ret = afk_service_call(dcp->audiosrv->srv, 0, dcp->audiosrv->cmds.open,
306-
NULL, 0, 32, NULL, 0, 32);
306+
dev_info(dcp->dev, "%s: starting audio service, plugged:%d\n", __func__, asrv->plugged);
307+
if (asrv->is_open)
308+
return;
309+
310+
ret = afk_service_call(service, 0, asrv->cmds.open, NULL, 0, 32,
311+
NULL, 0, 32);
307312
if (ret) {
308313
dev_err(dcp->dev, "error opening audio service: %d\n", ret);
309314
return;
310315
}
316+
mutex_lock(&asrv->plug_lock);
317+
asrv->is_open = true;
311318

312-
mutex_lock(&dcp->audiosrv->plug_lock);
313-
if (dcp->audiosrv->audio_dev)
314-
dcpaud_connect(dcp->audiosrv->audio_dev, dcp->audiosrv->plugged);
315-
mutex_unlock(&dcp->audiosrv->plug_lock);
319+
if (asrv->audio_dev)
320+
dcpaud_connect(asrv->audio_dev, asrv->plugged);
321+
mutex_unlock(&asrv->plug_lock);
322+
}
323+
324+
void av_service_disconnect(struct apple_dcp *dcp)
325+
{
326+
struct apple_epic_service *service;
327+
struct audiosrv_data *asrv = dcp->audiosrv;
328+
int ret;
329+
330+
scoped_guard(rwsem_write, &asrv->srv_rwsem) {
331+
if (!asrv->srv)
332+
return;
333+
service = asrv->srv;
334+
}
335+
336+
/* close AV audio service */
337+
dev_info(dcp->dev, "%s: stopping audio service\n", __func__);
338+
if (!asrv->is_open)
339+
return;
340+
341+
mutex_lock(&asrv->plug_lock);
342+
343+
if (asrv->audio_dev)
344+
dcpaud_disconnect(asrv->audio_dev);
345+
346+
mutex_unlock(&asrv->plug_lock);
347+
348+
ret = afk_service_call(service, 0, asrv->cmds.close, NULL, 0, 16,
349+
NULL, 0, 16);
350+
if (ret) {
351+
dev_err(dcp->dev, "error closing audio service: %d\n", ret);
352+
}
353+
if (service->torndown)
354+
service->enabled = false;
355+
asrv->is_open = false;
356+
}
357+
358+
static void av_work_service_start(struct work_struct *work)
359+
{
360+
struct audiosrv_data *audiosrv_data;
361+
struct apple_dcp *dcp;
362+
363+
audiosrv_data = container_of(work, struct audiosrv_data, start_av_service_wq);
364+
365+
scoped_guard(rwsem_read, &audiosrv_data->srv_rwsem) {
366+
if (!audiosrv_data->srv ||
367+
!audiosrv_data->srv->ep ||
368+
!audiosrv_data->srv->ep->dcp) {
369+
pr_err("%s: dcp: av: NULL ptr during startup\n", __func__);
370+
return;
371+
}
372+
dcp = audiosrv_data->srv->ep->dcp;
373+
}
374+
375+
av_service_connect(dcp);
316376
}
317377

318378
int avep_init(struct apple_dcp *dcp)
@@ -339,9 +399,9 @@ int avep_init(struct apple_dcp *dcp)
339399
dev_err(dcp->dev, "Audio not supported for firmware\n");
340400
return -ENODEV;
341401
}
342-
INIT_WORK(&audiosrv_data->start_av_service_wq, av_work_service_start);
343402

344403
dcp->audiosrv = audiosrv_data;
404+
INIT_WORK(&audiosrv_data->start_av_service_wq, av_work_service_start);
345405

346406
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
347407
if (endpoint) {

drivers/gpu/drm/apple/av.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@
66
//int avep_audiosrv_startlink(struct apple_dcp *dcp, struct dcp_sound_cookie *cookie);
77
//int avep_audiosrv_stoplink(struct apple_dcp *dcp);
88

9+
void av_service_connect(struct apple_dcp *dcp);
10+
void av_service_disconnect(struct apple_dcp *dcp);
11+
912
#endif /* __AV_H__ */

drivers/gpu/drm/apple/dcp.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <drm/drm_vblank.h>
3232

3333
#include "afk.h"
34+
#include "av.h"
3435
#include "dcp.h"
3536
#include "dcp-internal.h"
3637
#include "iomfb.h"
@@ -413,6 +414,9 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port)
413414
if (dcp->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
414415
dptxport_set_hpd(dcp->dptxport[port].service, true);
415416

417+
if (dcp->avep)
418+
av_service_connect(dcp);
419+
416420
return 0;
417421

418422
out_unlock:
@@ -444,6 +448,8 @@ EXPORT_SYMBOL_GPL(dcp_dptx_connect_oob);
444448
int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port)
445449
{
446450
struct apple_dcp *dcp = platform_get_drvdata(pdev);
451+
if (dcp->avep)
452+
av_service_disconnect(dcp);
447453
dptxport_set_hpd(dcp->dptxport[port].service, false);
448454
return dcp_dptx_disconnect(dcp, port);
449455
}
@@ -629,13 +635,19 @@ void dcp_poweron(struct platform_device *pdev)
629635
WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat);
630636
break;
631637
}
638+
639+
if (dcp->avep)
640+
av_service_connect(dcp);
632641
}
633642
EXPORT_SYMBOL(dcp_poweron);
634643

635644
void dcp_poweroff(struct platform_device *pdev)
636645
{
637646
struct apple_dcp *dcp = platform_get_drvdata(pdev);
638647

648+
if (dcp->avep)
649+
av_service_disconnect(dcp);
650+
639651
switch (dcp->fw_compat) {
640652
case DCP_FIRMWARE_V_12_3:
641653
iomfb_poweroff_v12_3(dcp);
@@ -1074,6 +1086,7 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data)
10741086
disable_irq(dcp->hdmi_hpd_irq);
10751087

10761088
if (dcp->avep) {
1089+
av_service_disconnect(dcp);
10771090
afk_shutdown(dcp->avep);
10781091
dcp->avep = NULL;
10791092
}
@@ -1230,6 +1243,9 @@ static int dcp_platform_suspend(struct device *dev)
12301243
{
12311244
struct apple_dcp *dcp = dev_get_drvdata(dev);
12321245

1246+
if (dcp->avep)
1247+
av_service_disconnect(dcp);
1248+
12331249
if (dcp->hdmi_hpd_irq) {
12341250
disable_irq(dcp->hdmi_hpd_irq);
12351251
dcp_dptx_disconnect(dcp, 0);
@@ -1258,6 +1274,9 @@ static int dcp_platform_resume(struct device *dev)
12581274
dcp_dptx_connect(dcp, 0);
12591275
}
12601276

1277+
if (dcp->avep)
1278+
av_service_connect(dcp);
1279+
12611280
return 0;
12621281
}
12631282

0 commit comments

Comments
 (0)