Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (21 commits) x86/PCI: use dev_printk when possible PCI: add D3 power state avoidance quirk PCI: fix bogus "'device' may be used uninitialized" warning in pci_slot PCI: add an option to allow ASPM enabled forcibly PCI: disable ASPM on pre-1.1 PCIe devices PCI: disable ASPM per ACPI FADT setting PCI MSI: Don't disable MSIs if the mask bit isn't supported PCI: handle 64-bit resources better on 32-bit machines PCI: rewrite PCI BAR reading code PCI: document pci_target_state PCI hotplug: fix typo in pcie hotplug output x86 gart: replace to_pages macro with iommu_num_pages x86, AMD IOMMU: replace to_pages macro with iommu_num_pages iommu: add iommu_num_pages helper function dma-coherent: add documentation to new interfaces Cris: convert to using generic dma-coherent mem allocator Sh: use generic per-device coherent dma allocator ARM: support generic per-device coherent dma mem Generic dma-coherent: fix DMA_MEMORY_EXCLUSIVE x86: use generic per-device dma coherent allocator ...
This commit is contained in:
commit
1d9b9f6a53
36 changed files with 516 additions and 572 deletions
|
@ -17,6 +17,7 @@ config ARM
|
|||
select HAVE_KRETPROBES if (HAVE_KPROBES)
|
||||
select HAVE_FTRACE if (!XIP_KERNEL)
|
||||
select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE)
|
||||
select HAVE_GENERIC_DMA_COHERENT
|
||||
help
|
||||
The ARM series is a line of low-power-consumption RISC chip designs
|
||||
licensed by ARM Ltd and targeted at embedded applications and
|
||||
|
|
|
@ -274,6 +274,11 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
|
|||
void *
|
||||
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
|
||||
{
|
||||
void *memory;
|
||||
|
||||
if (dma_alloc_from_coherent(dev, size, handle, &memory))
|
||||
return memory;
|
||||
|
||||
if (arch_is_coherent()) {
|
||||
void *virt;
|
||||
|
||||
|
@ -362,6 +367,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
|
|||
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
|
||||
return;
|
||||
|
||||
if (arch_is_coherent()) {
|
||||
kfree(cpu_addr);
|
||||
return;
|
||||
|
|
|
@ -641,6 +641,7 @@ config PCI
|
|||
bool
|
||||
depends on ETRAX_CARDBUS
|
||||
default y
|
||||
select HAVE_GENERIC_DMA_COHERENT
|
||||
|
||||
config ETRAX_IOP_FW_LOAD
|
||||
tristate "IO-processor hotplug firmware loading support"
|
||||
|
|
|
@ -15,35 +15,16 @@
|
|||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct dma_coherent_mem {
|
||||
void *virt_base;
|
||||
u32 device_base;
|
||||
int size;
|
||||
int flags;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp)
|
||||
{
|
||||
void *ret;
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
int order = get_order(size);
|
||||
/* ignore region specifiers */
|
||||
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
|
||||
|
||||
if (mem) {
|
||||
int page = bitmap_find_free_region(mem->bitmap, mem->size,
|
||||
order);
|
||||
if (page >= 0) {
|
||||
*dma_handle = mem->device_base + (page << PAGE_SHIFT);
|
||||
ret = mem->virt_base + (page << PAGE_SHIFT);
|
||||
memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
if (mem->flags & DMA_MEMORY_EXCLUSIVE)
|
||||
return NULL;
|
||||
}
|
||||
if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
|
||||
return ret;
|
||||
|
||||
if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
|
||||
gfp |= GFP_DMA;
|
||||
|
@ -60,90 +41,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
|
|||
void dma_free_coherent(struct device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
int order = get_order(size);
|
||||
|
||||
if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
|
||||
bitmap_release_region(mem->bitmap, page, order);
|
||||
} else
|
||||
if (!dma_release_from_coherent(dev, order, vaddr))
|
||||
free_pages((unsigned long)vaddr, order);
|
||||
}
|
||||
|
||||
int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags)
|
||||
{
|
||||
void __iomem *mem_base;
|
||||
int pages = size >> PAGE_SHIFT;
|
||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
|
||||
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
|
||||
goto out;
|
||||
if (!size)
|
||||
goto out;
|
||||
if (dev->dma_mem)
|
||||
goto out;
|
||||
|
||||
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
||||
|
||||
mem_base = ioremap(bus_addr, size);
|
||||
if (!mem_base)
|
||||
goto out;
|
||||
|
||||
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto iounmap_out;
|
||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
|
||||
dev->dma_mem->virt_base = mem_base;
|
||||
dev->dma_mem->device_base = device_addr;
|
||||
dev->dma_mem->size = pages;
|
||||
dev->dma_mem->flags = flags;
|
||||
|
||||
if (flags & DMA_MEMORY_MAP)
|
||||
return DMA_MEMORY_MAP;
|
||||
|
||||
return DMA_MEMORY_IO;
|
||||
|
||||
free1_out:
|
||||
kfree(dev->dma_mem);
|
||||
iounmap_out:
|
||||
iounmap(mem_base);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
||||
|
||||
void dma_release_declared_memory(struct device *dev)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
|
||||
if(!mem)
|
||||
return;
|
||||
dev->dma_mem = NULL;
|
||||
iounmap(mem->virt_base);
|
||||
kfree(mem->bitmap);
|
||||
kfree(mem);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_release_declared_memory);
|
||||
|
||||
void *dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
int pos, err;
|
||||
|
||||
if (!mem)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
||||
err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
return mem->virt_base + (pos << PAGE_SHIFT);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
|
||||
|
|
|
@ -11,6 +11,7 @@ config SUPERH
|
|||
select HAVE_CLK
|
||||
select HAVE_IDE
|
||||
select HAVE_OPROFILE
|
||||
select HAVE_GENERIC_DMA_COHERENT
|
||||
help
|
||||
The SuperH is a RISC processor targeted for use in embedded systems
|
||||
and consumer electronics; it was also used in the Sega Dreamcast
|
||||
|
|
|
@ -28,21 +28,10 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
|
|||
dma_addr_t *dma_handle, gfp_t gfp)
|
||||
{
|
||||
void *ret, *ret_nocache;
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
int order = get_order(size);
|
||||
|
||||
if (mem) {
|
||||
int page = bitmap_find_free_region(mem->bitmap, mem->size,
|
||||
order);
|
||||
if (page >= 0) {
|
||||
*dma_handle = mem->device_base + (page << PAGE_SHIFT);
|
||||
ret = mem->virt_base + (page << PAGE_SHIFT);
|
||||
memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
if (mem->flags & DMA_MEMORY_EXCLUSIVE)
|
||||
return NULL;
|
||||
}
|
||||
if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
|
||||
return ret;
|
||||
|
||||
ret = (void *)__get_free_pages(gfp, order);
|
||||
if (!ret)
|
||||
|
@ -72,11 +61,7 @@ void dma_free_coherent(struct device *dev, size_t size,
|
|||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
int order = get_order(size);
|
||||
|
||||
if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
|
||||
bitmap_release_region(mem->bitmap, page, order);
|
||||
} else {
|
||||
if (!dma_release_from_coherent(dev, order, vaddr)) {
|
||||
WARN_ON(irqs_disabled()); /* for portability */
|
||||
BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE);
|
||||
free_pages((unsigned long)phys_to_virt(dma_handle), order);
|
||||
|
@ -85,83 +70,6 @@ void dma_free_coherent(struct device *dev, size_t size,
|
|||
}
|
||||
EXPORT_SYMBOL(dma_free_coherent);
|
||||
|
||||
int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags)
|
||||
{
|
||||
void __iomem *mem_base = NULL;
|
||||
int pages = size >> PAGE_SHIFT;
|
||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
|
||||
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
|
||||
goto out;
|
||||
if (!size)
|
||||
goto out;
|
||||
if (dev->dma_mem)
|
||||
goto out;
|
||||
|
||||
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
||||
|
||||
mem_base = ioremap_nocache(bus_addr, size);
|
||||
if (!mem_base)
|
||||
goto out;
|
||||
|
||||
dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto out;
|
||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
|
||||
dev->dma_mem->virt_base = mem_base;
|
||||
dev->dma_mem->device_base = device_addr;
|
||||
dev->dma_mem->size = pages;
|
||||
dev->dma_mem->flags = flags;
|
||||
|
||||
if (flags & DMA_MEMORY_MAP)
|
||||
return DMA_MEMORY_MAP;
|
||||
|
||||
return DMA_MEMORY_IO;
|
||||
|
||||
free1_out:
|
||||
kfree(dev->dma_mem);
|
||||
out:
|
||||
if (mem_base)
|
||||
iounmap(mem_base);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
||||
|
||||
void dma_release_declared_memory(struct device *dev)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
dev->dma_mem = NULL;
|
||||
iounmap(mem->virt_base);
|
||||
kfree(mem->bitmap);
|
||||
kfree(mem);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_release_declared_memory);
|
||||
|
||||
void *dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
int pos, err;
|
||||
|
||||
if (!mem)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
||||
err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
return mem->virt_base + (pos << PAGE_SHIFT);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
|
||||
|
||||
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
|
|
|
@ -30,6 +30,7 @@ config X86
|
|||
select HAVE_FTRACE
|
||||
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
|
||||
select HAVE_ARCH_KGDB if !X86_VOYAGER
|
||||
select HAVE_GENERIC_DMA_COHERENT if X86_32
|
||||
select HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
|
||||
config ARCH_DEFCONFIG
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
|
||||
#define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
|
||||
|
||||
#define to_pages(addr, size) \
|
||||
(round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
|
||||
|
||||
#define EXIT_LOOP_COUNT 10000000
|
||||
|
||||
static DEFINE_RWLOCK(amd_iommu_devtable_lock);
|
||||
|
@ -185,7 +182,7 @@ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid,
|
|||
u64 address, size_t size)
|
||||
{
|
||||
int s = 0;
|
||||
unsigned pages = to_pages(address, size);
|
||||
unsigned pages = iommu_num_pages(address, size);
|
||||
|
||||
address &= PAGE_MASK;
|
||||
|
||||
|
@ -557,8 +554,8 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
|
|||
if (iommu->exclusion_start &&
|
||||
iommu->exclusion_start < dma_dom->aperture_size) {
|
||||
unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
|
||||
int pages = to_pages(iommu->exclusion_start,
|
||||
iommu->exclusion_length);
|
||||
int pages = iommu_num_pages(iommu->exclusion_start,
|
||||
iommu->exclusion_length);
|
||||
dma_ops_reserve_addresses(dma_dom, startpage, pages);
|
||||
}
|
||||
|
||||
|
@ -767,7 +764,7 @@ static dma_addr_t __map_single(struct device *dev,
|
|||
unsigned int pages;
|
||||
int i;
|
||||
|
||||
pages = to_pages(paddr, size);
|
||||
pages = iommu_num_pages(paddr, size);
|
||||
paddr &= PAGE_MASK;
|
||||
|
||||
address = dma_ops_alloc_addresses(dev, dma_dom, pages);
|
||||
|
@ -802,7 +799,7 @@ static void __unmap_single(struct amd_iommu *iommu,
|
|||
if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size))
|
||||
return;
|
||||
|
||||
pages = to_pages(dma_addr, size);
|
||||
pages = iommu_num_pages(dma_addr, size);
|
||||
dma_addr &= PAGE_MASK;
|
||||
start = dma_addr;
|
||||
|
||||
|
|
|
@ -192,124 +192,6 @@ static __init int iommu_setup(char *p)
|
|||
}
|
||||
early_param("iommu", iommu_setup);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags)
|
||||
{
|
||||
void __iomem *mem_base = NULL;
|
||||
int pages = size >> PAGE_SHIFT;
|
||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
|
||||
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
|
||||
goto out;
|
||||
if (!size)
|
||||
goto out;
|
||||
if (dev->dma_mem)
|
||||
goto out;
|
||||
|
||||
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
||||
|
||||
mem_base = ioremap(bus_addr, size);
|
||||
if (!mem_base)
|
||||
goto out;
|
||||
|
||||
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto out;
|
||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
|
||||
dev->dma_mem->virt_base = mem_base;
|
||||
dev->dma_mem->device_base = device_addr;
|
||||
dev->dma_mem->size = pages;
|
||||
dev->dma_mem->flags = flags;
|
||||
|
||||
if (flags & DMA_MEMORY_MAP)
|
||||
return DMA_MEMORY_MAP;
|
||||
|
||||
return DMA_MEMORY_IO;
|
||||
|
||||
free1_out:
|
||||
kfree(dev->dma_mem);
|
||||
out:
|
||||
if (mem_base)
|
||||
iounmap(mem_base);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
||||
|
||||
void dma_release_declared_memory(struct device *dev)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
dev->dma_mem = NULL;
|
||||
iounmap(mem->virt_base);
|
||||
kfree(mem->bitmap);
|
||||
kfree(mem);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_release_declared_memory);
|
||||
|
||||
void *dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
int pos, err;
|
||||
int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1);
|
||||
|
||||
pages >>= PAGE_SHIFT;
|
||||
|
||||
if (!mem)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
||||
err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
return mem->virt_base + (pos << PAGE_SHIFT);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
|
||||
|
||||
static int dma_alloc_from_coherent_mem(struct device *dev, ssize_t size,
|
||||
dma_addr_t *dma_handle, void **ret)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
int order = get_order(size);
|
||||
|
||||
if (mem) {
|
||||
int page = bitmap_find_free_region(mem->bitmap, mem->size,
|
||||
order);
|
||||
if (page >= 0) {
|
||||
*dma_handle = mem->device_base + (page << PAGE_SHIFT);
|
||||
*ret = mem->virt_base + (page << PAGE_SHIFT);
|
||||
memset(*ret, 0, size);
|
||||
}
|
||||
if (mem->flags & DMA_MEMORY_EXCLUSIVE)
|
||||
*ret = NULL;
|
||||
}
|
||||
return (mem != NULL);
|
||||
}
|
||||
|
||||
static int dma_release_coherent(struct device *dev, int order, void *vaddr)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
|
||||
if (mem && vaddr >= mem->virt_base && vaddr <
|
||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
|
||||
bitmap_release_region(mem->bitmap, page, order);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define dma_alloc_from_coherent_mem(dev, size, handle, ret) (0)
|
||||
#define dma_release_coherent(dev, order, vaddr) (0)
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
int dma_supported(struct device *dev, u64 mask)
|
||||
{
|
||||
struct dma_mapping_ops *ops = get_dma_ops(dev);
|
||||
|
@ -379,7 +261,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
|
|||
/* ignore region specifiers */
|
||||
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
|
||||
|
||||
if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory))
|
||||
if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
|
||||
return memory;
|
||||
|
||||
if (!dev) {
|
||||
|
@ -484,7 +366,7 @@ void dma_free_coherent(struct device *dev, size_t size,
|
|||
|
||||
int order = get_order(size);
|
||||
WARN_ON(irqs_disabled()); /* for portability */
|
||||
if (dma_release_coherent(dev, order, vaddr))
|
||||
if (dma_release_from_coherent(dev, order, vaddr))
|
||||
return;
|
||||
if (ops->unmap_single)
|
||||
ops->unmap_single(dev, bus, size, 0);
|
||||
|
|
|
@ -67,9 +67,6 @@ static u32 gart_unmapped_entry;
|
|||
(((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)
|
||||
#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))
|
||||
|
||||
#define to_pages(addr, size) \
|
||||
(round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
|
||||
|
||||
#define EMERGENCY_PAGES 32 /* = 128KB */
|
||||
|
||||
#ifdef CONFIG_AGP
|
||||
|
@ -241,7 +238,7 @@ nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
|
|||
static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
|
||||
size_t size, int dir)
|
||||
{
|
||||
unsigned long npages = to_pages(phys_mem, size);
|
||||
unsigned long npages = iommu_num_pages(phys_mem, size);
|
||||
unsigned long iommu_page = alloc_iommu(dev, npages);
|
||||
int i;
|
||||
|
||||
|
@ -304,7 +301,7 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
|
|||
return;
|
||||
|
||||
iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
|
||||
npages = to_pages(dma_addr, size);
|
||||
npages = iommu_num_pages(dma_addr, size);
|
||||
for (i = 0; i < npages; i++) {
|
||||
iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
|
||||
CLEAR_LEAK(iommu_page + i);
|
||||
|
@ -387,7 +384,7 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start,
|
|||
}
|
||||
|
||||
addr = phys_addr;
|
||||
pages = to_pages(s->offset, s->length);
|
||||
pages = iommu_num_pages(s->offset, s->length);
|
||||
while (pages--) {
|
||||
iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
|
||||
SET_LEAK(iommu_page);
|
||||
|
@ -470,7 +467,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
|
|||
|
||||
seg_size += s->length;
|
||||
need = nextneed;
|
||||
pages += to_pages(s->offset, s->length);
|
||||
pages += iommu_num_pages(s->offset, s->length);
|
||||
ps = s;
|
||||
}
|
||||
if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0)
|
||||
|
|
|
@ -23,7 +23,8 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
|
|||
pci_read_config_byte(d, reg++, &busno);
|
||||
pci_read_config_byte(d, reg++, &suba);
|
||||
pci_read_config_byte(d, reg++, &subb);
|
||||
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
|
||||
dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno,
|
||||
suba, subb);
|
||||
if (busno)
|
||||
pci_scan_bus_with_sysdata(busno); /* Bus A */
|
||||
if (suba < subb)
|
||||
|
|
|
@ -128,10 +128,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
|
|||
pr = pci_find_parent_resource(dev, r);
|
||||
if (!r->start || !pr ||
|
||||
request_resource(pr, r) < 0) {
|
||||
printk(KERN_ERR "PCI: Cannot allocate "
|
||||
"resource region %d "
|
||||
"of bridge %s\n",
|
||||
idx, pci_name(dev));
|
||||
dev_err(&dev->dev, "BAR %d: can't "
|
||||
"allocate resource\n", idx);
|
||||
/*
|
||||
* Something is wrong with the region.
|
||||
* Invalidate the resource to prevent
|
||||
|
@ -166,15 +164,15 @@ static void __init pcibios_allocate_resources(int pass)
|
|||
else
|
||||
disabled = !(command & PCI_COMMAND_MEMORY);
|
||||
if (pass == disabled) {
|
||||
DBG("PCI: Resource %08lx-%08lx "
|
||||
"(f=%lx, d=%d, p=%d)\n",
|
||||
r->start, r->end, r->flags, disabled, pass);
|
||||
dev_dbg(&dev->dev, "resource %#08llx-%#08llx "
|
||||
"(f=%lx, d=%d, p=%d)\n",
|
||||
(unsigned long long) r->start,
|
||||
(unsigned long long) r->end,
|
||||
r->flags, disabled, pass);
|
||||
pr = pci_find_parent_resource(dev, r);
|
||||
if (!pr || request_resource(pr, r) < 0) {
|
||||
printk(KERN_ERR "PCI: Cannot allocate "
|
||||
"resource region %d "
|
||||
"of device %s\n",
|
||||
idx, pci_name(dev));
|
||||
dev_err(&dev->dev, "BAR %d: can't "
|
||||
"allocate resource\n", idx);
|
||||
/* We'll assign a new address later */
|
||||
r->end -= r->start;
|
||||
r->start = 0;
|
||||
|
@ -187,8 +185,7 @@ static void __init pcibios_allocate_resources(int pass)
|
|||
/* Turn the ROM off, leave the resource region,
|
||||
* but keep it unregistered. */
|
||||
u32 reg;
|
||||
DBG("PCI: Switching off ROM of %s\n",
|
||||
pci_name(dev));
|
||||
dev_dbg(&dev->dev, "disabling ROM\n");
|
||||
r->flags &= ~IORESOURCE_ROM_ENABLE;
|
||||
pci_read_config_dword(dev,
|
||||
dev->rom_base_reg, ®);
|
||||
|
@ -257,8 +254,7 @@ void pcibios_set_master(struct pci_dev *dev)
|
|||
lat = pcibios_max_latency;
|
||||
else
|
||||
return;
|
||||
printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n",
|
||||
pci_name(dev), lat);
|
||||
dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat);
|
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
|
||||
}
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
|
|||
{
|
||||
WARN_ON_ONCE(pirq >= 9);
|
||||
if (pirq > 8) {
|
||||
printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
|
||||
dev_info(&dev->dev, "VLSI router PIRQ escape (%d)\n", pirq);
|
||||
return 0;
|
||||
}
|
||||
return read_config_nybble(router, 0x74, pirq-1);
|
||||
|
@ -446,7 +446,7 @@ static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
|
|||
{
|
||||
WARN_ON_ONCE(pirq >= 9);
|
||||
if (pirq > 8) {
|
||||
printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
|
||||
dev_info(&dev->dev, "VLSI router PIRQ escape (%d)\n", pirq);
|
||||
return 0;
|
||||
}
|
||||
write_config_nybble(router, 0x74, pirq-1, irq);
|
||||
|
@ -492,15 +492,17 @@ static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq
|
|||
irq = 0;
|
||||
if (pirq <= 4)
|
||||
irq = read_config_nybble(router, 0x56, pirq - 1);
|
||||
printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
|
||||
dev->vendor, dev->device, pirq, irq);
|
||||
dev_info(&dev->dev,
|
||||
"AMD756: dev [%04x/%04x], router PIRQ %d get IRQ %d\n",
|
||||
dev->vendor, dev->device, pirq, irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
|
||||
{
|
||||
printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n",
|
||||
dev->vendor, dev->device, pirq, irq);
|
||||
dev_info(&dev->dev,
|
||||
"AMD756: dev [%04x/%04x], router PIRQ %d set IRQ %d\n",
|
||||
dev->vendor, dev->device, pirq, irq);
|
||||
if (pirq <= 4)
|
||||
write_config_nybble(router, 0x56, pirq - 1, irq);
|
||||
return 1;
|
||||
|
@ -730,7 +732,6 @@ static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router,
|
|||
switch (device) {
|
||||
case PCI_DEVICE_ID_AL_M1533:
|
||||
case PCI_DEVICE_ID_AL_M1563:
|
||||
printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n");
|
||||
r->name = "ALI";
|
||||
r->get = pirq_ali_get;
|
||||
r->set = pirq_ali_set;
|
||||
|
@ -840,11 +841,9 @@ static void __init pirq_find_router(struct irq_router *r)
|
|||
h->probe(r, pirq_router_dev, pirq_router_dev->device))
|
||||
break;
|
||||
}
|
||||
printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
|
||||
pirq_router.name,
|
||||
pirq_router_dev->vendor,
|
||||
pirq_router_dev->device,
|
||||
pci_name(pirq_router_dev));
|
||||
dev_info(&pirq_router_dev->dev, "%s IRQ router [%04x/%04x]\n",
|
||||
pirq_router.name,
|
||||
pirq_router_dev->vendor, pirq_router_dev->device);
|
||||
|
||||
/* The device remains referenced for the kernel lifetime */
|
||||
}
|
||||
|
@ -877,7 +876,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
|||
/* Find IRQ pin */
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
if (!pin) {
|
||||
DBG(KERN_DEBUG " -> no interrupt pin\n");
|
||||
dev_dbg(&dev->dev, "no interrupt pin\n");
|
||||
return 0;
|
||||
}
|
||||
pin = pin - 1;
|
||||
|
@ -887,20 +886,20 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
|||
if (!pirq_table)
|
||||
return 0;
|
||||
|
||||
DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin);
|
||||
info = pirq_get_info(dev);
|
||||
if (!info) {
|
||||
DBG(" -> not found in routing table\n" KERN_DEBUG);
|
||||
dev_dbg(&dev->dev, "PCI INT %c not found in routing table\n",
|
||||
'A' + pin);
|
||||
return 0;
|
||||
}
|
||||
pirq = info->irq[pin].link;
|
||||
mask = info->irq[pin].bitmap;
|
||||
if (!pirq) {
|
||||
DBG(" -> not routed\n" KERN_DEBUG);
|
||||
dev_dbg(&dev->dev, "PCI INT %c not routed\n", 'A' + pin);
|
||||
return 0;
|
||||
}
|
||||
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask,
|
||||
pirq_table->exclusive_irqs);
|
||||
dev_dbg(&dev->dev, "PCI INT %c -> PIRQ %02x, mask %04x, excl %04x",
|
||||
'A' + pin, pirq, mask, pirq_table->exclusive_irqs);
|
||||
mask &= pcibios_irq_mask;
|
||||
|
||||
/* Work around broken HP Pavilion Notebooks which assign USB to
|
||||
|
@ -930,10 +929,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
|||
if (pci_probe & PCI_USE_PIRQ_MASK)
|
||||
newirq = 0;
|
||||
else
|
||||
printk("\n" KERN_WARNING
|
||||
"PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n"
|
||||
KERN_DEBUG, newirq,
|
||||
pci_name(dev));
|
||||
dev_warn(&dev->dev, "IRQ %d doesn't match PIRQ mask "
|
||||
"%#x; try pci=usepirqmask\n", newirq, mask);
|
||||
}
|
||||
if (!newirq && assign) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
|
@ -944,39 +941,35 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
|||
newirq = i;
|
||||
}
|
||||
}
|
||||
DBG(" -> newirq=%d", newirq);
|
||||
dev_dbg(&dev->dev, "PCI INT %c -> newirq %d", 'A' + pin, newirq);
|
||||
|
||||
/* Check if it is hardcoded */
|
||||
if ((pirq & 0xf0) == 0xf0) {
|
||||
irq = pirq & 0xf;
|
||||
DBG(" -> hardcoded IRQ %d\n", irq);
|
||||
msg = "Hardcoded";
|
||||
msg = "hardcoded";
|
||||
} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
|
||||
((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask))) {
|
||||
DBG(" -> got IRQ %d\n", irq);
|
||||
msg = "Found";
|
||||
msg = "found";
|
||||
eisa_set_level_irq(irq);
|
||||
} else if (newirq && r->set &&
|
||||
(dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
|
||||
DBG(" -> assigning IRQ %d", newirq);
|
||||
if (r->set(pirq_router_dev, dev, pirq, newirq)) {
|
||||
eisa_set_level_irq(newirq);
|
||||
DBG(" ... OK\n");
|
||||
msg = "Assigned";
|
||||
msg = "assigned";
|
||||
irq = newirq;
|
||||
}
|
||||
}
|
||||
|
||||
if (!irq) {
|
||||
DBG(" ... failed\n");
|
||||
if (newirq && mask == (1 << newirq)) {
|
||||
msg = "Guessed";
|
||||
msg = "guessed";
|
||||
irq = newirq;
|
||||
} else
|
||||
} else {
|
||||
dev_dbg(&dev->dev, "can't route interrupt\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq,
|
||||
pci_name(dev));
|
||||
dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin, irq);
|
||||
|
||||
/* Update IRQ for all devices with the same pirq value */
|
||||
while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
|
||||
|
@ -996,17 +989,17 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
|||
(!(pci_probe & PCI_USE_PIRQ_MASK) || \
|
||||
((1 << dev2->irq) & mask))) {
|
||||
#ifndef CONFIG_PCI_MSI
|
||||
printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
|
||||
pci_name(dev2), dev2->irq, irq);
|
||||
dev_info(&dev2->dev, "IRQ routing conflict: "
|
||||
"have IRQ %d, want IRQ %d\n",
|
||||
dev2->irq, irq);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
dev2->irq = irq;
|
||||
pirq_penalty[irq]++;
|
||||
if (dev != dev2)
|
||||
printk(KERN_INFO
|
||||
"PCI: Sharing IRQ %d with %s\n",
|
||||
irq, pci_name(dev2));
|
||||
dev_info(&dev->dev, "sharing IRQ %d with %s\n",
|
||||
irq, pci_name(dev2));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
@ -1025,8 +1018,7 @@ static void __init pcibios_fixup_irqs(void)
|
|||
* already in use.
|
||||
*/
|
||||
if (dev->irq >= 16) {
|
||||
DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n",
|
||||
pci_name(dev), dev->irq);
|
||||
dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq);
|
||||
dev->irq = 0;
|
||||
}
|
||||
/*
|
||||
|
@ -1070,12 +1062,12 @@ static void __init pcibios_fixup_irqs(void)
|
|||
irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
|
||||
PCI_SLOT(bridge->devfn), pin);
|
||||
if (irq >= 0)
|
||||
printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n",
|
||||
pci_name(bridge), 'A' + pin, irq);
|
||||
dev_warn(&dev->dev, "using bridge %s INT %c to get IRQ %d\n",
|
||||
pci_name(bridge),
|
||||
'A' + pin, irq);
|
||||
}
|
||||
if (irq >= 0) {
|
||||
printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
|
||||
pci_name(dev), 'A' + pin, irq);
|
||||
dev_info(&dev->dev, "PCI->APIC IRQ transform: INT %c -> IRQ %d\n", 'A' + pin, irq);
|
||||
dev->irq = irq;
|
||||
}
|
||||
}
|
||||
|
@ -1231,25 +1223,24 @@ static int pirq_enable_irq(struct pci_dev *dev)
|
|||
irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
|
||||
PCI_SLOT(bridge->devfn), pin);
|
||||
if (irq >= 0)
|
||||
printk(KERN_WARNING
|
||||
"PCI: using PPB %s[%c] to get irq %d\n",
|
||||
pci_name(bridge),
|
||||
'A' + pin, irq);
|
||||
dev_warn(&dev->dev, "using bridge %s "
|
||||
"INT %c to get IRQ %d\n",
|
||||
pci_name(bridge), 'A' + pin,
|
||||
irq);
|
||||
dev = bridge;
|
||||
}
|
||||
dev = temp_dev;
|
||||
if (irq >= 0) {
|
||||
printk(KERN_INFO
|
||||
"PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
|
||||
pci_name(dev), 'A' + pin, irq);
|
||||
dev_info(&dev->dev, "PCI->APIC IRQ transform: "
|
||||
"INT %c -> IRQ %d\n", 'A' + pin, irq);
|
||||
dev->irq = irq;
|
||||
return 0;
|
||||
} else
|
||||
msg = " Probably buggy MP table.";
|
||||
msg = "; probably buggy MP table";
|
||||
} else if (pci_probe & PCI_BIOS_IRQ_SCAN)
|
||||
msg = "";
|
||||
else
|
||||
msg = " Please try using pci=biosirq.";
|
||||
msg = "; please try using pci=biosirq";
|
||||
|
||||
/*
|
||||
* With IDE legacy devices the IRQ lookup failure is not
|
||||
|
@ -1259,9 +1250,8 @@ static int pirq_enable_irq(struct pci_dev *dev)
|
|||
!(dev->class & 0x5))
|
||||
return 0;
|
||||
|
||||
printk(KERN_WARNING
|
||||
"PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
|
||||
'A' + pin, pci_name(dev), msg);
|
||||
dev_warn(&dev->dev, "can't find IRQ for PCI INT %c%s\n",
|
||||
'A' + pin, msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -131,13 +131,14 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
|
|||
u8 busno, suba, subb;
|
||||
int quad = BUS2QUAD(d->bus->number);
|
||||
|
||||
printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
|
||||
dev_info(&d->dev, "searching for i450NX host bridges\n");
|
||||
reg = 0xd0;
|
||||
for(pxb=0; pxb<2; pxb++) {
|
||||
pci_read_config_byte(d, reg++, &busno);
|
||||
pci_read_config_byte(d, reg++, &suba);
|
||||
pci_read_config_byte(d, reg++, &subb);
|
||||
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
|
||||
dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n",
|
||||
pxb, busno, suba, subb);
|
||||
if (busno) {
|
||||
/* Bus A */
|
||||
pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
|
||||
|
|
|
@ -76,9 +76,9 @@ static struct acpi_pci_driver acpi_pci_slot_driver = {
|
|||
};
|
||||
|
||||
static int
|
||||
check_slot(acpi_handle handle, int *device, unsigned long *sun)
|
||||
check_slot(acpi_handle handle, unsigned long *sun)
|
||||
{
|
||||
int retval = 0;
|
||||
int device = -1;
|
||||
unsigned long adr, sta;
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
@ -89,32 +89,27 @@ check_slot(acpi_handle handle, int *device, unsigned long *sun)
|
|||
if (check_sta_before_sun) {
|
||||
/* If SxFy doesn't have _STA, we just assume it's there */
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) {
|
||||
retval = -1;
|
||||
if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer);
|
||||
retval = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*device = (adr >> 16) & 0xffff;
|
||||
|
||||
/* No _SUN == not a slot == bail */
|
||||
status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer);
|
||||
retval = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
device = (adr >> 16) & 0xffff;
|
||||
out:
|
||||
kfree(buffer.pointer);
|
||||
return retval;
|
||||
return device;
|
||||
}
|
||||
|
||||
struct callback_args {
|
||||
|
@ -144,7 +139,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
struct callback_args *parent_context = context;
|
||||
struct pci_bus *pci_bus = parent_context->pci_bus;
|
||||
|
||||
if (check_slot(handle, &device, &sun))
|
||||
device = check_slot(handle, &sun);
|
||||
if (device < 0)
|
||||
return AE_OK;
|
||||
|
||||
slot = kmalloc(sizeof(*slot), GFP_KERNEL);
|
||||
|
|
|
@ -1103,7 +1103,7 @@ static inline void dbg_ctrl(struct controller *ctrl)
|
|||
dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
|
||||
dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
|
||||
dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
|
||||
dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
|
||||
dbg(" Command Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
|
||||
pciehp_readw(ctrl, SLOTSTATUS, ®16);
|
||||
dbg("Slot Status : 0x%04x\n", reg16);
|
||||
pciehp_readw(ctrl, SLOTCTRL, ®16);
|
||||
|
|
|
@ -126,7 +126,16 @@ static void msix_flush_writes(unsigned int irq)
|
|||
}
|
||||
}
|
||||
|
||||
static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
|
||||
/*
|
||||
* PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
|
||||
* mask all MSI interrupts by clearing the MSI enable bit does not work
|
||||
* reliably as devices without an INTx disable bit will then generate a
|
||||
* level IRQ which will never be cleared.
|
||||
*
|
||||
* Returns 1 if it succeeded in masking the interrupt and 0 if the device
|
||||
* doesn't support MSI masking.
|
||||
*/
|
||||
static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
|
||||
{
|
||||
struct msi_desc *entry;
|
||||
|
||||
|
@ -144,8 +153,7 @@ static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
|
|||
mask_bits |= flag & mask;
|
||||
pci_write_config_dword(entry->dev, pos, mask_bits);
|
||||
} else {
|
||||
__msi_set_enable(entry->dev, entry->msi_attrib.pos,
|
||||
!flag);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case PCI_CAP_ID_MSIX:
|
||||
|
@ -161,6 +169,7 @@ static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
|
|||
break;
|
||||
}
|
||||
entry->msi_attrib.masked = !!flag;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci-aspm.h>
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acresrc.h>
|
||||
|
@ -372,6 +373,12 @@ static int __init acpi_pci_init(void)
|
|||
printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
|
||||
pci_no_msi();
|
||||
}
|
||||
|
||||
if (acpi_gbl_FADT.boot_flags & BAF_PCIE_ASPM_CONTROL) {
|
||||
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
|
||||
pcie_no_aspm();
|
||||
}
|
||||
|
||||
ret = register_acpi_bus_type(&acpi_pci_bus);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
|
|
@ -572,6 +572,10 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
|||
if (!ret)
|
||||
pci_update_current_state(dev);
|
||||
}
|
||||
/* This device is quirked not to be put into D3, so
|
||||
don't put it in D3 */
|
||||
if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
|
||||
return 0;
|
||||
|
||||
error = pci_raw_set_power_state(dev, state);
|
||||
|
||||
|
@ -1123,6 +1127,12 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
|
|||
}
|
||||
|
||||
/**
|
||||
* pci_target_state - find an appropriate low power state for a given PCI dev
|
||||
* @dev: PCI device
|
||||
*
|
||||
* Use underlying platform code to find a supported low power state for @dev.
|
||||
* If the platform can't manage @dev, return the deepest state from which it
|
||||
* can generate wake events, based on any available PME info.
|
||||
*/
|
||||
pci_power_t pci_target_state(struct pci_dev *dev)
|
||||
{
|
||||
|
|
|
@ -55,7 +55,7 @@ struct pcie_link_state {
|
|||
struct endpoint_state endpoints[8];
|
||||
};
|
||||
|
||||
static int aspm_disabled;
|
||||
static int aspm_disabled, aspm_force;
|
||||
static DEFINE_MUTEX(aspm_lock);
|
||||
static LIST_HEAD(link_list);
|
||||
|
||||
|
@ -510,6 +510,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
|
|||
{
|
||||
struct pci_dev *child_dev;
|
||||
int child_pos;
|
||||
u32 reg32;
|
||||
|
||||
/*
|
||||
* Some functions in a slot might not all be PCIE functions, very
|
||||
|
@ -519,6 +520,19 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
|
|||
child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
|
||||
if (!child_pos)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Disable ASPM for pre-1.1 PCIe device, we follow MS to use
|
||||
* RBER bit to determine if a function is 1.1 version device
|
||||
*/
|
||||
pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP,
|
||||
®32);
|
||||
if (!(reg32 & PCI_EXP_DEVCAP_RBER && !aspm_force)) {
|
||||
printk("Pre-1.1 PCIe device detected, "
|
||||
"disable ASPM for %s. It can be enabled forcedly"
|
||||
" with 'pcie_aspm=force'\n", pci_name(pdev));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -802,11 +816,23 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
|
|||
|
||||
static int __init pcie_aspm_disable(char *str)
|
||||
{
|
||||
aspm_disabled = 1;
|
||||
if (!strcmp(str, "off")) {
|
||||
aspm_disabled = 1;
|
||||
printk(KERN_INFO "PCIe ASPM is disabled\n");
|
||||
} else if (!strcmp(str, "force")) {
|
||||
aspm_force = 1;
|
||||
printk(KERN_INFO "PCIe ASPM is forcedly enabled\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("pcie_noaspm", pcie_aspm_disable);
|
||||
__setup("pcie_aspm=", pcie_aspm_disable);
|
||||
|
||||
void pcie_no_aspm(void)
|
||||
{
|
||||
if (!aspm_force)
|
||||
aspm_disabled = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
|
|
@ -163,28 +163,7 @@ static inline unsigned int pci_calc_resource_flags(unsigned int flags)
|
|||
return IORESOURCE_MEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the extent of a PCI decode..
|
||||
*/
|
||||
static u32 pci_size(u32 base, u32 maxbase, u32 mask)
|
||||
{
|
||||
u32 size = mask & maxbase; /* Find the significant bits */
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
/* Get the lowest of them to find the decode size, and
|
||||
from that the extent. */
|
||||
size = (size & ~(size-1)) - 1;
|
||||
|
||||
/* base == maxbase can be valid only if the BAR has
|
||||
already been programmed with all 1s. */
|
||||
if (base == maxbase && ((base | size) & mask) != mask)
|
||||
return 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
|
||||
static u64 pci_size(u64 base, u64 maxbase, u64 mask)
|
||||
{
|
||||
u64 size = mask & maxbase; /* Find the significant bits */
|
||||
if (!size)
|
||||
|
@ -202,117 +181,142 @@ static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
|
|||
return size;
|
||||
}
|
||||
|
||||
static inline int is_64bit_memory(u32 mask)
|
||||
enum pci_bar_type {
|
||||
pci_bar_unknown, /* Standard PCI BAR probe */
|
||||
pci_bar_io, /* An io port BAR */
|
||||
pci_bar_mem32, /* A 32-bit memory BAR */
|
||||
pci_bar_mem64, /* A 64-bit memory BAR */
|
||||
};
|
||||
|
||||
static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
|
||||
{
|
||||
if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
|
||||
(PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
|
||||
return 1;
|
||||
return 0;
|
||||
if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
|
||||
return pci_bar_io;
|
||||
}
|
||||
|
||||
res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
|
||||
|
||||
if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
return pci_bar_mem64;
|
||||
return pci_bar_mem32;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the type is not unknown, we assume that the lowest bit is 'enable'.
|
||||
* Returns 1 if the BAR was 64-bit and 0 if it was 32-bit.
|
||||
*/
|
||||
static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
|
||||
struct resource *res, unsigned int pos)
|
||||
{
|
||||
u32 l, sz, mask;
|
||||
|
||||
mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0;
|
||||
|
||||
res->name = pci_name(dev);
|
||||
|
||||
pci_read_config_dword(dev, pos, &l);
|
||||
pci_write_config_dword(dev, pos, mask);
|
||||
pci_read_config_dword(dev, pos, &sz);
|
||||
pci_write_config_dword(dev, pos, l);
|
||||
|
||||
/*
|
||||
* All bits set in sz means the device isn't working properly.
|
||||
* If the BAR isn't implemented, all bits must be 0. If it's a
|
||||
* memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit
|
||||
* 1 must be clear.
|
||||
*/
|
||||
if (!sz || sz == 0xffffffff)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* I don't know how l can have all bits set. Copied from old code.
|
||||
* Maybe it fixes a bug on some ancient platform.
|
||||
*/
|
||||
if (l == 0xffffffff)
|
||||
l = 0;
|
||||
|
||||
if (type == pci_bar_unknown) {
|
||||
type = decode_bar(res, l);
|
||||
res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
|
||||
if (type == pci_bar_io) {
|
||||
l &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff;
|
||||
} else {
|
||||
l &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
|
||||
}
|
||||
} else {
|
||||
res->flags |= (l & IORESOURCE_ROM_ENABLE);
|
||||
l &= PCI_ROM_ADDRESS_MASK;
|
||||
mask = (u32)PCI_ROM_ADDRESS_MASK;
|
||||
}
|
||||
|
||||
if (type == pci_bar_mem64) {
|
||||
u64 l64 = l;
|
||||
u64 sz64 = sz;
|
||||
u64 mask64 = mask | (u64)~0 << 32;
|
||||
|
||||
pci_read_config_dword(dev, pos + 4, &l);
|
||||
pci_write_config_dword(dev, pos + 4, ~0);
|
||||
pci_read_config_dword(dev, pos + 4, &sz);
|
||||
pci_write_config_dword(dev, pos + 4, l);
|
||||
|
||||
l64 |= ((u64)l << 32);
|
||||
sz64 |= ((u64)sz << 32);
|
||||
|
||||
sz64 = pci_size(l64, sz64, mask64);
|
||||
|
||||
if (!sz64)
|
||||
goto fail;
|
||||
|
||||
if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) {
|
||||
dev_err(&dev->dev, "can't handle 64-bit BAR\n");
|
||||
goto fail;
|
||||
} else if ((sizeof(resource_size_t) < 8) && l) {
|
||||
/* Address above 32-bit boundary; disable the BAR */
|
||||
pci_write_config_dword(dev, pos, 0);
|
||||
pci_write_config_dword(dev, pos + 4, 0);
|
||||
res->start = 0;
|
||||
res->end = sz64;
|
||||
} else {
|
||||
res->start = l64;
|
||||
res->end = l64 + sz64;
|
||||
}
|
||||
} else {
|
||||
sz = pci_size(l, sz, mask);
|
||||
|
||||
if (!sz)
|
||||
goto fail;
|
||||
|
||||
res->start = l;
|
||||
res->end = l + sz;
|
||||
}
|
||||
|
||||
out:
|
||||
return (type == pci_bar_mem64) ? 1 : 0;
|
||||
fail:
|
||||
res->flags = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
|
||||
{
|
||||
unsigned int pos, reg, next;
|
||||
u32 l, sz;
|
||||
struct resource *res;
|
||||
unsigned int pos, reg;
|
||||
|
||||
for(pos=0; pos<howmany; pos = next) {
|
||||
u64 l64;
|
||||
u64 sz64;
|
||||
u32 raw_sz;
|
||||
|
||||
next = pos+1;
|
||||
res = &dev->resource[pos];
|
||||
res->name = pci_name(dev);
|
||||
for (pos = 0; pos < howmany; pos++) {
|
||||
struct resource *res = &dev->resource[pos];
|
||||
reg = PCI_BASE_ADDRESS_0 + (pos << 2);
|
||||
pci_read_config_dword(dev, reg, &l);
|
||||
pci_write_config_dword(dev, reg, ~0);
|
||||
pci_read_config_dword(dev, reg, &sz);
|
||||
pci_write_config_dword(dev, reg, l);
|
||||
if (!sz || sz == 0xffffffff)
|
||||
continue;
|
||||
if (l == 0xffffffff)
|
||||
l = 0;
|
||||
raw_sz = sz;
|
||||
if ((l & PCI_BASE_ADDRESS_SPACE) ==
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY) {
|
||||
sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
|
||||
/*
|
||||
* For 64bit prefetchable memory sz could be 0, if the
|
||||
* real size is bigger than 4G, so we need to check
|
||||
* szhi for that.
|
||||
*/
|
||||
if (!is_64bit_memory(l) && !sz)
|
||||
continue;
|
||||
res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
|
||||
} else {
|
||||
sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
|
||||
if (!sz)
|
||||
continue;
|
||||
res->start = l & PCI_BASE_ADDRESS_IO_MASK;
|
||||
res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
|
||||
}
|
||||
res->end = res->start + (unsigned long) sz;
|
||||
res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
|
||||
if (is_64bit_memory(l)) {
|
||||
u32 szhi, lhi;
|
||||
|
||||
pci_read_config_dword(dev, reg+4, &lhi);
|
||||
pci_write_config_dword(dev, reg+4, ~0);
|
||||
pci_read_config_dword(dev, reg+4, &szhi);
|
||||
pci_write_config_dword(dev, reg+4, lhi);
|
||||
sz64 = ((u64)szhi << 32) | raw_sz;
|
||||
l64 = ((u64)lhi << 32) | l;
|
||||
sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
|
||||
next++;
|
||||
#if BITS_PER_LONG == 64
|
||||
if (!sz64) {
|
||||
res->start = 0;
|
||||
res->end = 0;
|
||||
res->flags = 0;
|
||||
continue;
|
||||
}
|
||||
res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
res->end = res->start + sz64;
|
||||
#else
|
||||
if (sz64 > 0x100000000ULL) {
|
||||
dev_err(&dev->dev, "BAR %d: can't handle 64-bit"
|
||||
" BAR\n", pos);
|
||||
res->start = 0;
|
||||
res->flags = 0;
|
||||
} else if (lhi) {
|
||||
/* 64-bit wide address, treat as disabled */
|
||||
pci_write_config_dword(dev, reg,
|
||||
l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
|
||||
pci_write_config_dword(dev, reg+4, 0);
|
||||
res->start = 0;
|
||||
res->end = sz;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pos += __pci_read_base(dev, pci_bar_unknown, res, reg);
|
||||
}
|
||||
|
||||
if (rom) {
|
||||
struct resource *res = &dev->resource[PCI_ROM_RESOURCE];
|
||||
dev->rom_base_reg = rom;
|
||||
res = &dev->resource[PCI_ROM_RESOURCE];
|
||||
res->name = pci_name(dev);
|
||||
pci_read_config_dword(dev, rom, &l);
|
||||
pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
|
||||
pci_read_config_dword(dev, rom, &sz);
|
||||
pci_write_config_dword(dev, rom, l);
|
||||
if (l == 0xffffffff)
|
||||
l = 0;
|
||||
if (sz && sz != 0xffffffff) {
|
||||
sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
|
||||
if (sz) {
|
||||
res->flags = (l & IORESOURCE_ROM_ENABLE) |
|
||||
IORESOURCE_MEM | IORESOURCE_PREFETCH |
|
||||
IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
|
||||
IORESOURCE_SIZEALIGN;
|
||||
res->start = l & PCI_ROM_ADDRESS_MASK;
|
||||
res->end = res->start + (unsigned long) sz;
|
||||
}
|
||||
}
|
||||
res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH |
|
||||
IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
|
||||
IORESOURCE_SIZEALIGN;
|
||||
__pci_read_base(dev, pci_bar_mem32, res, rom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1053,7 +1057,8 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
|
|||
}
|
||||
}
|
||||
|
||||
if (bus->self)
|
||||
/* only one slot has pcie device */
|
||||
if (bus->self && nr)
|
||||
pcie_aspm_init_link_state(bus->self);
|
||||
|
||||
return nr;
|
||||
|
|
|
@ -923,6 +923,19 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev)
|
|||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, quirk_ide_samemode);
|
||||
|
||||
/*
|
||||
* Some ATA devices break if put into D3
|
||||
*/
|
||||
|
||||
static void __devinit quirk_no_ata_d3(struct pci_dev *pdev)
|
||||
{
|
||||
/* Quirk the legacy ATA devices only. The AHCI ones are ok */
|
||||
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
|
||||
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3);
|
||||
|
||||
/* This was originally an Alpha specific thing, but it really fits here.
|
||||
* The i82375 PCI/EISA bridge appears as non-classified. Fix that.
|
||||
*/
|
||||
|
|
|
@ -277,6 +277,7 @@ enum acpi_prefered_pm_profiles {
|
|||
#define BAF_LEGACY_DEVICES 0x0001
|
||||
#define BAF_8042_KEYBOARD_CONTROLLER 0x0002
|
||||
#define BAF_MSI_NOT_SUPPORTED 0x0008
|
||||
#define BAF_PCIE_ASPM_CONTROL 0x0010
|
||||
|
||||
#define FADT2_REVISION_ID 3
|
||||
#define FADT2_MINUS_REVISION_ID 2
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <asm-generic/dma-coherent.h>
|
||||
|
||||
/*
|
||||
* DMA-consistent mapping functions. These allocate/free a region of
|
||||
* uncached, unwrite-buffered mapped memory space for use with DMA
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <asm-generic/dma-coherent.h>
|
||||
|
||||
void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag);
|
||||
|
||||
|
|
32
include/asm-generic/dma-coherent.h
Normal file
32
include/asm-generic/dma-coherent.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef DMA_COHERENT_H
|
||||
#define DMA_COHERENT_H
|
||||
|
||||
#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
|
||||
/*
|
||||
* These two functions are only for dma allocator.
|
||||
* Don't use them in device drivers.
|
||||
*/
|
||||
int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||
dma_addr_t *dma_handle, void **ret);
|
||||
int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
|
||||
|
||||
/*
|
||||
* Standard interface
|
||||
*/
|
||||
#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
|
||||
extern int
|
||||
dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags);
|
||||
|
||||
extern void
|
||||
dma_release_declared_memory(struct device *dev);
|
||||
|
||||
extern void *
|
||||
dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size);
|
||||
#else
|
||||
#define dma_alloc_from_coherent(dev, size, handle, ret) (0)
|
||||
#define dma_release_from_coherent(dev, order, vaddr) (0)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/scatterlist.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm-generic/dma-coherent.h>
|
||||
|
||||
extern struct bus_type pci_bus_type;
|
||||
|
||||
|
|
|
@ -249,25 +249,5 @@ static inline int dma_get_cache_alignment(void)
|
|||
|
||||
#define dma_is_consistent(d, h) (1)
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
# define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
|
||||
struct dma_coherent_mem {
|
||||
void *virt_base;
|
||||
u32 device_base;
|
||||
int size;
|
||||
int flags;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
extern int
|
||||
dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags);
|
||||
|
||||
extern void
|
||||
dma_release_declared_memory(struct device *dev);
|
||||
|
||||
extern void *
|
||||
dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size);
|
||||
#endif /* CONFIG_X86_32 */
|
||||
#include <asm-generic/dma-coherent.h>
|
||||
#endif
|
||||
|
|
|
@ -8,3 +8,4 @@ extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
|
|||
unsigned long align_mask);
|
||||
extern void iommu_area_free(unsigned long *map, unsigned long start,
|
||||
unsigned int nr);
|
||||
extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len);
|
||||
|
|
|
@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
|||
extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||
extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
|
||||
extern void pcie_no_aspm(void);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||||
{
|
||||
|
@ -40,6 +41,10 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
|
|||
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void pcie_no_aspm(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */
|
||||
|
|
|
@ -124,6 +124,8 @@ enum pci_dev_flags {
|
|||
* generation too.
|
||||
*/
|
||||
PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1,
|
||||
/* Device configuration is irrevocably lost if disabled into D3 */
|
||||
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
|
||||
};
|
||||
|
||||
typedef unsigned short __bitwise pci_bus_flags_t;
|
||||
|
|
|
@ -374,6 +374,7 @@
|
|||
#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */
|
||||
#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */
|
||||
#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
|
||||
#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */
|
||||
#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
|
||||
#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
|
||||
#define PCI_EXP_DEVCTL 8 /* Device Control */
|
||||
|
|
|
@ -802,6 +802,10 @@ config PROC_PAGE_MONITOR
|
|||
|
||||
endmenu # General setup
|
||||
|
||||
config HAVE_GENERIC_DMA_COHERENT
|
||||
bool
|
||||
default n
|
||||
|
||||
config SLABINFO
|
||||
bool
|
||||
depends on PROC_FS
|
||||
|
|
|
@ -84,6 +84,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
|
|||
obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
|
||||
obj-$(CONFIG_MARKERS) += marker.o
|
||||
obj-$(CONFIG_LATENCYTOP) += latencytop.o
|
||||
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
|
||||
obj-$(CONFIG_FTRACE) += trace/
|
||||
obj-$(CONFIG_TRACING) += trace/
|
||||
obj-$(CONFIG_SMP) += sched_cpupri.o
|
||||
|
|
154
kernel/dma-coherent.c
Normal file
154
kernel/dma-coherent.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Coherent per-device memory handling.
|
||||
* Borrowed from i386
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
struct dma_coherent_mem {
|
||||
void *virt_base;
|
||||
u32 device_base;
|
||||
int size;
|
||||
int flags;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags)
|
||||
{
|
||||
void __iomem *mem_base = NULL;
|
||||
int pages = size >> PAGE_SHIFT;
|
||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
|
||||
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
|
||||
goto out;
|
||||
if (!size)
|
||||
goto out;
|
||||
if (dev->dma_mem)
|
||||
goto out;
|
||||
|
||||
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
||||
|
||||
mem_base = ioremap(bus_addr, size);
|
||||
if (!mem_base)
|
||||
goto out;
|
||||
|
||||
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto out;
|
||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
|
||||
dev->dma_mem->virt_base = mem_base;
|
||||
dev->dma_mem->device_base = device_addr;
|
||||
dev->dma_mem->size = pages;
|
||||
dev->dma_mem->flags = flags;
|
||||
|
||||
if (flags & DMA_MEMORY_MAP)
|
||||
return DMA_MEMORY_MAP;
|
||||
|
||||
return DMA_MEMORY_IO;
|
||||
|
||||
free1_out:
|
||||
kfree(dev->dma_mem);
|
||||
out:
|
||||
if (mem_base)
|
||||
iounmap(mem_base);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
||||
|
||||
void dma_release_declared_memory(struct device *dev)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
dev->dma_mem = NULL;
|
||||
iounmap(mem->virt_base);
|
||||
kfree(mem->bitmap);
|
||||
kfree(mem);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_release_declared_memory);
|
||||
|
||||
void *dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
int pos, err;
|
||||
int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1);
|
||||
|
||||
pages >>= PAGE_SHIFT;
|
||||
|
||||
if (!mem)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
||||
err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
return mem->virt_base + (pos << PAGE_SHIFT);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
|
||||
|
||||
/**
|
||||
* Try to allocate memory from the per-device coherent area.
|
||||
*
|
||||
* @dev: device from which we allocate memory
|
||||
* @size: size of requested memory area
|
||||
* @dma_handle: This will be filled with the correct dma handle
|
||||
* @ret: This pointer will be filled with the virtual address
|
||||
* to allocated area.
|
||||
*
|
||||
* This function should be only called from per-arch %dma_alloc_coherent()
|
||||
* to support allocation from per-device coherent memory pools.
|
||||
*
|
||||
* Returns 0 if dma_alloc_coherent should continue with allocating from
|
||||
* generic memory areas, or !0 if dma_alloc_coherent should return %ret.
|
||||
*/
|
||||
int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||
dma_addr_t *dma_handle, void **ret)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
int order = get_order(size);
|
||||
|
||||
if (mem) {
|
||||
int page = bitmap_find_free_region(mem->bitmap, mem->size,
|
||||
order);
|
||||
if (page >= 0) {
|
||||
*dma_handle = mem->device_base + (page << PAGE_SHIFT);
|
||||
*ret = mem->virt_base + (page << PAGE_SHIFT);
|
||||
memset(*ret, 0, size);
|
||||
} else if (mem->flags & DMA_MEMORY_EXCLUSIVE)
|
||||
*ret = NULL;
|
||||
}
|
||||
return (mem != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to free the memory allocated from per-device coherent memory pool.
|
||||
* @dev: device from which the memory was allocated
|
||||
* @order: the order of pages allocated
|
||||
* @vaddr: virtual address of allocated pages
|
||||
*
|
||||
* This checks whether the memory was allocated from the per-device
|
||||
* coherent memory pool and if so, releases that memory.
|
||||
*
|
||||
* Returns 1 if we correctly released the memory, or 0 if
|
||||
* %dma_release_coherent() should proceed with releasing memory from
|
||||
* generic pools.
|
||||
*/
|
||||
int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
|
||||
if (mem && vaddr >= mem->virt_base && vaddr <
|
||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
|
||||
bitmap_release_region(mem->bitmap, page, order);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -80,3 +80,11 @@ void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
|
|||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iommu_area_free);
|
||||
|
||||
unsigned long iommu_num_pages(unsigned long addr, unsigned long len)
|
||||
{
|
||||
unsigned long size = roundup((addr & ~PAGE_MASK) + len, PAGE_SIZE);
|
||||
|
||||
return size >> PAGE_SHIFT;
|
||||
}
|
||||
EXPORT_SYMBOL(iommu_num_pages);
|
||||
|
|
Loading…
Reference in a new issue