#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <vm/vm.h>
#include <bus/pci/pci_cfgreg.h>
#include <machine/md_var.h>
#include <bus/pci/pcivar.h>
#include <bus/pci/pcireg.h>
#include <bus/pci/x86_64/pci_early_quirks.h>
#define MiB(v) ((unsigned long)(v) << 20)
struct pci_device_id {
uint32_t vendor;
uint32_t device;
const struct intel_stolen_ops *data;
};
vm_paddr_t intel_graphics_stolen_base = 0;
vm_paddr_t intel_graphics_stolen_size = 0;
SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_base, CTLFLAG_RD,
&intel_graphics_stolen_base, 0,
"Base address of the intel graphics stolen memory.");
SYSCTL_U64(_hw, OID_AUTO, intel_graphics_stolen_size, CTLFLAG_RD,
&intel_graphics_stolen_size, 0,
"Size of the intel graphics stolen memory.");
static vm_paddr_t
intel_stolen_base_gen3(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(bus, slot, func, INTEL_BSM, 4);
val = ctrl & INTEL_BSM_MASK;
return (val);
}
static vm_paddr_t
intel_stolen_base_gen11(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(bus, slot, func, INTEL_GEN11_BSM_DW0, 4);
val = ctrl & INTEL_BSM_MASK;
val |= (uint64_t)pci_cfgregread(
bus, slot, func, INTEL_GEN11_BSM_DW1, 4) << 32;
return (val);
}
static vm_paddr_t
intel_stolen_size_gen3(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(0, 0, 0, I830_GMCH_CTRL, 2);
val = ctrl & I855_GMCH_GMS_MASK;
switch (val) {
case I855_GMCH_GMS_STOLEN_1M:
return (MiB(1));
case I855_GMCH_GMS_STOLEN_4M:
return (MiB(4));
case I855_GMCH_GMS_STOLEN_8M:
return (MiB(8));
case I855_GMCH_GMS_STOLEN_16M:
return (MiB(16));
case I855_GMCH_GMS_STOLEN_32M:
return (MiB(32));
case I915_GMCH_GMS_STOLEN_48M:
return (MiB(48));
case I915_GMCH_GMS_STOLEN_64M:
return (MiB(64));
case G33_GMCH_GMS_STOLEN_128M:
return (MiB(128));
case G33_GMCH_GMS_STOLEN_256M:
return (MiB(256));
case INTEL_GMCH_GMS_STOLEN_96M:
return (MiB(96));
case INTEL_GMCH_GMS_STOLEN_160M:
return (MiB(160));
case INTEL_GMCH_GMS_STOLEN_224M:
return (MiB(224));
case INTEL_GMCH_GMS_STOLEN_352M:
return (MiB(352));
}
return (0);
}
static vm_paddr_t
intel_stolen_size_gen6(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2);
val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
return (val * MiB(32));
}
static vm_paddr_t
intel_stolen_size_gen8(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2);
val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
return (val * MiB(32));
}
static vm_paddr_t
intel_stolen_size_chv(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2);
val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
if (val < 0x11)
return (val * MiB(32));
else if (val < 0x17)
return ((val - 0x11) * MiB(4) + MiB(8));
else
return ((val - 0x17) * MiB(4) + MiB(36));
}
static vm_paddr_t
intel_stolen_size_gen9(int bus, int slot, int func)
{
uint32_t ctrl;
vm_paddr_t val;
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2);
val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
if (val < 0xF0)
return (val * MiB(32));
return ((val - 0xF0) * MiB(4) + MiB(4));
}
struct intel_stolen_ops {
vm_paddr_t (*base)(int bus, int slot, int func);
vm_paddr_t (*size)(int bus, int slot, int func);
};
static const struct intel_stolen_ops intel_stolen_ops_gen3 = {
.base = intel_stolen_base_gen3,
.size = intel_stolen_size_gen3,
};
static const struct intel_stolen_ops intel_stolen_ops_gen6 = {
.base = intel_stolen_base_gen3,
.size = intel_stolen_size_gen6,
};
static const struct intel_stolen_ops intel_stolen_ops_gen8 = {
.base = intel_stolen_base_gen3,
.size = intel_stolen_size_gen8,
};
static const struct intel_stolen_ops intel_stolen_ops_gen9 = {
.base = intel_stolen_base_gen3,
.size = intel_stolen_size_gen9,
};
static const struct intel_stolen_ops intel_stolen_ops_chv = {
.base = intel_stolen_base_gen3,
.size = intel_stolen_size_chv,
};
static const struct intel_stolen_ops intel_stolen_ops_gen11 = {
.base = intel_stolen_base_gen11,
.size = intel_stolen_size_gen9,
};
static const struct pci_device_id intel_ids[] = {
INTEL_I915G_IDS(&intel_stolen_ops_gen3),
INTEL_I915GM_IDS(&intel_stolen_ops_gen3),
INTEL_I945G_IDS(&intel_stolen_ops_gen3),
INTEL_I945GM_IDS(&intel_stolen_ops_gen3),
INTEL_VLV_IDS(&intel_stolen_ops_gen6),
INTEL_PINEVIEW_IDS(&intel_stolen_ops_gen3),
INTEL_I965G_IDS(&intel_stolen_ops_gen3),
INTEL_G33_IDS(&intel_stolen_ops_gen3),
INTEL_I965GM_IDS(&intel_stolen_ops_gen3),
INTEL_GM45_IDS(&intel_stolen_ops_gen3),
INTEL_G45_IDS(&intel_stolen_ops_gen3),
INTEL_IRONLAKE_D_IDS(&intel_stolen_ops_gen3),
INTEL_IRONLAKE_M_IDS(&intel_stolen_ops_gen3),
INTEL_SNB_D_IDS(&intel_stolen_ops_gen6),
INTEL_SNB_M_IDS(&intel_stolen_ops_gen6),
INTEL_IVB_M_IDS(&intel_stolen_ops_gen6),
INTEL_IVB_D_IDS(&intel_stolen_ops_gen6),
INTEL_HSW_IDS(&intel_stolen_ops_gen6),
INTEL_BDW_IDS(&intel_stolen_ops_gen8),
INTEL_CHV_IDS(&intel_stolen_ops_chv),
INTEL_SKL_IDS(&intel_stolen_ops_gen9),
INTEL_BXT_IDS(&intel_stolen_ops_gen9),
INTEL_KBL_IDS(&intel_stolen_ops_gen9),
INTEL_CFL_IDS(&intel_stolen_ops_gen9),
INTEL_GLK_IDS(&intel_stolen_ops_gen9),
INTEL_CNL_IDS(&intel_stolen_ops_gen9),
INTEL_ICL_11_IDS(&intel_stolen_ops_gen11),
INTEL_EHL_IDS(&intel_stolen_ops_gen11),
INTEL_JSL_IDS(&intel_stolen_ops_gen11),
INTEL_TGL_12_IDS(&intel_stolen_ops_gen11),
INTEL_RKL_IDS(&intel_stolen_ops_gen11),
INTEL_ADLS_IDS(&intel_stolen_ops_gen11),
INTEL_ADLP_IDS(&intel_stolen_ops_gen11),
INTEL_RPLS_IDS(&intel_stolen_ops_gen11),
};
static void
intel_graphics_stolen(void)
{
const struct intel_stolen_ops *ops;
uint32_t vendor, device, class;
int i;
const int bus = 0;
const int slot = 2;
const int func = 0;
if (pci_cfgregopen() == 0)
return;
vendor = pci_cfgregread(bus, slot, func, PCIR_VENDOR, 2);
if (vendor != PCI_VENDOR_INTEL)
return;
class = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 2);
if (class != PCI_CLASS_VGA)
return;
device = pci_cfgregread(bus, slot, func, PCIR_DEVICE, 2);
if (device == 0xFFFF)
return;
for (i = 0; i < nitems(intel_ids); i++) {
if (intel_ids[i].device != device)
continue;
ops = intel_ids[i].data;
intel_graphics_stolen_base = ops->base(bus, slot, func);
intel_graphics_stolen_size = ops->size(bus, slot, func);
break;
}
}
void
pci_early_quirks(void)
{
intel_graphics_stolen();
}