Reviewed-by: Lyude Paul <[email protected]>
On Sun, 2026-08-16 at 15:09 +0200, Marek Czernohous wrote:
> From: Marek Czernohous <[email protected]>
>
> NVAC (MCP79/MCP7A) uses g94_pci_func, whose .msi_rearm is
> nv40_pci_msi_rearm(): a re-arm write through the MMIO mirror of PCI
> config space. On this IGP that path is unreliable; when a re-arm is
> missed the interrupt line stays dead, command submission times out
> and
> the GPU appears hung until reboot. On an Apple Mac mini (early 2009,
> MCP79, boot0 0x0ac080b1) this showed as sporadic fifo timeouts and
> GPU
> hangs under load unless MSI was disabled via config=NvMSI=0.
>
> Give NVAC its own pci func that re-arms through real PCI config space
> (nv46_pci_msi_rearm) instead. This follows existing precedent:
> nv46.c
> documents the MMIO-mirror re-arm as broken on several related parts,
> and commit 5112abc6a433 ("drm/nouveau/pci/g92: Fix rearm") fixed g92
> the same way while moving the remaining chipsets, NVAC included, into
> the newly added shared g94 table, where NVAC stayed on the MMIO path.
> This change completes that fix for NVAC. The sibling IGP NVAA
> (MCP77/MCP78) has MSI disabled entirely as "reported broken" in
> nvkm_pci_new_(); NVAC works correctly once the re-arm goes through
> config space, so disabling MSI is not necessary.
>
> Only NVAC is switched: that is the hardware this has been validated
> on. The other users of g94_pci_func (G94/G96/G98/GT2xx and the
> MCP77/MCP89 IGPs) keep their current behavior; MCP77 and MCP89
> plausibly want the same treatment but were not tested.
>
> Tested on the Mac mini as a daily driver for two months with MSI
> enabled and zero fifo timeouts. Independently confirmed stable on an
> iMac9,1 (MCP79) running 6.12.90 with the v1 form of this change (the
> same one-line functional switch, applied to that kernel's g94
> implementation).
>
> Fixes: 5112abc6a433 ("drm/nouveau/pci/g92: Fix rearm")
> Cc: <[email protected]> # v6.16+
> Tested-by: Fab Stz <[email protected]>
> Assisted-by: Claude:claude-opus-4-7
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Marek Czernohous <[email protected]>
> ---
> .../gpu/drm/nouveau/include/nvkm/subdev/pci.h | 1 +
> .../gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +-
> .../gpu/drm/nouveau/nvkm/subdev/pci/Kbuild | 1 +
> .../gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c | 35
> +++++++++++++++++++
> 4 files changed, 38 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c
>
> diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
> b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
> index 112b674ed9c8..0172e0d200f8 100644
> --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
> +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
> @@ -46,6 +46,7 @@ int nv4c_pci_new(struct nvkm_device *, enum
> nvkm_subdev_type, int inst, struct n
> int g84_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> int g92_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> int g94_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> +int mcp79_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> int gf100_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> int gf106_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> int gk104_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int
> inst, struct nvkm_pci **);
> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> index ea62dc97f118..f7e02a16e5bc 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> @@ -1237,7 +1237,7 @@ nvac_chipset = {
> .mc = { 0x00000001, g98_mc_new },
> .mmu = { 0x00000001, mcp77_mmu_new },
> .mxm = { 0x00000001, nv50_mxm_new },
> - .pci = { 0x00000001, g94_pci_new },
> + .pci = { 0x00000001, mcp79_pci_new },
> .therm = { 0x00000001, g84_therm_new },
> .timer = { 0x00000001, nv41_timer_new },
> .volt = { 0x00000001, nv40_volt_new },
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
> b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
> index a14ea0f7b1c8..90f03baeb22a 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
> @@ -9,6 +9,7 @@ nvkm-y += nvkm/subdev/pci/nv4c.o
> nvkm-y += nvkm/subdev/pci/g84.o
> nvkm-y += nvkm/subdev/pci/g92.o
> nvkm-y += nvkm/subdev/pci/g94.o
> +nvkm-y += nvkm/subdev/pci/mcp79.o
> nvkm-y += nvkm/subdev/pci/gf100.o
> nvkm-y += nvkm/subdev/pci/gf106.o
> nvkm-y += nvkm/subdev/pci/gk104.o
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c
> b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c
> new file mode 100644
> index 000000000000..e2ae242f1aa7
> --- /dev/null
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c
> @@ -0,0 +1,35 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright 2026 Marek Czernohous
> + *
> + * MCP79/MCP7A (NVAC): like g94, but MSI re-arm goes through real
> PCI
> + * config space. The MMIO-mirror re-arm is unreliable on this IGP
> and a
> + * missed re-arm kills the interrupt line (see the nv46 comment; g92
> + * already re-arms through config space for the same reason).
> + */
> +#include "priv.h"
> +
> +static const struct nvkm_pci_func
> +mcp79_pci_func = {
> + .cfg = { .addr = 0x088000, .size = 0x1000 },
> +
> + .init = g84_pci_init,
> + .msi_rearm = nv46_pci_msi_rearm,
> +
> + .pcie.init = g84_pcie_init,
> + .pcie.set_link = g84_pcie_set_link,
> +
> + .pcie.max_speed = g84_pcie_max_speed,
> + .pcie.cur_speed = g84_pcie_cur_speed,
> +
> + .pcie.set_version = g84_pcie_set_version,
> + .pcie.version = g84_pcie_version,
> + .pcie.version_supported = g92_pcie_version_supported,
> +};
> +
> +int
> +mcp79_pci_new(struct nvkm_device *device, enum nvkm_subdev_type
> type, int inst,
> + struct nvkm_pci **ppci)
> +{
> + return nvkm_pci_new_(&mcp79_pci_func, device, type, inst,
> ppci);
> +}