Changeset View
Standalone View
sys/dev/pci/pci_early_quirks.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2018 Johannes Lundberg | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
*/ | |||||
#include <sys/cdefs.h> | |||||
__FBSDID("$FreeBSD$"); | |||||
#include <sys/param.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/bus.h> | |||||
#include <sys/kernel.h> | |||||
#include <dev/pci/pcivar.h> | |||||
#include <dev/pci/pcireg.h> | |||||
#include <machine/pci_cfgreg.h> | |||||
#include <machine/physmem.h> | |||||
#include <vm/vm.h> | |||||
#include "pci_early_quirks.h" | |||||
#define MB (1024*1024) | |||||
kib: Look at sys/amd64/amd64/mp_machdep.c:87, where the GiB(x) macro is defined. I like this way… | |||||
struct pci_device_id { | |||||
uint32_t vendor; | |||||
uint32_t device; | |||||
uintptr_t data; | |||||
}; | |||||
Done Inline ActionsSee inline comment in the loop iterating over the array. kib: See inline comment in the loop iterating over the array. | |||||
Done Inline ActionsThe plan was to make a function that could be used for many other things, other than only stolen memory, similar to what Linux does. Hence the generic pointer. johalun0_gmail.com: The plan was to make a function that could be used for many other things, other than only… | |||||
#if defined(__amd64__) | |||||
/* | |||||
* These global variables are read by LinuxKPI. | |||||
* LinuxKPI provide this information to the i915 driver. | |||||
*/ | |||||
vm_paddr_t intel_graphics_stolen_base = 0; | |||||
vm_paddr_t intel_graphics_stolen_size = 0; | |||||
/* | |||||
* Intel early quirks functions | |||||
*/ | |||||
static vm_paddr_t | |||||
intel_stolen_base_gen3(int bus, int slot, int func) | |||||
{ | |||||
vm_paddr_t val; | |||||
val = pci_cfgregread(bus, slot, func, INTEL_BSM, 4); | |||||
return (val & INTEL_BSM_MASK); | |||||
Done Inline ActionsThis blank line is not needed. kib: This blank line is not needed. | |||||
} | |||||
static vm_paddr_t | |||||
intel_stolen_size_gen3(int bus, int slot, int func) | |||||
{ | |||||
uint16_t ctrl; | |||||
uint16_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 1 * MB; | |||||
case I855_GMCH_GMS_STOLEN_4M: | |||||
Not Done Inline Actionsreturn (); there and in all returns down. kib: return (); there and in all returns down. | |||||
return 4 * MB; | |||||
case I855_GMCH_GMS_STOLEN_8M: | |||||
return 8 * MB; | |||||
case I855_GMCH_GMS_STOLEN_16M: | |||||
return 16 * MB; | |||||
case I855_GMCH_GMS_STOLEN_32M: | |||||
return 32 * MB; | |||||
case I915_GMCH_GMS_STOLEN_48M: | |||||
return 48 * MB; | |||||
case I915_GMCH_GMS_STOLEN_64M: | |||||
return 64 * MB; | |||||
case G33_GMCH_GMS_STOLEN_128M: | |||||
return 128 * MB; | |||||
case G33_GMCH_GMS_STOLEN_256M: | |||||
return 256 * MB; | |||||
case INTEL_GMCH_GMS_STOLEN_96M: | |||||
return 96 * MB; | |||||
case INTEL_GMCH_GMS_STOLEN_160M: | |||||
return 160 * MB; | |||||
case INTEL_GMCH_GMS_STOLEN_224M: | |||||
return 224 * MB; | |||||
case INTEL_GMCH_GMS_STOLEN_352M: | |||||
return 352 * MB; | |||||
} | |||||
return 0; | |||||
} | |||||
static vm_paddr_t | |||||
intel_stolen_size_gen6(int bus, int slot, int func) | |||||
{ | |||||
uint16_t ctrl; | |||||
uint16_t val; | |||||
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); | |||||
val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; | |||||
return (val * 32 * MB); | |||||
Done Inline ActionsExtra blank line, there and in all functions down. kib: Extra blank line, there and in all functions down. | |||||
} | |||||
static vm_paddr_t | |||||
intel_stolen_size_gen8(int bus, int slot, int func) | |||||
{ | |||||
uint16_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 * 32 * MB); | |||||
} | |||||
static vm_paddr_t | |||||
intel_stolen_size_chv(int bus, int slot, int func) | |||||
{ | |||||
uint16_t ctrl; | |||||
uint16_t val; | |||||
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); | |||||
val = (ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK; | |||||
/* | |||||
* 0x0 to 0x10: 32MB increments starting at 0MB | |||||
* 0x11 to 0x16: 4MB increments starting at 8MB | |||||
* 0x17 to 0x1d: 4MB increments start at 36MB | |||||
*/ | |||||
if (val < 0x11) | |||||
return (val * 32 * MB); | |||||
else if (val < 0x17) | |||||
return ((val - 0x11) * 4 * MB + 8 * MB); | |||||
else | |||||
return ((val - 0x17) * 4 * MB + 36 * MB); | |||||
} | |||||
static vm_paddr_t | |||||
intel_stolen_size_gen9(int bus, int slot, int func) | |||||
{ | |||||
uint16_t ctrl; | |||||
uint16_t val; | |||||
ctrl = pci_cfgregread(bus, slot, func, SNB_GMCH_CTRL, 2); | |||||
val = (ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK; | |||||
/* 0x0 to 0xEF: 32MB increments starting at 0MB */ | |||||
/* 0xF0 to 0xFE: 4MB increments starting at 4MB */ | |||||
if (val < 0xF0) | |||||
return (val * 32 * MB); | |||||
else | |||||
return ((val - 0xF0) * 4 * MB + 4 * MB); | |||||
Done Inline Actions'else' is not needed. kib: 'else' is not needed. | |||||
return 0; | |||||
} | |||||
Done Inline ActionsThe return is dead. kib: The return is dead. | |||||
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 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), | |||||
}; | |||||
/* | |||||
* Buggy BIOS don't reserve memory for the GPU properly and the OS | |||||
* can claim it before the GPU driver is loaded. This function will | |||||
* check the registers for base and size of this memory and reserve | |||||
* it for the GPU driver. | |||||
* gen3 (2004) and newer devices are supported. Support for older hw | |||||
* can be ported from Linux if needed. | |||||
*/ | |||||
static void | |||||
intel_graphics_stolen(void) | |||||
{ | |||||
const struct intel_stolen_ops *ops; | |||||
uint16_t vendor, device, class; | |||||
int i; | |||||
uint8_t bus = 0; | |||||
uint8_t slot = 2; | |||||
Done Inline ActionsWell, style recommends avoiding initialization in declaration. There you really provide constants, so perhaps either add const qualifiers to b/s/f names, or use #defines with more telling name, like NB_BUS etc. kib: Well, style recommends avoiding initialization in declaration. There you really provide… | |||||
uint8_t 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 = (const struct intel_stolen_ops*) intel_ids[i].data; | |||||
Done Inline ActionsWhy do you do it this way ? Make the type of data member 'constr struct intel_stolen_ops *' directly. kib: Why do you do it this way ? Make the type of data member 'constr struct intel_stolen_ops *'… | |||||
Done Inline ActionsSo that data can be a generic pointer for to be used by other early quirk functions. johalun0_gmail.com: So that data can be a generic pointer for to be used by other early quirk functions. | |||||
intel_graphics_stolen_base = ops->base(bus, slot, func); | |||||
intel_graphics_stolen_size = ops->size(bus, slot, func); | |||||
Not Done Inline ActionsI'd suggest a warning here if size == 0. Graphics will not work properly if size is 0. (Although maybe i915 code already does this, in which case ignore). bwidawsk: I'd suggest a warning here if size == 0. Graphics will not work properly if size is 0. | |||||
break; | |||||
Done Inline ActionsExtra blank line. kib: Extra blank line. | |||||
} | |||||
phys_avail_reserve(intel_graphics_stolen_base, | |||||
intel_graphics_stolen_base + intel_graphics_stolen_size); | |||||
} | |||||
#endif /* defined(__amd64__) */ | |||||
void | |||||
pci_early_quirks(void) | |||||
{ | |||||
#if defined(__amd64__) | |||||
intel_graphics_stolen(); | |||||
#endif | |||||
Done Inline ActionsAdd blank line after '{'. kib: Add blank line after '{'. | |||||
} |
Look at sys/amd64/amd64/mp_machdep.c:87, where the GiB(x) macro is defined. I like this way much more than manual multiplication by a constant.