// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2001-2003 SuSE Labs. * Distributed under the GNU public license, v2. * * This is a GART driver for the AMD Opteron/Athlon64 on-CPU northbridge. * It also includes support for the AMD 8151 AGP bridge, * although it doesn't actually do much, as all the real * work is done in the northbridge(s).
*/
staticint amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
{ int i, j, num_entries; longlong tmp; int mask_type; struct agp_bridge_data *bridge = mem->bridge;
u32 pte;
num_entries = agp_num_entries();
if (type != mem->type) return -EINVAL;
mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); if (mask_type != 0) return -EINVAL;
/* Make sure we can fit the range in the gatt table. */ /* FIXME: could wrap */ if (((unsignedlong)pg_start + mem->page_count) > num_entries) return -EINVAL;
j = pg_start;
/* gatt table should be empty. */ while (j < (pg_start + mem->page_count)) { if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY;
j++;
}
if (!mem->is_flushed) {
global_cache_flush();
mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
tmp = agp_bridge->driver->mask_memory(agp_bridge,
page_to_phys(mem->pages[i]),
mask_type);
/* * This hack alters the order element according * to the size of a long. It sucks. I totally disown this, even * though it does appear to work for the most part.
*/ staticstruct aper_size_info_32 amd64_aperture_sizes[7] =
{
{32, 8192, 3+(sizeof(long)/8), 0 },
{64, 16384, 4+(sizeof(long)/8), 1<<1 },
{128, 32768, 5+(sizeof(long)/8), 1<<2 },
{256, 65536, 6+(sizeof(long)/8), 1<<1 | 1<<2 },
{512, 131072, 7+(sizeof(long)/8), 1<<3 },
{1024, 262144, 8+(sizeof(long)/8), 1<<1 | 1<<3},
{2048, 524288, 9+(sizeof(long)/8), 1<<2 | 1<<3}
};
/* * Get the current Aperture size from the x86-64. * Note, that there may be multiple x86-64's, but we just return * the value from the first one we find. The set_size functions * keep the rest coherent anyway. Or at least should do.
*/ staticint amd64_fetch_size(void)
{ struct pci_dev *dev; int i;
u32 temp; struct aper_size_info_32 *values;
dev = node_to_amd_nb(0)->misc; if (dev==NULL) return 0;
/* * In a multiprocessor x86-64 system, this function gets * called once for each CPU.
*/ static u64 amd64_configure(struct pci_dev *hammer, u64 gatt_table)
{
u64 aperturebase;
u32 tmp;
u64 aper_base;
/* Address to map to */
pci_read_config_dword(hammer, AMD64_GARTAPERTUREBASE, &tmp);
aperturebase = (u64)tmp << 25;
aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK);
/* Some basic sanity checks for the aperture. */ staticint agp_aperture_valid(u64 aper, u32 size)
{ if (!aperture_valid(aper, size, 32*1024*1024)) return 0;
/* Request the Aperture. This catches cases when someone else already put a mapping in there - happens with some very broken BIOS
Maybe better to use pci_assign_resource/pci_enable_device instead
trusting the bridges? */ if (!aperture_resource &&
!(aperture_resource = request_mem_region(aper, size, "aperture"))) {
printk(KERN_ERR PFX "Aperture conflicts with PCI mapping.\n"); return 0;
} return 1;
}
/* * W*s centric BIOS sometimes only set up the aperture in the AGP * bridge, not the northbridge. On AMD64 this is handled early * in aperture.c, but when IOMMU is not enabled or we run * on a 32bit kernel this needs to be redone. * Unfortunately it is impossible to fix the aperture here because it's too late * to allocate that much memory. But at least error out cleanly instead of * crashing.
*/ staticint fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)
{
u64 aper, nb_aper; int order = 0;
u32 nb_order, nb_base;
u16 apsize;
/* Northbridge seems to contain crap. Try the AGP bridge. */
pci_read_config_word(agp, cap+0x14, &apsize); if (apsize == 0xffff) { if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) return 0; return -1;
}
apsize &= 0xfff; /* Some BIOS use weird encodings not in the AGPv3 table. */ if (apsize & 0xff)
apsize |= 0xf00;
order = 7 - hweight16(apsize);
aper = pci_bus_address(agp, AGP_APERTURE_BAR);
/* * On some sick chips APSIZE is 0. This means it wants 4G * so let double check that order, and lets trust the AMD NB settings
*/ if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) {
dev_info(&agp->dev, "aperture size %u MB is not right, using settings from NB\n",
32 << order);
order = nb_order;
}
if (nb_order >= order) { if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) return 0;
}
staticint cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
{ int i;
if (!amd_nb_num()) return -ENODEV;
if (!amd_nb_has_feature(AMD_NB_GART)) return -ENODEV;
i = 0; for (i = 0; i < amd_nb_num(); i++) { struct pci_dev *dev = node_to_amd_nb(i)->misc; if (fix_northbridge(dev, pdev, cap_ptr) < 0) {
dev_err(&dev->dev, "no usable aperture found\n"); #ifdef __x86_64__ /* should port this to i386 */
dev_err(&dev->dev, "consider rebooting with iommu=memaper=2 to get a good aperture\n"); #endif return -1;
}
} return 0;
}
/* Handle shadow device of the Nvidia NForce3 */ /* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ staticint nforce3_agp_init(struct pci_dev *pdev)
{
u32 tmp, apbase, apbar, aplimit; struct pci_dev *dev1; int i, ret; unsigned size = amd64_fetch_size();
/* if x86-64 aperture base is beyond 4G, exit here */ if ( (apbase & 0x7fff) >> (32 - 25) ) {
dev_info(&pdev->dev, "aperture base > 4G\n");
ret = -ENODEV; goto put;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.