From: sashiko-bot@kernel.org
To: "James Calligeros" <jcalligeros99@gmail.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v3 08/21] ASoC: apple: Add macaudio machine driver
Date: Sun, 18 Oct 2026 06:23:12 +0000 [thread overview]
Message-ID: <sashiko-outbox-175986@kernel.org> (raw)
In-Reply-To: <20261018-macaudio-v3-8-abdff7741dea@gmail.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] ASoC: apple: macaudio: wrong drvdata and teardown order in remove()
- [High] ASoC: apple: macaudio: ABBA deadlock in macaudio_vlimit_update()
- [High] ASoC: apple: macaudio: static macaudio_card mutated across probes
- [High] ASoC: apple: macaudio: atomic Primary FE fails with nonatomic speaker BE
- [Medium] ASoC: apple: macaudio: OF node reference leaks in macaudio_parse_of()
- [Medium] ASoC: apple: macaudio: TDM idle mode skipped in macaudio_be_assign_tdm()
- [Medium] ASoC: apple: macaudio: race with cancel_delayed_work() on timeout work
--
commit 56eeabc9bf8ef8e9b2a3eb1ec213300f3ed1ab23
Author: Martin Povišer <povik+lin@cutebit.org>
ASoC: apple: Add macaudio machine driver
This commit adds an ASoC machine driver for Apple Silicon Macs to manage
DPCM routing between MCA I2S frontends/backends, speaker arrays, speaker
sense capture, and headset jack codecs.
> diff --git a/sound/soc/apple/macaudio.c b/sound/soc/apple/macaudio.c
> new file mode 100644
> index 0000000000000..b8e58c9a676f8
> --- /dev/null
> +++ b/sound/soc/apple/macaudio.c
> @@ -0,0 +1,1715 @@
[ ... ]
> +static struct snd_soc_dai_link macaudio_fe_links[] = {
> + {
> + .name = "Primary",
> + .stream_name = "Primary",
> + .dynamic = 1,
> + .dpcm_merged_rate = 1,
> + .dpcm_merged_chan = 1,
> + .dpcm_merged_format = 1,
> + .dai_fmt = MACAUDIO_DAI_FMT,
> + SND_SOC_DAILINK_REG(primary),
> + },
> + {
> + .name = "Secondary",
> + .stream_name = "Secondary",
> + .dynamic = 1,
> + .dpcm_merged_rate = 1,
> + .dpcm_merged_chan = 1,
> + .dpcm_merged_format = 1,
> + .dai_fmt = MACAUDIO_DAI_FMT,
> + .playback_only = 1,
> + .nonatomic = 1,
> + SND_SOC_DAILINK_REG(secondary),
> + },
[Severity: High]
Should the Primary frontend link in macaudio_fe_links[] (and the headphone
backend links in macaudio_parse_of()) also set .nonatomic = 1?
In macaudio_dapm_routes[], both Primary and Secondary are routed to both
Speaker Playback Mux (where Primary is the default selection at index 0)
and Headphone Playback Mux. In macaudio_parse_of(), speaker backend links
set link->nonatomic = 1, while headphone backend links have
link->nonatomic = 0.
When Primary (atomic) is routed to a speaker backend (nonatomic),
dpcm_be_connect() in sound/soc/soc-pcm.c rejects the connection with
-EINVAL because an atomic frontend cannot connect to a nonatomic backend:
sound/soc/soc-pcm.c:dpcm_be_connect() {
...
if (be_substream->pcm->nonatomic && !fe_substream->pcm->nonatomic) {
dev_err(be->dev, "FE is atomic but BE is nonatomic, invalid configuration\n");
return -EINVAL;
}
if (!be_substream->pcm->nonatomic && fe_substream->pcm->nonatomic) {
be_substream->pcm->nonatomic = 1;
}
...
}
Furthermore, if Secondary (nonatomic) is ever routed to Headphone Playback
Mux, dpcm_be_connect() mutates the headphone backend PCM to nonatomic = 1,
causing subsequent attempts to route Primary to headphones to also fail
with -EINVAL.
[ ... ]
> +static void macaudio_vlimit_update(struct macaudio_snd_data *ma, bool take_rwsem)
> +{
> + bool unlock = true;
> + const char *reason;
> +
> + /* Do nothing if there is no safety configured */
> + if (!ma->has_safety)
> + return;
> +
> + /* Check that the control has been pinged within the timeout */
> + if (ma->speaker_lock_remain <= 0) {
> + reason = "Lock timeout";
> + unlock = false;
> + }
> +
> + /*
> + * If this has been called from either of the safety interlock
> + * workqueues, the core API has not taken controls_rwsem for us.
> + * Take the write semaphore since macaudio_vlimit_unlock writes
> + * to the kcontrols.
> + */
> + if (take_rwsem)
> + down_write(&ma->card->snd_card->controls_rwsem);
[Severity: High]
Can taking controls_rwsem here while holding ma->volume_lock_mutex cause an
AB-BA deadlock with macaudio_slk_put()?
When lock_update_work or lock_timeout_work runs,
macaudio_vlimit_enable_timeout(), macaudio_vlimit_disable_timeout(), and
macaudio_vlimit_timeout_work() first acquire ma->volume_lock_mutex via
guard(mutex)(&ma->volume_lock_mutex) and then call
macaudio_vlimit_update(ma, true), which calls
down_write(&ma->card->snd_card->controls_rwsem):
volume_lock_mutex -> controls_rwsem
Conversely, when userspace writes to the Speaker Volume Unlock control,
snd_ctl_elem_write() in sound/core/control.c acquires
down_write(&card->controls_rwsem) before invoking macaudio_slk_put(), which
then acquires guard(mutex)(&ma->volume_lock_mutex):
controls_rwsem -> volume_lock_mutex
If a userspace control write races with either work item, will the two
threads deadlock against each other?
> +
> + if (unlock != ma->speaker_volume_unlocked) {
> + if (unlock) {
> + dev_info(ma->card->dev, "Speaker volumes unlocked\n");
> + } else {
> + dev_info(ma->card->dev, "Speaker volumes locked: %s\n", reason);
> + ma->speaker_volume_was_locked = true;
> + }
> +
> + macaudio_vlimit_unlock(ma, unlock);
> + ma->speaker_volume_unlocked = unlock;
> + snd_ctl_notify(ma->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
> + &ma->speaker_lock_kctl->id);
> + }
> +
> + if (take_rwsem)
> + up_write(&ma->card->snd_card->controls_rwsem);
> +}
> +
> +static void macaudio_vlimit_enable_timeout(struct macaudio_snd_data *ma)
> +{
> + guard(mutex)(&ma->volume_lock_mutex);
> +
> + if (ma->speaker_lock_timeout_enabled) {
> + return;
> + }
> +
> + if (ma->speaker_lock_remain > 0) {
> + ma->speaker_lock_timeout = ktime_add(ktime_get(), ma->speaker_lock_remain);
> + schedule_delayed_work(&ma->lock_timeout_work,
> + usecs_to_jiffies(ktime_to_us(ma->speaker_lock_remain)));
> + dev_dbg(ma->card->dev, "Enabling volume limit timeout: %ld us left\n",
> + (long)ktime_to_us(ma->speaker_lock_remain));
> + }
> +
> + macaudio_vlimit_update(ma, true);
> +
> + ma->speaker_lock_timeout_enabled = true;
> +}
> +
> +static void macaudio_vlimit_disable_timeout(struct macaudio_snd_data *ma)
> +{
> + ktime_t now;
> +
> + guard(mutex)(&ma->volume_lock_mutex);
> +
> + if (!ma->speaker_lock_timeout_enabled) {
> + return;
> + }
> +
> + now = ktime_get();
> +
> + cancel_delayed_work(&ma->lock_timeout_work);
> +
> + if (ktime_after(now, ma->speaker_lock_timeout))
> + ma->speaker_lock_remain = 0;
> + else if (ma->speaker_lock_remain > 0)
> + ma->speaker_lock_remain = ktime_sub(ma->speaker_lock_timeout, now);
> +
> + dev_dbg(ma->card->dev, "Disabling volume limit timeout: %ld us left\n",
> + (long)ktime_to_us(ma->speaker_lock_remain));
> +
> + macaudio_vlimit_update(ma, true);
> +
> + ma->speaker_lock_timeout_enabled = false;
> +}
> +
> +static void macaudio_vlimit_timeout_work(struct work_struct *wrk)
> +{
> + struct macaudio_snd_data *ma = container_of(to_delayed_work(wrk),
> + struct macaudio_snd_data, lock_timeout_work);
> +
> + guard(mutex)(&ma->volume_lock_mutex);
> + ma->speaker_lock_remain = 0;
> + macaudio_vlimit_update(ma, true);
> +}
[Severity: Medium]
What happens if lock_timeout_work fires and macaudio_vlimit_timeout_work()
blocks on ma->volume_lock_mutex just after macaudio_slk_put() or
macaudio_vlimit_disable_timeout() acquires ma->volume_lock_mutex?
Because macaudio_slk_put() and macaudio_vlimit_disable_timeout() use
non-synchronous cancel_delayed_work(&ma->lock_timeout_work) while holding
ma->volume_lock_mutex, cancel_delayed_work() cannot stop a
macaudio_vlimit_timeout_work() instance that has already been dispatched
and is waiting on ma->volume_lock_mutex.
Once macaudio_slk_put() refreshes ma->speaker_lock_remain to
ms_to_ktime(SPEAKER_LOCK_TIMEOUT), reschedules lock_timeout_work, and
releases ma->volume_lock_mutex (or macaudio_vlimit_disable_timeout()
disables the timeout and releases the mutex), the waiting
macaudio_vlimit_timeout_work() will acquire ma->volume_lock_mutex and
unconditionally zero ma->speaker_lock_remain and lock the speaker volumes.
Should macaudio_vlimit_timeout_work() verify that
ma->speaker_lock_timeout_enabled is still true and
ktime_after(ktime_get(), ma->speaker_lock_timeout) before zeroing
ma->speaker_lock_remain?
[ ... ]
> +static int macaudio_parse_of_component(struct device_node *node, int index,
> + struct snd_soc_dai_link_component *comp)
> +{
> + struct of_phandle_args args;
> + int ret;
> +
> + ret = of_parse_phandle_with_args(node, "sound-dai", "#sound-dai-cells",
> + index, &args);
> + if (ret)
> + return ret;
> + comp->of_node = args.np;
> + return snd_soc_get_dai_name(&args, &comp->dai_name);
> +}
[ ... ]
> +static int macaudio_parse_of(struct macaudio_snd_data *ma, struct snd_soc_card *card)
> +{
> + struct device_node *codec = NULL;
> + struct device_node *cpu = NULL;
> + struct device_node *np = NULL;
> + struct device_node *platform = NULL;
> + struct snd_soc_dai_link *link = NULL;
> + struct device *dev = card->dev;
> + struct macaudio_link_props *link_props;
> + int ret, num_links, i;
[ ... ]
> + for (be_index = 0; be_index < num_bes; be_index++) {
> + /*
> + * Set initial link name to be overwritten by a BE-specific
> + * name later so that we can use at least use the provisional
> + * name in error messages.
> + */
> + link->name = link_name;
> +
> + ret = macaudio_parse_of_be_dai_link(card, link, be_index,
> + ncodecs_per_cpu, cpu, codec);
> + if (ret)
> + goto err_free;
> +
> + link->nonatomic = link_props->is_speakers = speakers;
> + link_props->is_headphones = !speakers;
> +
> + link_props->codecs = devm_kcalloc(dev, ncodecs_per_cpu,
> + sizeof(struct ma_codec_idle), GFP_KERNEL);
> + if (!link_props->codecs)
> + return -ENOMEM;
[ ... ]
> + /* Steal platform OF reference for use in FE links later */
> + platform = link->cpus->of_node;
> +
> + link++; link_props++;
> + }
> +
> + of_node_put(codec);
> + of_node_put(cpu);
> + cpu = codec = NULL;
> +
> + num_links += num_bes;
> + }
[ ... ]
> +err_free:
> + of_node_put(codec);
> + of_node_put(cpu);
> + of_node_put(np);
> +
> + if (!card->dai_link)
> + return ret;
> +
> + for (i = 0; i < num_links; i++) {
> + /*
> + * TODO: If we don't go through this path are the references
> + * freed inside ASoC?
> + */
> + snd_soc_of_put_dai_link_codecs(&card->dai_link[i]);
> + snd_soc_of_put_dai_link_cpus(&card->dai_link[i]);
> + }
> +
> + return ret;
> +}
[Severity: Medium]
Does macaudio_parse_of() leak device_node references in several paths?
1. If devm_kcalloc() for link_props->codecs fails, macaudio_parse_of()
returns -ENOMEM directly from inside the for_each_available_child_of_node()
loop instead of jumping to err_free, leaking np, cpu, codec, and all
previously acquired DAI link component of_node references.
2. In macaudio_parse_of_component(), comp->of_node = args.np is assigned
before calling snd_soc_get_dai_name(&args, &comp->dai_name). In
macaudio_parse_of(), num_links is only incremented by num_bes after the
entire inner for (be_index = 0; be_index < num_bes; be_index++) loop
completes. If macaudio_parse_of_be_dai_link() fails (for example when
snd_soc_get_dai_name() returns -EPROBE_DEFER), execution jumps to err_free,
where the cleanup loop only iterates up to num_links and misses any
comp->of_node references already populated in the current child node's BE
links.
3. Regarding the TODO comment in err_free: ASoC core does not release
dai_link->codecs[].of_node or dai_link->cpus[].of_node. If
devm_snd_soc_register_card() fails or when the driver is removed, those
device_node references are never released.
[ ... ]
> +static int macaudio_be_assign_tdm(struct snd_soc_pcm_runtime *rtd)
> +{
> + struct snd_soc_card *card = rtd->card;
> + struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
> + struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
> + struct snd_soc_dai *dai;
> + unsigned int mask;
> + int nslots, ret, i;
> +
> + if (!props->tdm_mask)
> + return 0;
> +
> + mask = props->tdm_mask;
> + nslots = __fls(mask) + 1;
> +
> + if (rtd->dai_link->num_codecs == 1) {
> + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), mask,
> + 0, nslots, MACAUDIO_SLOTWIDTH);
> +
> + /*
> + * Headphones get a pass on -ENOTSUPP (see the comment
> + * around bclk_ratio value for primary FE).
> + */
> + if (ret == -ENOTSUPP && props->is_headphones)
> + return 0;
> +
> + return ret;
> + }
> +
> + for_each_rtd_codec_dais(rtd, i, dai) {
> + int slot = __ffs(mask);
> +
> + mask &= ~(1 << slot);
> + ret = snd_soc_dai_set_tdm_slot(dai, 1 << slot, 0, nslots,
> + MACAUDIO_SLOTWIDTH);
> + if (ret)
> + return ret;
> +
> + if (props->codecs[i].idle_mode) {
> + ret = snd_soc_dai_set_tdm_idle(dai, props->codecs[i].idle_mask,
> + 0, props->codecs[i].idle_mode, 0);
> + if (ret) {
> + dev_err(card->dev, "Failed to set idle props for codec %d\n", i);
> + return ret;
> + }
> +
> + }
> + }
> +
> + return 0;
> +}
[Severity: Medium]
When rtd->dai_link->num_codecs == 1, macaudio_be_assign_tdm() returns early
after calling snd_soc_dai_set_tdm_slot() without checking
props->codecs[0].idle_mode or calling snd_soc_dai_set_tdm_idle().
On machines where each speaker backend DAI link has a single codec (such as
2 speaker codecs split across 2 CPU BEs), won't this skip applying the
dai-tdm-idle-mode-* and dai-tdm-slot-tx-idle-mask-* properties parsed by
macaudio_get_codec_idle_props()?
[ ... ]
> +static struct snd_soc_card macaudio_card = {
> + .owner = THIS_MODULE,
> + .driver_name = "macaudio",
> + .dapm_widgets = macaudio_snd_widgets,
> + .num_dapm_widgets = ARRAY_SIZE(macaudio_snd_widgets),
> + .dapm_routes = macaudio_dapm_routes,
> + .num_dapm_routes = ARRAY_SIZE(macaudio_dapm_routes),
> + .controls = macaudio_controls,
> + .num_controls = ARRAY_SIZE(macaudio_controls),
> + .probe = macaudio_probe,
> + .late_probe = macaudio_late_probe,
> + .component_chaining = true,
> + .fully_routed = true,
> + .fixup_controls = macaudio_fixup_controls,
> +};
[ ... ]
> +static int macaudio_snd_platform_probe(struct platform_device *pdev)
> +{
> + struct snd_soc_card *card;
> + struct macaudio_snd_data *data;
> + struct device *dev = &pdev->dev;
> + struct snd_soc_dai_link *link;
> + const struct of_device_id *of_id;
> + int ret;
> + int i;
> +
> + of_id = of_match_device(macaudio_snd_device_id, dev);
> + if (!of_id)
> + return -EINVAL;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> + card = &macaudio_card;
> + data->card = card;
> +
> + snd_soc_card_set_drvdata(card, data);
> + dev_set_drvdata(&pdev->dev, data);
> + mutex_init(&data->volume_lock_mutex);
> + mutex_init(&data->be_link_mutex);
> +
> + card->dev = dev;
> +
> + if (of_id->data)
> + data->cfg = of_id->data;
> + else
> + data->cfg = &macaudio_fallback_cfg;
> +
> + ret = macaudio_parse_of(data, card);
> + if (ret)
> + return ret;
> +
> + /* Remove useless controls */
> + if (!data->has_speakers) /* No speakers, remove both */
> + card->num_controls -= MACAUDIO_NUM_SPEAKER_CONTROLS;
> + else if (!data->cfg->safe_vol) /* No safety, remove unlock */
> + card->num_controls -= MACAUDIO_NUM_SPEAKER_LIMIT_CONTROLS;
> + else /* Speakers with safety, mark us as such */
> + data->has_safety = true;
[Severity: High]
Since macaudio_card is a static struct shared across probe attempts, what
happens if devm_snd_soc_register_card() defers probe (-EPROBE_DEFER) or the
device is unbound and re-probed?
In macaudio_snd_platform_probe(), card->num_controls is decremented in-place
with -= without being reset to ARRAY_SIZE(macaudio_controls). Across
repeated deferred probes, card->num_controls will be decremented multiple
times, dropping valid controls or underflowing. For example, on a machine
with speakers and !safe_vol, a second probe attempt will drop the Speaker
Sample Rate control, causing snd_soc_card_get_kcontrol(card, "Speaker Sample
Rate") in macaudio_late_probe() to return NULL and triggering a NULL pointer
dereference when macaudio_dpcm_hw_params() or macaudio_be_hw_free() accesses
&ma->speaker_sample_rate_kctl->id.
Similarly, macaudio_parse_of() assigns a devm-allocated array to
macaudio_card.dai_link; if probe fails after that allocation, devres frees
the array while leaving macaudio_card.dai_link pointing to freed memory if a
subsequent probe jumps to err_free before reallocating card->dai_link.
Embedding struct snd_soc_card inside struct macaudio_snd_data (and
initializing it from a const template on probe) would avoid mutating global
state across probes.
> +
> + for_each_card_prelinks(card, i, link) {
> + if (link->no_pcm) {
> + link->ops = &macaudio_be_ops;
> + link->init = macaudio_be_init;
> + link->exit = macaudio_be_exit;
> + } else {
> + link->ops = &macaudio_fe_ops;
> + link->init = macaudio_fe_init;
> + }
> + }
> +
> + INIT_WORK(&data->lock_update_work, macaudio_vlimit_update_work);
> + INIT_DELAYED_WORK(&data->lock_timeout_work, macaudio_vlimit_timeout_work);
> +
> + return devm_snd_soc_register_card(dev, card);
> +}
> +
> +static void macaudio_snd_platform_remove(struct platform_device *pdev)
> +{
> + struct macaudio_snd_data *ma = dev_get_drvdata(&pdev->dev);
> +
> + cancel_work_sync(&ma->lock_update_work);
> + cancel_delayed_work_sync(&ma->lock_timeout_work);
> +}
[Severity: Critical]
Does macaudio_snd_platform_remove() retrieve the wrong pointer from
dev_get_drvdata(&pdev->dev) and cancel the work items in the wrong order
relative to card unregistration?
1. In macaudio_snd_platform_probe(), dev_set_drvdata(&pdev->dev, data) sets
the platform device's drvdata to struct macaudio_snd_data *data, and then
calls devm_snd_soc_register_card(dev, card). Inside snd_soc_register_card()
in sound/soc/soc-core.c, ASoC unconditionally overwrites card->dev's drvdata
with card:
sound/soc/soc-core.c:snd_soc_register_card() {
...
dev_set_drvdata(card->dev, card);
...
}
When macaudio_snd_platform_remove() later calls dev_get_drvdata(&pdev->dev),
it receives struct snd_soc_card * (instead of struct macaudio_snd_data *)
and passes offsets inside macaudio_card to cancel_work_sync() and
cancel_delayed_work_sync().
2. Because the card is registered with devm_snd_soc_register_card(), the
devres release callback that unregisters the card runs after
macaudio_snd_platform_remove() returns. While the card is still registered
(and during PCM teardown in snd_soc_unregister_card()), macaudio_be_trigger()
or macaudio_slk_put() can schedule lock_update_work and lock_timeout_work
again after macaudio_snd_platform_remove() has completed, leading to
use-after-free when devres frees struct macaudio_snd_data.
|}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261018-macaudio-v3-0-abdff7741dea@gmail.com?part=8
next prev parent reply other threads:[~2026-10-18 6:23 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-18 5:53 [PATCH v3 00/21] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
2026-10-18 5:53 ` [PATCH v3 01/21] ASoC: dt-bindings: cs42l84: Document sound-name-prefix property James Calligeros
2026-10-18 5:53 ` [PATCH v3 02/21] ASoC: dt-bindings: cs42l42: Document additional dai-common properties James Calligeros
2026-10-18 6:04 ` sashiko-bot
2026-10-18 5:53 ` [PATCH v3 03/21] ASoC: dt-bindings: Add binding for Apple Silicon Mac audio James Calligeros
2026-10-18 6:07 ` sashiko-bot
2026-10-18 5:53 ` [PATCH v3 04/21] ASoC: ops: Introduce 'snd_soc_ctl_activate' James Calligeros
2026-10-18 5:53 ` [PATCH v3 05/21] ASoC: ops: Introduce 'soc_set_enum_kctl' James Calligeros
2026-10-18 5:54 ` [PATCH v3 06/21] ASoC: card: Let 'fixup_controls' return errors James Calligeros
2026-10-18 5:54 ` [PATCH v3 07/21] ASoC: tas2770: Add compatible for TAS5770L James Calligeros
2026-10-18 5:54 ` [PATCH v3 08/21] ASoC: apple: Add macaudio machine driver James Calligeros
2026-10-18 6:23 ` sashiko-bot [this message]
2026-10-18 5:54 ` [PATCH v3 09/21] arm64: dts: apple: t8103-jxxx: Add regulators for CS42L83 power supply James Calligeros
2026-10-18 6:04 ` sashiko-bot
2026-10-18 5:54 ` [PATCH v3 10/21] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes James Calligeros
2026-10-18 6:10 ` sashiko-bot
2026-10-18 5:54 ` [PATCH v3 11/21] arm64: dts: apple: t8103-j313: " James Calligeros
2026-10-18 6:15 ` sashiko-bot
2026-10-18 5:54 ` [PATCH v3 12/21] arm64: dts: apple: t8103-j293: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 13/21] arm64: dts: apple: t8103-j45x: Add headset " James Calligeros
2026-10-18 5:54 ` [PATCH v3 14/21] arm64: dts: apple: t8112-j413: Add speaker/headset " James Calligeros
2026-10-18 5:54 ` [PATCH v3 15/21] arm64: dts: apple: t8112-j415: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 16/21] arm64: dts: apple: t8112-j473: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 17/21] arm64: dts: apple: t8112-j493: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 18/21] arm64: dts: apple: t600x-j31x: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 19/21] arm64: dts: apple: t600x-j375: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 20/21] arm64: dts: apple: t602x-j41x: " James Calligeros
2026-10-18 5:54 ` [PATCH v3 21/21] arm64: dts: apple: t602x-j47x: " James Calligeros
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-175986@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=jcalligeros99@gmail.com \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox