Foundry/barswap/k80_quirk/archive/k80_strap_quirk.c

79 lines
2.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-only OR AGPL-3.0-or-later
/*
* k80_strap_quirk.c — strap every K80/GK210 BAR1 to 256 MB BEFORE the kernel
* sizes its BARs, via a PCI early-fixup. This is the clean, every-boot version
* of the runtime PSTRAPS resize (kepler_compute_driver_spec.md §15): because the
* strap is written in pci_fixup_early — which runs immediately before
* pci_read_bases() probes the BAR sizes — the kernel sees 256 MB from the start,
* so it allocates BAR1 small AND sizes the PLX bridge windows correctly. That is
* what the post-boot userspace resize can't do (it can't resize a bridge window
* after the fact), and it's why ~2 dies were left unmountable.
*
* The strap field on GK210 is PSTRAPS (BAR0 + 0x101000) bits [15:14] (value 2 =
* 256 MB) with override-enable bit 31. We read BAR0 from config space (it is
* assigned by boot before fixups run), ioremap PSTRAPS, and write the field.
*
* Usage: insmod, then re-enumerate the GPU cards so the fixup fires:
* for each GPU PLX upstream bridge: echo 1 > .../remove ; echo 1 > /sys/bus/pci/rescan
* (or build into initramfs for boot-time; loadable fixups apply on rescans.)
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
#define GK210_VENDOR 0x10de
#define GK210_DEVICE 0x102d
#define PSTRAPS_OFFSET 0x101000u
#define BAR1_SHIFT 14
#define BAR1_MASK 0xfu
#define BAR1_VAL_256MB 2u
#define OVERRIDE_EN (1u << 31)
static void k80_strap_fixup(struct pci_dev *dev)
{
u32 bar0 = 0, v;
void __iomem *base;
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
bar0 &= PCI_BASE_ADDRESS_MEM_MASK; /* strip the low flag bits */
if (!bar0) {
dev_info(&dev->dev, "k80_strap: BAR0 unassigned, skipping\n");
return;
}
base = ioremap(bar0 + PSTRAPS_OFFSET, 8);
if (!base) {
dev_info(&dev->dev, "k80_strap: ioremap(0x%x) failed\n",
bar0 + PSTRAPS_OFFSET);
return;
}
v = readl(base);
v = (v & ~(BAR1_MASK << BAR1_SHIFT)) | (BAR1_VAL_256MB << BAR1_SHIFT) | OVERRIDE_EN;
writel(v, base);
(void)readl(base); /* post-write read barrier */
iounmap(base);
dev_info(&dev->dev,
"k80_strap: BAR1 -> 256MB (PSTRAPS=0x%08x via BAR0 0x%x)\n",
v, bar0);
}
DECLARE_PCI_FIXUP_EARLY(GK210_VENDOR, GK210_DEVICE, k80_strap_fixup);
static int __init k80q_init(void)
{
pr_info("k80_strap_quirk: loaded (pci_fixup_early for %04x:%04x)\n",
GK210_VENDOR, GK210_DEVICE);
return 0;
}
static void __exit k80q_exit(void)
{
pr_info("k80_strap_quirk: unloaded\n");
}
module_init(k80q_init);
module_exit(k80q_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Strap K80/GK210 BAR1 to 256MB in pci_fixup_early (before BAR sizing)");
MODULE_AUTHOR("Nex-N2");