Commit 1053e6bb authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-iommu-for-linus' of...

Merge branch 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86/amd-iommu: Update copyright headers
  x86/amd-iommu: Reenable AMD IOMMU if it's mysteriously vanished over suspend
  AGP: Warn when GATT memory cannot be set to UC
  x86, GART: Disable GART table walk probes
  x86, GART: Remove superfluous AMD64_GARTEN
parents a8fe1500 3d8a1a6a
/* /*
* Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
* Author: Joerg Roedel <joerg.roedel@amd.com> * Author: Joerg Roedel <joerg.roedel@amd.com>
* Leo Duran <leo.duran@amd.com> * Leo Duran <leo.duran@amd.com>
* *
......
/* /*
* Copyright (C) 2009 Advanced Micro Devices, Inc. * Copyright (C) 2009-2010 Advanced Micro Devices, Inc.
* Author: Joerg Roedel <joerg.roedel@amd.com> * Author: Joerg Roedel <joerg.roedel@amd.com>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
......
/* /*
* Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
* Author: Joerg Roedel <joerg.roedel@amd.com> * Author: Joerg Roedel <joerg.roedel@amd.com>
* Leo Duran <leo.duran@amd.com> * Leo Duran <leo.duran@amd.com>
* *
...@@ -416,13 +416,22 @@ struct amd_iommu { ...@@ -416,13 +416,22 @@ struct amd_iommu {
struct dma_ops_domain *default_dom; struct dma_ops_domain *default_dom;
/* /*
* This array is required to work around a potential BIOS bug. * We can't rely on the BIOS to restore all values on reinit, so we
* The BIOS may miss to restore parts of the PCI configuration * need to stash them
* space when the system resumes from S3. The result is that the
* IOMMU does not execute commands anymore which leads to system
* failure.
*/ */
u32 cache_cfg[4];
/* The iommu BAR */
u32 stored_addr_lo;
u32 stored_addr_hi;
/*
* Each iommu has 6 l1s, each of which is documented as having 0x12
* registers
*/
u32 stored_l1[6][0x12];
/* The l2 indirect registers */
u32 stored_l2[0x83];
}; };
/* /*
......
...@@ -17,6 +17,7 @@ extern int fix_aperture; ...@@ -17,6 +17,7 @@ extern int fix_aperture;
#define GARTEN (1<<0) #define GARTEN (1<<0)
#define DISGARTCPU (1<<4) #define DISGARTCPU (1<<4)
#define DISGARTIO (1<<5) #define DISGARTIO (1<<5)
#define DISTLBWALKPRB (1<<6)
/* GART cache control register bits. */ /* GART cache control register bits. */
#define INVGART (1<<0) #define INVGART (1<<0)
...@@ -27,7 +28,6 @@ extern int fix_aperture; ...@@ -27,7 +28,6 @@ extern int fix_aperture;
#define AMD64_GARTAPERTUREBASE 0x94 #define AMD64_GARTAPERTUREBASE 0x94
#define AMD64_GARTTABLEBASE 0x98 #define AMD64_GARTTABLEBASE 0x98
#define AMD64_GARTCACHECTL 0x9c #define AMD64_GARTCACHECTL 0x9c
#define AMD64_GARTEN (1<<0)
#ifdef CONFIG_GART_IOMMU #ifdef CONFIG_GART_IOMMU
extern int gart_iommu_aperture; extern int gart_iommu_aperture;
...@@ -57,6 +57,19 @@ static inline void gart_iommu_hole_init(void) ...@@ -57,6 +57,19 @@ static inline void gart_iommu_hole_init(void)
extern int agp_amd64_init(void); extern int agp_amd64_init(void);
static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order)
{
u32 ctl;
/*
* Don't enable translation but enable GART IO and CPU accesses.
* Also, set DISTLBWALKPRB since GART tables memory is UC.
*/
ctl = DISTLBWALKPRB | order << 1;
pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
}
static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
{ {
u32 tmp, ctl; u32 tmp, ctl;
......
/* /*
* Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
* Author: Joerg Roedel <joerg.roedel@amd.com> * Author: Joerg Roedel <joerg.roedel@amd.com>
* Leo Duran <leo.duran@amd.com> * Leo Duran <leo.duran@amd.com>
* *
......
/* /*
* Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
* Author: Joerg Roedel <joerg.roedel@amd.com> * Author: Joerg Roedel <joerg.roedel@amd.com>
* Leo Duran <leo.duran@amd.com> * Leo Duran <leo.duran@amd.com>
* *
...@@ -194,6 +194,39 @@ static inline unsigned long tbl_size(int entry_size) ...@@ -194,6 +194,39 @@ static inline unsigned long tbl_size(int entry_size)
return 1UL << shift; return 1UL << shift;
} }
/* Access to l1 and l2 indexed register spaces */
static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
{
u32 val;
pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
pci_read_config_dword(iommu->dev, 0xfc, &val);
return val;
}
static void iommu_write_l1(struct amd_iommu *iommu, u16 l1, u8 address, u32 val)
{
pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16 | 1 << 31));
pci_write_config_dword(iommu->dev, 0xfc, val);
pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
}
static u32 iommu_read_l2(struct amd_iommu *iommu, u8 address)
{
u32 val;
pci_write_config_dword(iommu->dev, 0xf0, address);
pci_read_config_dword(iommu->dev, 0xf4, &val);
return val;
}
static void iommu_write_l2(struct amd_iommu *iommu, u8 address, u32 val)
{
pci_write_config_dword(iommu->dev, 0xf0, (address | 1 << 8));
pci_write_config_dword(iommu->dev, 0xf4, val);
}
/**************************************************************************** /****************************************************************************
* *
* AMD IOMMU MMIO register space handling functions * AMD IOMMU MMIO register space handling functions
...@@ -619,6 +652,7 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu) ...@@ -619,6 +652,7 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
{ {
int cap_ptr = iommu->cap_ptr; int cap_ptr = iommu->cap_ptr;
u32 range, misc; u32 range, misc;
int i, j;
pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET, pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
&iommu->cap); &iommu->cap);
...@@ -633,12 +667,29 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu) ...@@ -633,12 +667,29 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
MMIO_GET_LD(range)); MMIO_GET_LD(range));
iommu->evt_msi_num = MMIO_MSI_NUM(misc); iommu->evt_msi_num = MMIO_MSI_NUM(misc);
if (is_rd890_iommu(iommu->dev)) { if (!is_rd890_iommu(iommu->dev))
pci_read_config_dword(iommu->dev, 0xf0, &iommu->cache_cfg[0]); return;
pci_read_config_dword(iommu->dev, 0xf4, &iommu->cache_cfg[1]);
pci_read_config_dword(iommu->dev, 0xf8, &iommu->cache_cfg[2]); /*
pci_read_config_dword(iommu->dev, 0xfc, &iommu->cache_cfg[3]); * Some rd890 systems may not be fully reconfigured by the BIOS, so
} * it's necessary for us to store this information so it can be
* reprogrammed on resume
*/
pci_read_config_dword(iommu->dev, iommu->cap_ptr + 4,
&iommu->stored_addr_lo);
pci_read_config_dword(iommu->dev, iommu->cap_ptr + 8,
&iommu->stored_addr_hi);
/* Low bit locks writes to configuration space */
iommu->stored_addr_lo &= ~1;
for (i = 0; i < 6; i++)
for (j = 0; j < 0x12; j++)
iommu->stored_l1[i][j] = iommu_read_l1(iommu, i, j);
for (i = 0; i < 0x83; i++)
iommu->stored_l2[i] = iommu_read_l2(iommu, i);
} }
/* /*
...@@ -1127,14 +1178,53 @@ static void iommu_init_flags(struct amd_iommu *iommu) ...@@ -1127,14 +1178,53 @@ static void iommu_init_flags(struct amd_iommu *iommu)
iommu_feature_enable(iommu, CONTROL_COHERENT_EN); iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
} }
static void iommu_apply_quirks(struct amd_iommu *iommu) static void iommu_apply_resume_quirks(struct amd_iommu *iommu)
{ {
if (is_rd890_iommu(iommu->dev)) { int i, j;
pci_write_config_dword(iommu->dev, 0xf0, iommu->cache_cfg[0]); u32 ioc_feature_control;
pci_write_config_dword(iommu->dev, 0xf4, iommu->cache_cfg[1]); struct pci_dev *pdev = NULL;
pci_write_config_dword(iommu->dev, 0xf8, iommu->cache_cfg[2]);
pci_write_config_dword(iommu->dev, 0xfc, iommu->cache_cfg[3]); /* RD890 BIOSes may not have completely reconfigured the iommu */
} if (!is_rd890_iommu(iommu->dev))
return;
/*
* First, we need to ensure that the iommu is enabled. This is
* controlled by a register in the northbridge
*/
pdev = pci_get_bus_and_slot(iommu->dev->bus->number, PCI_DEVFN(0, 0));
if (!pdev)
return;
/* Select Northbridge indirect register 0x75 and enable writing */
pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7));
pci_read_config_dword(pdev, 0x64, &ioc_feature_control);
/* Enable the iommu */
if (!(ioc_feature_control & 0x1))
pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1);
pci_dev_put(pdev);
/* Restore the iommu BAR */
pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
iommu->stored_addr_lo);
pci_write_config_dword(iommu->dev, iommu->cap_ptr + 8,
iommu->stored_addr_hi);
/* Restore the l1 indirect regs for each of the 6 l1s */
for (i = 0; i < 6; i++)
for (j = 0; j < 0x12; j++)
iommu_write_l1(iommu, i, j, iommu->stored_l1[i][j]);
/* Restore the l2 indirect regs */
for (i = 0; i < 0x83; i++)
iommu_write_l2(iommu, i, iommu->stored_l2[i]);
/* Lock PCI setup registers */
pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
iommu->stored_addr_lo | 1);
} }
/* /*
...@@ -1147,7 +1237,6 @@ static void enable_iommus(void) ...@@ -1147,7 +1237,6 @@ static void enable_iommus(void)
for_each_iommu(iommu) { for_each_iommu(iommu) {
iommu_disable(iommu); iommu_disable(iommu);
iommu_apply_quirks(iommu);
iommu_init_flags(iommu); iommu_init_flags(iommu);
iommu_set_device_table(iommu); iommu_set_device_table(iommu);
iommu_enable_command_buffer(iommu); iommu_enable_command_buffer(iommu);
...@@ -1173,6 +1262,11 @@ static void disable_iommus(void) ...@@ -1173,6 +1262,11 @@ static void disable_iommus(void)
static int amd_iommu_resume(struct sys_device *dev) static int amd_iommu_resume(struct sys_device *dev)
{ {
struct amd_iommu *iommu;
for_each_iommu(iommu)
iommu_apply_resume_quirks(iommu);
/* re-load the hardware */ /* re-load the hardware */
enable_iommus(); enable_iommus();
......
...@@ -307,7 +307,7 @@ void __init early_gart_iommu_check(void) ...@@ -307,7 +307,7 @@ void __init early_gart_iommu_check(void)
continue; continue;
ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
aper_enabled = ctl & AMD64_GARTEN; aper_enabled = ctl & GARTEN;
aper_order = (ctl >> 1) & 7; aper_order = (ctl >> 1) & 7;
aper_size = (32 * 1024 * 1024) << aper_order; aper_size = (32 * 1024 * 1024) << aper_order;
aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
...@@ -362,7 +362,7 @@ void __init early_gart_iommu_check(void) ...@@ -362,7 +362,7 @@ void __init early_gart_iommu_check(void)
continue; continue;
ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
ctl &= ~AMD64_GARTEN; ctl &= ~GARTEN;
write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
} }
} }
...@@ -505,8 +505,13 @@ void __init gart_iommu_hole_init(void) ...@@ -505,8 +505,13 @@ void __init gart_iommu_hole_init(void)
/* Fix up the north bridges */ /* Fix up the north bridges */
for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) { for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
int bus; int bus, dev_base, dev_limit;
int dev_base, dev_limit;
/*
* Don't enable translation yet but enable GART IO and CPU
* accesses and set DISTLBWALKPRB since GART table memory is UC.
*/
u32 ctl = DISTLBWALKPRB | aper_order << 1;
bus = bus_dev_ranges[i].bus; bus = bus_dev_ranges[i].bus;
dev_base = bus_dev_ranges[i].dev_base; dev_base = bus_dev_ranges[i].dev_base;
...@@ -515,10 +520,7 @@ void __init gart_iommu_hole_init(void) ...@@ -515,10 +520,7 @@ void __init gart_iommu_hole_init(void)
if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00))) if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
continue; continue;
/* Don't enable translation yet. That is done later. write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
Assume this BIOS didn't initialise the GART so
just overwrite all previous bits */
write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, aper_order << 1);
write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25); write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25);
} }
} }
......
...@@ -601,7 +601,7 @@ static void gart_fixup_northbridges(struct sys_device *dev) ...@@ -601,7 +601,7 @@ static void gart_fixup_northbridges(struct sys_device *dev)
* Don't enable translations just yet. That is the next * Don't enable translations just yet. That is the next
* step. Restore the pre-suspend aperture settings. * step. Restore the pre-suspend aperture settings.
*/ */
pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, aperture_order << 1); gart_set_size_and_enable(dev, aperture_order);
pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25); pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25);
} }
} }
......
...@@ -199,7 +199,7 @@ static void amd64_cleanup(void) ...@@ -199,7 +199,7 @@ static void amd64_cleanup(void)
struct pci_dev *dev = k8_northbridges[i]; struct pci_dev *dev = k8_northbridges[i];
/* disable gart translation */ /* disable gart translation */
pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp); pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp);
tmp &= ~AMD64_GARTEN; tmp &= ~GARTEN;
pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp); pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp);
} }
} }
...@@ -313,7 +313,7 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, ...@@ -313,7 +313,7 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order))
return -1; return -1;
pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1); gart_set_size_and_enable(nb, order);
pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25); pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25);
return 0; return 0;
......
...@@ -984,7 +984,9 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge) ...@@ -984,7 +984,9 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
bridge->driver->cache_flush(); bridge->driver->cache_flush();
#ifdef CONFIG_X86 #ifdef CONFIG_X86
set_memory_uc((unsigned long)table, 1 << page_order); if (set_memory_uc((unsigned long)table, 1 << page_order))
printk(KERN_WARNING "Could not set GATT table memory to UC!");
bridge->gatt_table = (void *)table; bridge->gatt_table = (void *)table;
#else #else
bridge->gatt_table = ioremap_nocache(virt_to_phys(table), bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment