Skip to content

Commit dd842f7

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 b636ac7 commit dd842f7

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)
@@ -444,10 +474,6 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
444474

445475
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops);
446476
dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
447-
snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM,
448-
dcpaud->chan->device->dev, 1024 * 1024,
449-
SIZE_MAX);
450-
451477
pcm->nonatomic = true;
452478
pcm->private_data = dcpaud;
453479
strscpy(pcm->name, card->shortname, sizeof(pcm->name));
@@ -496,26 +522,29 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud)
496522
strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname));
497523
}
498524

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

501542
static int dcpaud_init_snd_card(struct dcp_audio *dcpaud)
502543
{
503544
int ret;
504-
struct dma_chan *chan;
505-
506545
if (!hdmi_audio)
507546
return -ENODEV;
508547

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

520549
ret = snd_card_new(dcpaud->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
521550
THIS_MODULE, 0, &dcpaud->card);
@@ -548,35 +577,12 @@ static int dcpaud_init_snd_card(struct dcp_audio *dcpaud)
548577
return ret;
549578
}
550579

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

570584
mutex_lock(&dcpaud->data_lock);
571585

572-
if (!dcpaud->chan) {
573-
int ret = dcpaud_init_snd_card(dcpaud);
574-
if (ret) {
575-
dcpaud->dcp_connected = connected;
576-
mutex_unlock(&dcpaud->data_lock);
577-
return;
578-
}
579-
}
580586
dcpaud_report_hotplug(dcpaud, connected);
581587
}
582588

@@ -643,14 +649,17 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data)
643649
dcpaud->dma_link = device_link_add(dev, dcpaud->dma_dev, DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE |
644650
DL_FLAG_STATELESS);
645651

646-
mutex_lock(&dcpaud->data_lock);
647652
/* ignore errors to prevent audio issues affecting the display side */
648-
dcpaud_init_snd_card(dcpaud);
649-
mutex_unlock(&dcpaud->data_lock);
653+
ret = dcpaud_init_snd_card(dcpaud);
650654

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

655664
return 0;
656665
}

0 commit comments

Comments
 (0)