168 lines
5.9 KiB
C
168 lines
5.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only OR AGPL-3.0-or-later */
|
|
/* Copyright (C) 2026 David (Corey) Herrera */
|
|
/*
|
|
* bar1_probe.c — Kernel module to probe GK210 BAR1 minimum size
|
|
*
|
|
* Uses pci_read/write_config_dword() which works even when ECAM/CF8
|
|
* doesn't reach the device (bar_swap holds the pci_dev references).
|
|
*
|
|
* Usage:
|
|
* insmod bar1_probe.ko
|
|
* dmesg | grep bar1_probe
|
|
* rmmod bar1_probe
|
|
*
|
|
* Prerequisites: bar_swap.ko loaded, a die must be acquired first.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/init.h>
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("David (Corey) Herrera");
|
|
MODULE_DESCRIPTION("GK210 BAR1 size probe");
|
|
|
|
#define GK210_VENDOR 0x10de
|
|
#define GK210_DEVICE 0x102d
|
|
#define LOG "bar1_probe: "
|
|
|
|
static int __init bar1_probe_init(void)
|
|
{
|
|
struct pci_dev *dev = NULL;
|
|
int die_idx = 0;
|
|
|
|
pr_info(LOG "=== GK210 BAR1 Size Probe ===\n");
|
|
|
|
/* Find all GK210 dies */
|
|
while ((dev = pci_get_device(GK210_VENDOR, GK210_DEVICE, dev)) != NULL) {
|
|
u32 bar_vals[6];
|
|
u16 cmd_orig, cmd_disabled;
|
|
u32 lo_orig, hi_orig, lo_mask, hi_mask;
|
|
u64 full_mask, bar1_size;
|
|
int i;
|
|
|
|
pr_info(LOG "Die %d: %s\n", die_idx, pci_name(dev));
|
|
|
|
/* Read current BARs */
|
|
pr_info(LOG " Current BARs:\n");
|
|
for (i = 0; i < 6; i++) {
|
|
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, &bar_vals[i]);
|
|
pr_info(LOG " BAR%d (0x%02X): 0x%08X\n", i, 0x10 + i*4, bar_vals[i]);
|
|
}
|
|
|
|
/* Read CMD */
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd_orig);
|
|
pr_info(LOG " CMD: 0x%04X\n", cmd_orig);
|
|
|
|
/* Identify BAR layout:
|
|
* GK210: BAR0 = 32-bit non-pref (16 MB registers)
|
|
* BAR1+BAR2 = 64-bit pref (VRAM)
|
|
* BAR3+BAR4 = 64-bit pref (NV control)
|
|
* BAR5 = I/O (typically)
|
|
*/
|
|
|
|
/* Disable memory decode */
|
|
cmd_disabled = cmd_orig & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
|
|
pci_write_config_word(dev, PCI_COMMAND, cmd_disabled);
|
|
pr_info(LOG " Decode disabled (0x%04X -> 0x%04X)\n", cmd_orig, cmd_disabled);
|
|
|
|
/* Probe each BAR size */
|
|
pr_info(LOG " BAR size masks:\n");
|
|
for (i = 0; i < 6; i++) {
|
|
u32 orig, mask;
|
|
int off = PCI_BASE_ADDRESS_0 + i * 4;
|
|
|
|
pci_read_config_dword(dev, off, &orig);
|
|
pci_write_config_dword(dev, off, 0xFFFFFFFF);
|
|
pci_read_config_dword(dev, off, &mask);
|
|
pci_write_config_dword(dev, off, orig);
|
|
|
|
pr_info(LOG " BAR%d: orig=0x%08X mask=0x%08X\n", i, orig, mask);
|
|
}
|
|
|
|
/* Now specifically probe BAR1 (64-bit): offsets 0x14 + 0x18 */
|
|
pci_read_config_dword(dev, 0x14, &lo_orig);
|
|
pci_read_config_dword(dev, 0x18, &hi_orig);
|
|
|
|
pci_write_config_dword(dev, 0x14, 0xFFFFFFFF);
|
|
pci_write_config_dword(dev, 0x18, 0xFFFFFFFF);
|
|
pci_read_config_dword(dev, 0x14, &lo_mask);
|
|
pci_read_config_dword(dev, 0x18, &hi_mask);
|
|
pci_write_config_dword(dev, 0x14, lo_orig);
|
|
pci_write_config_dword(dev, 0x18, hi_orig);
|
|
|
|
pr_info(LOG " BAR1 (64-bit VRAM) probe:\n");
|
|
pr_info(LOG " Low orig=0x%08X mask=0x%08X\n", lo_orig, lo_mask);
|
|
pr_info(LOG " High orig=0x%08X mask=0x%08X\n", hi_orig, hi_mask);
|
|
|
|
full_mask = ((u64)hi_mask << 32) | ((u64)(lo_mask & 0xFFFFFFF0));
|
|
bar1_size = ~full_mask + 1;
|
|
|
|
pr_info(LOG " Full mask: 0x%016llX\n", full_mask);
|
|
pr_info(LOG " BAR1 size: 0x%llX (%llu GB)\n",
|
|
bar1_size, bar1_size >> 30);
|
|
|
|
if (bar1_size == 0x400000000ULL) {
|
|
pr_info(LOG " >>> HARDWIRED TO 16 GB — cannot resize <<<\n");
|
|
} else if (bar1_size > 0 && bar1_size < 0x400000000ULL) {
|
|
pr_info(LOG " >>> MINIMUM SIZE = %llu GB — RESIZABLE! <<<\n",
|
|
bar1_size >> 30);
|
|
} else {
|
|
pr_info(LOG " >>> UNEXPECTED SIZE — investigate <<<\n");
|
|
}
|
|
|
|
/* Also probe BAR0 (32-bit) and BAR3 (64-bit) for reference */
|
|
{
|
|
u32 b0_orig, b0_mask;
|
|
pci_read_config_dword(dev, 0x10, &b0_orig);
|
|
pci_write_config_dword(dev, 0x10, 0xFFFFFFFF);
|
|
pci_read_config_dword(dev, 0x10, &b0_mask);
|
|
pci_write_config_dword(dev, 0x10, b0_orig);
|
|
|
|
u32 b0_size_mask = b0_mask & 0xFFFFFFF0;
|
|
u32 b0_size = ~b0_size_mask + 1;
|
|
pr_info(LOG " BAR0 size: %u MB (mask=0x%08X)\n", b0_size >> 20, b0_mask);
|
|
}
|
|
|
|
{
|
|
u32 b3lo_orig, b3hi_orig, b3lo_mask, b3hi_mask;
|
|
pci_read_config_dword(dev, 0x1C, &b3lo_orig);
|
|
pci_read_config_dword(dev, 0x20, &b3hi_orig);
|
|
pci_write_config_dword(dev, 0x1C, 0xFFFFFFFF);
|
|
pci_write_config_dword(dev, 0x20, 0xFFFFFFFF);
|
|
pci_read_config_dword(dev, 0x1C, &b3lo_mask);
|
|
pci_read_config_dword(dev, 0x20, &b3hi_mask);
|
|
pci_write_config_dword(dev, 0x1C, b3lo_orig);
|
|
pci_write_config_dword(dev, 0x20, b3hi_orig);
|
|
|
|
u64 b3_full = ((u64)b3hi_mask << 32) | ((u64)(b3lo_mask & 0xFFFFFFF0));
|
|
u64 b3_size = ~b3_full + 1;
|
|
pr_info(LOG " BAR3 size: %llu MB (mask_lo=0x%08X mask_hi=0x%08X)\n",
|
|
b3_size >> 20, b3lo_mask, b3hi_mask);
|
|
}
|
|
|
|
/* Restore CMD */
|
|
pci_write_config_word(dev, PCI_COMMAND, cmd_orig);
|
|
pr_info(LOG " CMD restored to 0x%04X\n\n", cmd_orig);
|
|
|
|
die_idx++;
|
|
}
|
|
|
|
if (die_idx == 0)
|
|
pr_info(LOG "No GK210 devices found\n");
|
|
else
|
|
pr_info(LOG "Probed %d dies total\n", die_idx);
|
|
|
|
/* Module doesn't need to stay loaded */
|
|
return -ENODEV; /* Force unload after printing results */
|
|
}
|
|
|
|
static void __exit bar1_probe_exit(void)
|
|
{
|
|
pr_info(LOG "unloaded\n");
|
|
}
|
|
|
|
module_init(bar1_probe_init);
|
|
module_exit(bar1_probe_exit);
|