Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions drivers/gpu/drm/apple/afk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,7 @@ int afk_service_call_timeout(struct apple_epic_service *service, u16 group,
if (!service)
return -ENODEV;

bfr = kzalloc(bfr_len, GFP_KERNEL);
bfr = kvzalloc(bfr_len, GFP_KERNEL);
if (!bfr)
return -ENOMEM;

Expand Down Expand Up @@ -1249,7 +1249,7 @@ int afk_service_call_timeout(struct apple_epic_service *service, u16 group,
}

out:
kfree(bfr);
kvfree(bfr);
return ret;
}

Expand Down
62 changes: 56 additions & 6 deletions drivers/gpu/drm/apple/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
Expand All @@ -30,7 +32,11 @@
#include "audio.h"
#include "parser.h"

#define DCPAUD_ELEMENTS_MAXSIZE 16384
/*
* As macOS 13 asks for. Elements that do not fit come back cut off at the
* buffer's end, with a used size of 0.
*/
#define DCPAUD_ELEMENTS_MAXSIZE SZ_256K
#define DCPAUD_PRODUCTATTRS_MAXSIZE 1024

struct dcp_audio {
Expand All @@ -52,6 +58,8 @@ struct dcp_audio {

struct snd_pcm_chmap_elem selected_chmap;
struct dcp_sound_cookie selected_cookie;
/* the stream holds a runtime PM reference, put in sync_stop */
bool pm_held;
void *elements;
void *productattrs;

Expand Down Expand Up @@ -418,7 +426,10 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (!dcpaud_connection_up(dcpaud))
return -ENXIO;

WARN_ON(pm_runtime_get_sync(dcpaud->dev) < 0);
if (!dcpaud->pm_held) {
WARN_ON(pm_runtime_get_sync(dcpaud->dev) < 0);
dcpaud->pm_held = true;
}
ret = dcp_audiosrv_startlink(dcpaud->dcp_dev,
&dcpaud->selected_cookie);
if (ret < 0)
Expand All @@ -444,9 +455,8 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)

case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
/* the runtime PM reference goes in sync_stop */
ret = dcp_audiosrv_stoplink(dcpaud->dcp_dev);
pm_runtime_mark_last_busy(dcpaud->dev);
__pm_runtime_put_autosuspend(dcpaud->dev);
if (ret < 0)
return ret;
break;
Expand All @@ -455,13 +465,44 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}

/*
* ALSA calls this once a stream has stopped (STOP, SUSPEND, or the STOP
* that undoes a failed START), before the next hw_params, prepare or
* hw_free, at close, at system suspend and at disconnect, outside the
* stream lock. The DMA terminate is asynchronous: putting the runtime PM
* reference in trigger STOP powered the DPA's domain (ps_dpa*) down while
* SIO still ran DMA towards it, and SIO crashed ("Shim DMA unavailable",
* the TERMINATE timing out after it). Wait for the terminate first.
*/
static int dcp_pcm_sync_stop(struct snd_pcm_substream *substream)
{
struct dcp_audio *dcpaud = substream->pcm->private_data;
bool held;

snd_dmaengine_pcm_sync_stop(substream);

/* START sets it under the stream lock */
snd_pcm_stream_lock_irq(substream);
held = dcpaud->pm_held;
dcpaud->pm_held = false;
snd_pcm_stream_unlock_irq(substream);

if (held) {
pm_runtime_mark_last_busy(dcpaud->dev);
__pm_runtime_put_autosuspend(dcpaud->dev);
}

return 0;
}

struct snd_pcm_ops dcp_playback_ops = {
.open = dcp_pcm_open,
.close = dcp_pcm_close,
.hw_params = dcp_pcm_hw_params,
.hw_free = dcp_pcm_hw_free,
.prepare = dcp_pcm_prepare,
.trigger = dcp_pcm_trigger,
.sync_stop = dcp_pcm_sync_stop,
.pointer = snd_dmaengine_pcm_pointer,
};

Expand Down Expand Up @@ -736,18 +777,27 @@ static const struct component_ops dcpaud_comp_ops = {
.unbind = dcpaud_comp_unbind,
};

static void dcpaud_free_elements(void *elements)
{
kvfree(elements);
}

static int dcpaud_probe(struct platform_device *pdev)
{
struct dcp_audio *dcpaud;
int ret;

dcpaud = devm_kzalloc(&pdev->dev, sizeof(*dcpaud), GFP_KERNEL);
if (!dcpaud)
return -ENOMEM;

dcpaud->elements = devm_kzalloc(&pdev->dev, DCPAUD_ELEMENTS_MAXSIZE,
GFP_KERNEL);
dcpaud->elements = kvzalloc(DCPAUD_ELEMENTS_MAXSIZE, GFP_KERNEL);
if (!dcpaud->elements)
return -ENOMEM;
ret = devm_add_action_or_reset(&pdev->dev, dcpaud_free_elements,
dcpaud->elements);
if (ret)
return ret;

dcpaud->productattrs = devm_kzalloc(&pdev->dev, DCPAUD_PRODUCTATTRS_MAXSIZE,
GFP_KERNEL);
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/apple/av.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,10 @@ dcp_audiosrv_osobject_call(struct apple_epic_service *service, u16 group,
} __attribute__((packed)) *hdr;
static_assert(sizeof(*hdr) == 48);
size_t bfr_len = output_maxsize + sizeof(*hdr);
void *bfr __free(kfree) = NULL;
void *bfr __free(kvfree) = NULL;
int ret;

bfr = kzalloc(bfr_len, GFP_KERNEL);
bfr = kvzalloc(bfr_len, GFP_KERNEL);
if (!bfr)
return -ENOMEM;

Expand Down