Skip to content

Commit d7e0dd3

Browse files
hoshinolinajannau
authored andcommitted
drm/apple: audio: Defer DMA channel acquisition to device open
Allow the DMA device driver to probe late, and still create the sound device upfront. Instead try to request the DMA channel on first PCM open. This should be safe as long as we bail early and don't allow the process to continue to configuring buffers (since that requires the DMA to be configured). Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent e174462 commit d7e0dd3

1 file changed

Lines changed: 57 additions & 48 deletions

File tree

drivers/gpu/drm/apple/audio.c

Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -212,17 +212,47 @@ static int dcpaud_rule_rate(struct snd_pcm_hw_params *params,
212212
return snd_interval_rate_bits(r, hits.rates);
213213
}
214214

215+
static int dcpaud_init_dma(struct dcp_audio *dcpaud)
216+
{
217+
struct dma_chan *chan;
218+
if (dcpaud->chan)
219+
return 0;
220+
221+
chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx");
222+
/* squelch dma channel request errors, the driver will try again alter */
223+
if (!chan) {
224+
dev_warn(dcpaud->dev, "audio TX DMA channel request failed\n");
225+
return -ENXIO;
226+
} else if (chan == ERR_PTR(-EPROBE_DEFER)) {
227+
dev_info(dcpaud->dev, "audio TX DMA channel is not ready yet\n");
228+
return -ENXIO;
229+
} else if (IS_ERR(chan)) {
230+
dev_warn(dcpaud->dev, "audio TX DMA channel request failed: %ld\n", PTR_ERR(chan));
231+
return PTR_ERR(chan);
232+
}
233+
dcpaud->chan = chan;
234+
235+
snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM,
236+
dcpaud->chan->device->dev, 1024 * 1024,
237+
SIZE_MAX);
238+
239+
return 0;
240+
}
241+
215242
static int dcp_pcm_open(struct snd_pcm_substream *substream)
216243
{
217244
struct dcp_audio *dcpaud = substream->pcm->private_data;
218-
struct dma_chan *chan = dcpaud->chan;
219245
struct snd_dmaengine_dai_dma_data dma_data = {
220246
.flags = SND_DMAENGINE_PCM_DAI_FLAG_PACK,
221247
};
222248
struct snd_pcm_hardware hw;
223249
int ret;
224250

225251
mutex_lock(&dcpaud->data_lock);
252+
ret = dcpaud_init_dma(dcpaud);
253+
if (ret < 0)
254+
return ret;
255+
226256
if (!dcpaud->connected) {
227257
mutex_unlock(&dcpaud->data_lock);
228258
return -ENXIO;
@@ -254,12 +284,12 @@ static int dcp_pcm_open(struct snd_pcm_substream *substream)
254284
hw.buffer_bytes_max = SIZE_MAX;
255285
hw.fifo_size = 16;
256286
ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, &dma_data,
257-
&hw, chan);
287+
&hw, dcpaud->chan);
258288
if (ret)
259289
return ret;
260290
substream->runtime->hw = hw;
261291

262-
return snd_dmaengine_pcm_open(substream, chan);
292+
return snd_dmaengine_pcm_open(substream, dcpaud->chan);
263293
}
264294

265295
static int dcp_pcm_close(struct snd_pcm_substream *substream)
@@ -442,10 +472,6 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
442472

443473
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops);
444474
dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
445-
snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM,
446-
dcpaud->chan->device->dev, 1024 * 1024,
447-
SIZE_MAX);
448-
449475
pcm->nonatomic = true;
450476
pcm->private_data = dcpaud;
451477
strscpy(pcm->name, card->shortname, sizeof(pcm->name));
@@ -494,26 +520,29 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud)
494520
strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname));
495521
}
496522

523+
#ifdef CONFIG_SND_DEBUG
524+
static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size)
525+
{
526+
struct debugfs_blob_wrapper *wrapper;
527+
wrapper = devm_kzalloc(dcpaud->dev, sizeof(*wrapper), GFP_KERNEL);
528+
if (!wrapper)
529+
return;
530+
wrapper->data = base;
531+
wrapper->size = size;
532+
debugfs_create_blob(name, 0600, dcpaud->card->debugfs_root, wrapper);
533+
}
534+
#else
535+
static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) {}
536+
#endif
537+
497538
extern bool hdmi_audio;
498539

499540
static int dcpaud_init_snd_card(struct dcp_audio *dcpaud)
500541
{
501542
int ret;
502-
struct dma_chan *chan;
503-
504543
if (!hdmi_audio)
505544
return -ENODEV;
506545

507-
chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx");
508-
/* squelch dma channel request errors, the driver will try again alter */
509-
if (!chan) {
510-
dev_warn(dcpaud->dev, "audio TX DMA channel request failed\n");
511-
return 0;
512-
} else if (IS_ERR(chan)) {
513-
dev_warn(dcpaud->dev, "audio TX DMA channel request failed: %pE\n", chan);
514-
return 0;
515-
}
516-
dcpaud->chan = chan;
517546

518547
ret = snd_card_new(dcpaud->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
519548
THIS_MODULE, 0, &dcpaud->card);
@@ -546,35 +575,12 @@ static int dcpaud_init_snd_card(struct dcp_audio *dcpaud)
546575
return ret;
547576
}
548577

549-
#ifdef CONFIG_SND_DEBUG
550-
static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size)
551-
{
552-
struct debugfs_blob_wrapper *wrapper;
553-
wrapper = devm_kzalloc(dcpaud->dev, sizeof(*wrapper), GFP_KERNEL);
554-
if (!wrapper)
555-
return;
556-
wrapper->data = base;
557-
wrapper->size = size;
558-
debugfs_create_blob(name, 0600, dcpaud->card->debugfs_root, wrapper);
559-
}
560-
#else
561-
static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) {}
562-
#endif
563-
564578
void dcpaud_connect(struct platform_device *pdev, bool connected)
565579
{
566580
struct dcp_audio *dcpaud = platform_get_drvdata(pdev);
567581

568582
mutex_lock(&dcpaud->data_lock);
569583

570-
if (!dcpaud->chan) {
571-
int ret = dcpaud_init_snd_card(dcpaud);
572-
if (ret) {
573-
dcpaud->dcp_connected = connected;
574-
mutex_unlock(&dcpaud->data_lock);
575-
return;
576-
}
577-
}
578584
dcpaud_report_hotplug(dcpaud, connected);
579585
}
580586

@@ -641,14 +647,17 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data)
641647
dcpaud->dma_link = device_link_add(dev, dcpaud->dma_dev, DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE |
642648
DL_FLAG_STATELESS);
643649

644-
mutex_lock(&dcpaud->data_lock);
645650
/* ignore errors to prevent audio issues affecting the display side */
646-
dcpaud_init_snd_card(dcpaud);
647-
mutex_unlock(&dcpaud->data_lock);
651+
ret = dcpaud_init_snd_card(dcpaud);
648652

649-
ret = device_create_file(dev, &dev_attr_probe_snd_card);
650-
if (ret)
651-
dev_info(dev, "creating force probe sysfs file failed: %d\n", ret);
653+
if (!ret) {
654+
dcpaud_expose_debugfs_blob(dcpaud, "selected_cookie", &dcpaud->selected_cookie,
655+
sizeof(dcpaud->selected_cookie));
656+
dcpaud_expose_debugfs_blob(dcpaud, "elements", dcpaud->elements,
657+
DCPAUD_ELEMENTS_MAXSIZE);
658+
dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs,
659+
DCPAUD_PRODUCTATTRS_MAXSIZE);
660+
}
652661

653662
return 0;
654663
}

0 commit comments

Comments
 (0)