提交 0670afdf 编写于 作者: L Linus Torvalds

Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6: (27 commits)
  [IA64] swiotlb abstraction (e.g. for Xen)
  [IA64] swiotlb cleanup
  [IA64] make swiotlb use bus_to_virt/virt_to_bus
  [IA64] swiotlb bug fixes
  [IA64] Hook up getcpu system call for IA64
  [IA64] clean up sparsemem memory_present call
  [IA64] show_mem() for IA64 sparsemem NUMA
  [IA64] missing exports hwsw_sync_...
  [IA64] virt_to_page() can be called with NULL arg
  [IA64] alignment bug in ldscript
  [IA64] register memory ranges in a consistent manner
  [IA64] Enable SWIOTLB only when needed
  [IA64-SGI] Check for TIO errors on shub2 Altix
  [IA64] remove bogus prototype ia64_esi_init()
  [IA64] Clear IRQ affinity when unregistered
  [IA64] fix ACPI Kconfig issues
  [IA64] Fix NULL-pointer dereference in ia64_machine_kexec()
  [IA64] find thread for user rbs address
  [IA64] use snprintf() on features field of /proc/cpuinfo
  [IA64] enable singlestep on system call
  ...
......@@ -11,6 +11,8 @@ menu "Processor type and features"
config IA64
bool
select PCI if (!IA64_HP_SIM)
select ACPI if (!IA64_HP_SIM)
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
......@@ -28,7 +30,6 @@ config MMU
config SWIOTLB
bool
default y
config RWSEM_XCHGADD_ALGORITHM
bool
......@@ -84,10 +85,9 @@ choice
config IA64_GENERIC
bool "generic"
select ACPI
select PCI
select NUMA
select ACPI_NUMA
select SWIOTLB
help
This selects the system type of your hardware. A "generic" kernel
will run on any supported IA-64 system. However, if you configure
......@@ -104,6 +104,7 @@ config IA64_GENERIC
config IA64_DIG
bool "DIG-compliant"
select SWIOTLB
config IA64_HP_ZX1
bool "HP-zx1/sx1000"
......@@ -113,6 +114,7 @@ config IA64_HP_ZX1
config IA64_HP_ZX1_SWIOTLB
bool "HP-zx1/sx1000 with software I/O TLB"
select SWIOTLB
help
Build a kernel that runs on HP zx1 and sx1000 systems even when they
have broken PCI devices which cannot DMA to full 32 bits. Apart
......@@ -131,6 +133,7 @@ config IA64_SGI_SN2
config IA64_HP_SIM
bool "Ski-simulator"
select SWIOTLB
endchoice
......
......@@ -192,3 +192,7 @@ EXPORT_SYMBOL(hwsw_unmap_sg);
EXPORT_SYMBOL(hwsw_dma_supported);
EXPORT_SYMBOL(hwsw_alloc_coherent);
EXPORT_SYMBOL(hwsw_free_coherent);
EXPORT_SYMBOL(hwsw_sync_single_for_cpu);
EXPORT_SYMBOL(hwsw_sync_single_for_device);
EXPORT_SYMBOL(hwsw_sync_sg_for_cpu);
EXPORT_SYMBOL(hwsw_sync_sg_for_device);
......@@ -79,6 +79,7 @@ crash_save_this_cpu()
final_note(buf);
}
#ifdef CONFIG_SMP
static int
kdump_wait_cpu_freeze(void)
{
......@@ -91,6 +92,7 @@ kdump_wait_cpu_freeze(void)
}
return 1;
}
#endif
void
machine_crash_shutdown(struct pt_regs *pt)
......@@ -116,6 +118,11 @@ machine_crash_shutdown(struct pt_regs *pt)
static void
machine_kdump_on_init(void)
{
if (!ia64_kimage) {
printk(KERN_NOTICE "machine_kdump_on_init(): "
"kdump not configured\n");
return;
}
local_irq_disable();
kexec_disable_iosapic();
machine_kexec(ia64_kimage);
......@@ -132,11 +139,12 @@ kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
atomic_inc(&kdump_cpu_freezed);
kdump_status[cpuid] = 1;
mb();
if (cpuid == 0) {
for (;;)
cpu_relax();
} else
#ifdef CONFIG_HOTPLUG_CPU
if (cpuid != 0)
ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
#endif
for (;;)
cpu_relax();
}
static int
......
......@@ -9,7 +9,8 @@
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/uaccess.h>
/**
* copy_oldmem_page - copy one page from "oldmem"
......
......@@ -380,7 +380,7 @@ efi_get_pal_addr (void)
#endif
return __va(md->phys_addr);
}
printk(KERN_WARNING "%s: no PAL-code memory-descriptor found",
printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n",
__FUNCTION__);
return NULL;
}
......
......@@ -1610,5 +1610,7 @@ sys_call_table:
data8 sys_sync_file_range // 1300
data8 sys_tee
data8 sys_vmsplice
data8 sys_ni_syscall // reserved for move_pages
data8 sys_getcpu
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
......@@ -925,6 +925,11 @@ iosapic_unregister_intr (unsigned int gsi)
/* Clear the interrupt controller descriptor */
idesc->chip = &no_irq_type;
#ifdef CONFIG_SMP
/* Clear affinity */
cpus_setall(idesc->affinity);
#endif
/* Clear the interrupt information */
memset(&iosapic_intr_info[vector], 0,
sizeof(struct iosapic_intr_info));
......
......@@ -14,6 +14,7 @@
#include <linux/kexec.h>
#include <linux/cpu.h>
#include <linux/irq.h>
#include <linux/efi.h>
#include <asm/mmu_context.h>
#include <asm/setup.h>
#include <asm/delay.h>
......@@ -68,22 +69,10 @@ void machine_kexec_cleanup(struct kimage *image)
{
}
void machine_shutdown(void)
{
int cpu;
for_each_online_cpu(cpu) {
if (cpu != smp_processor_id())
cpu_down(cpu);
}
kexec_disable_iosapic();
}
/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now.
*/
extern void *efi_get_pal_addr(void);
static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
{
struct kimage *image = arg;
......@@ -93,6 +82,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
unsigned long vector;
int ii;
BUG_ON(!image);
if (image->type == KEXEC_TYPE_CRASH) {
crash_save_this_cpu();
current->thread.ksp = (__u64)info->sw - 16;
......@@ -131,6 +121,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
void machine_kexec(struct kimage *image)
{
BUG_ON(!image);
unw_init_running(ia64_machine_kexec, image);
for(;;);
}
......@@ -34,6 +34,7 @@
#include <asm/ia32.h>
#include <asm/irq.h>
#include <asm/kdebug.h>
#include <asm/kexec.h>
#include <asm/pgalloc.h>
#include <asm/processor.h>
#include <asm/sal.h>
......@@ -803,6 +804,21 @@ cpu_halt (void)
ia64_pal_halt(min_power_state);
}
void machine_shutdown(void)
{
#ifdef CONFIG_HOTPLUG_CPU
int cpu;
for_each_online_cpu(cpu) {
if (cpu != smp_processor_id())
cpu_down(cpu);
}
#endif
#ifdef CONFIG_KEXEC
kexec_disable_iosapic();
#endif
}
void
machine_restart (char *restart_cmd)
{
......
......@@ -607,7 +607,7 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr)
*/
list_for_each_safe(this, next, &current->children) {
p = list_entry(this, struct task_struct, sibling);
if (p->mm != mm)
if (p->tgid != child->tgid)
continue;
if (thread_matches(p, addr)) {
child = p;
......@@ -1405,6 +1405,7 @@ ptrace_disable (struct task_struct *child)
struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child));
/* make sure the single step/taken-branch trap bits are not set: */
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child_psr->ss = 0;
child_psr->tb = 0;
}
......@@ -1525,6 +1526,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
* Make sure the single step/taken-branch trap bits
* are not set:
*/
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
ia64_psr(pt)->ss = 0;
ia64_psr(pt)->tb = 0;
......@@ -1556,6 +1558,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
goto out_tsk;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
set_tsk_thread_flag(child, TIF_SINGLESTEP);
if (request == PTRACE_SINGLESTEP) {
ia64_psr(pt)->ss = 1;
} else {
......@@ -1595,13 +1598,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
}
void
static void
syscall_trace (void)
{
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
if (!(current->ptrace & PT_PTRACED))
return;
/*
* The 0x80 provides a way for the tracing parent to
* distinguish between a syscall stop and SIGTRAP delivery.
......@@ -1664,7 +1663,8 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
audit_syscall_exit(success, result);
}
if (test_thread_flag(TIF_SYSCALL_TRACE)
if ((test_thread_flag(TIF_SYSCALL_TRACE)
|| test_thread_flag(TIF_SINGLESTEP))
&& (current->ptrace & PT_PTRACED))
syscall_trace();
}
......@@ -569,34 +569,31 @@ show_cpuinfo (struct seq_file *m, void *v)
{ 1UL << 1, "spontaneous deferral"},
{ 1UL << 2, "16-byte atomic ops" }
};
char features[128], *cp, sep;
char features[128], *cp, *sep;
struct cpuinfo_ia64 *c = v;
unsigned long mask;
unsigned long proc_freq;
int i;
int i, size;
mask = c->features;
/* build the feature string: */
memcpy(features, " standard", 10);
memcpy(features, "standard", 9);
cp = features;
sep = 0;
for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) {
size = sizeof(features);
sep = "";
for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) {
if (mask & feature_bits[i].mask) {
if (sep)
*cp++ = sep;
sep = ',';
*cp++ = ' ';
strcpy(cp, feature_bits[i].feature_name);
cp += strlen(feature_bits[i].feature_name);
cp += snprintf(cp, size, "%s%s", sep,
feature_bits[i].feature_name),
sep = ", ";
mask &= ~feature_bits[i].mask;
size = sizeof(features) - (cp - features);
}
}
if (mask) {
/* print unknown features as a hex value: */
if (sep)
*cp++ = sep;
sprintf(cp, " 0x%lx", mask);
if (mask && size > 1) {
/* print unknown features as a hex value */
snprintf(cp, size, "%s0x%lx", sep, mask);
}
proc_freq = cpufreq_quick_get(cpunum);
......@@ -612,7 +609,7 @@ show_cpuinfo (struct seq_file *m, void *v)
"model name : %s\n"
"revision : %u\n"
"archrev : %u\n"
"features :%s\n" /* don't change this---it _is_ right! */
"features : %s\n"
"cpu number : %lu\n"
"cpu regs : %u\n"
"cpu MHz : %lu.%06lu\n"
......
......@@ -157,6 +157,7 @@ SECTIONS
}
#endif
. = ALIGN(8);
__con_initcall_start = .;
.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET)
{ *(.con_initcall.init) }
......
......@@ -30,47 +30,69 @@ static unsigned long max_gap;
#endif
/**
* show_mem - display a memory statistics summary
* show_mem - give short summary of memory stats
*
* Just walks the pages in the system and describes where they're allocated.
* Shows a simple page count of reserved and used pages in the system.
* For discontig machines, it does this on a per-pgdat basis.
*/
void
show_mem (void)
void show_mem(void)
{
int i, total = 0, reserved = 0;
int shared = 0, cached = 0;
int i, total_reserved = 0;
int total_shared = 0, total_cached = 0;
unsigned long total_present = 0;
pg_data_t *pgdat;
printk(KERN_INFO "Mem-info:\n");
show_free_areas();
printk(KERN_INFO "Free swap: %6ldkB\n",
nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
for (i = 0; i < max_mapnr; i++) {
if (!pfn_valid(i)) {
printk(KERN_INFO "Node memory in pages:\n");
for_each_online_pgdat(pgdat) {
unsigned long present;
unsigned long flags;
int shared = 0, cached = 0, reserved = 0;
pgdat_resize_lock(pgdat, &flags);
present = pgdat->node_present_pages;
for(i = 0; i < pgdat->node_spanned_pages; i++) {
struct page *page;
if (pfn_valid(pgdat->node_start_pfn + i))
page = pfn_to_page(pgdat->node_start_pfn + i);
else {
#ifdef CONFIG_VIRTUAL_MEM_MAP
if (max_gap < LARGE_GAP)
continue;
i = vmemmap_find_next_valid_pfn(0, i) - 1;
if (max_gap < LARGE_GAP)
continue;
#endif
continue;
i = vmemmap_find_next_valid_pfn(pgdat->node_id,
i) - 1;
continue;
}
if (PageReserved(page))
reserved++;
else if (PageSwapCache(page))
cached++;
else if (page_count(page))
shared += page_count(page)-1;
}
total++;
if (PageReserved(mem_map+i))
reserved++;
else if (PageSwapCache(mem_map+i))
cached++;
else if (page_count(mem_map + i))
shared += page_count(mem_map + i) - 1;
pgdat_resize_unlock(pgdat, &flags);
total_present += present;
total_reserved += reserved;
total_cached += cached;
total_shared += shared;
printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, "
"shrd: %10d, swpd: %10d\n", pgdat->node_id,
present, reserved, shared, cached);
}
printk(KERN_INFO "%d pages of RAM\n", total);
printk(KERN_INFO "%d reserved pages\n", reserved);
printk(KERN_INFO "%d pages shared\n", shared);
printk(KERN_INFO "%d pages swap cached\n", cached);
printk(KERN_INFO "%ld pages in page table cache\n",
printk(KERN_INFO "%ld pages of RAM\n", total_present);
printk(KERN_INFO "%d reserved pages\n", total_reserved);
printk(KERN_INFO "%d pages shared\n", total_shared);
printk(KERN_INFO "%d pages swap cached\n", total_cached);
printk(KERN_INFO "Total of %ld pages in page table cache\n",
pgtable_quicklist_total_size());
printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
}
/* physical address where the bootmem map is located */
unsigned long bootmap_start;
......@@ -177,7 +199,7 @@ find_memory (void)
#ifdef CONFIG_CRASH_DUMP
/* If we are doing a crash dump, we still need to know the real mem
* size before original memory map is * reset. */
* size before original memory map is reset. */
saved_max_pfn = max_pfn;
#endif
}
......
......@@ -412,37 +412,6 @@ static void __init memory_less_nodes(void)
return;
}
#ifdef CONFIG_SPARSEMEM
/**
* register_sparse_mem - notify SPARSEMEM that this memory range exists.
* @start: physical start of range
* @end: physical end of range
* @arg: unused
*
* Simply calls SPARSEMEM to register memory section(s).
*/
static int __init register_sparse_mem(unsigned long start, unsigned long end,
void *arg)
{
int nid;
start = __pa(start) >> PAGE_SHIFT;
end = __pa(end) >> PAGE_SHIFT;
nid = early_pfn_to_nid(start);
memory_present(nid, start, end);
return 0;
}
static void __init arch_sparse_init(void)
{
efi_memmap_walk(register_sparse_mem, NULL);
sparse_init();
}
#else
#define arch_sparse_init() do {} while (0)
#endif
/**
* find_memory - walk the EFI memory map and setup the bootmem allocator
*
......@@ -473,6 +442,9 @@ void __init find_memory(void)
node_clear(node, memory_less_mask);
mem_data[node].min_pfn = ~0UL;
}
efi_memmap_walk(register_active_ranges, NULL);
/*
* Initialize the boot memory maps in reverse order since that's
* what the bootmem allocator expects
......@@ -506,6 +478,12 @@ void __init find_memory(void)
max_pfn = max_low_pfn;
find_initrd();
#ifdef CONFIG_CRASH_DUMP
/* If we are doing a crash dump, we still need to know the real mem
* size before original memory map is reset. */
saved_max_pfn = max_pfn;
#endif
}
#ifdef CONFIG_SMP
......@@ -654,7 +632,6 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
{
unsigned long end = start + len;
add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT);
mem_data[node].num_physpages += len >> PAGE_SHIFT;
if (start <= __pa(MAX_DMA_ADDRESS))
mem_data[node].num_dma_physpages +=
......@@ -686,10 +663,11 @@ void __init paging_init(void)
max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
arch_sparse_init();
efi_memmap_walk(filter_rsvd_memory, count_node_pages);
sparse_memory_present_with_active_regions(MAX_NUMNODES);
sparse_init();
#ifdef CONFIG_VIRTUAL_MEM_MAP
vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
sizeof(struct page));
......
......@@ -19,6 +19,7 @@
#include <linux/swap.h>
#include <linux/proc_fs.h>
#include <linux/bitops.h>
#include <linux/kexec.h>
#include <asm/a.out.h>
#include <asm/dma.h>
......@@ -128,6 +129,25 @@ lazy_mmu_prot_update (pte_t pte)
set_bit(PG_arch_1, &page->flags); /* mark page as clean */
}
/*
* Since DMA is i-cache coherent, any (complete) pages that were written via
* DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
* flush them when they get mapped into an executable vm-area.
*/
void
dma_mark_clean(void *addr, size_t size)
{
unsigned long pg_addr, end;
pg_addr = PAGE_ALIGN((unsigned long) addr);
end = (unsigned long) addr + size;
while (pg_addr + PAGE_SIZE <= end) {
struct page *page = virt_to_page(pg_addr);
set_bit(PG_arch_1, &page->flags);
pg_addr += PAGE_SIZE;
}
}
inline void
ia64_set_rbs_bot (void)
{
......@@ -595,13 +615,27 @@ find_largest_hole (u64 start, u64 end, void *arg)
return 0;
}
#endif /* CONFIG_VIRTUAL_MEM_MAP */
int __init
register_active_ranges(u64 start, u64 end, void *arg)
{
add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT);
int nid = paddr_to_nid(__pa(start));
if (nid < 0)
nid = 0;
#ifdef CONFIG_KEXEC
if (start > crashk_res.start && start < crashk_res.end)
start = crashk_res.end;
if (end > crashk_res.start && end < crashk_res.end)
end = crashk_res.start;
#endif
if (start < end)
add_active_range(nid, __pa(start) >> PAGE_SHIFT,
__pa(end) >> PAGE_SHIFT);
return 0;
}
#endif /* CONFIG_VIRTUAL_MEM_MAP */
static int __init
count_reserved_pages (u64 start, u64 end, void *arg)
......
......@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
* Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/types.h>
......@@ -38,12 +38,20 @@ static irqreturn_t hub_eint_handler(int irq, void *arg)
(u64) nasid, 0, 0, 0, 0, 0, 0);
if ((int)ret_stuff.v0)
panic("hubii_eint_handler(): Fatal TIO Error");
panic("%s: Fatal %s Error", __FUNCTION__,
((nasid & 1) ? "TIO" : "HUBII"));
if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
(void)hubiio_crb_error_handler(hubdev_info);
} else
bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
} else
if (nasid & 1) { /* TIO errors */
SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
(u64) nasid, 0, 0, 0, 0, 0, 0);
if ((int)ret_stuff.v0)
panic("%s: Fatal TIO Error", __FUNCTION__);
} else
bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
return IRQ_HANDLED;
}
......
......@@ -29,7 +29,7 @@ struct dma_mapping_ops swiotlb_dma_ops = {
.dma_supported = NULL,
};
void pci_swiotlb_init(void)
void __init pci_swiotlb_init(void)
{
/* don't initialize swiotlb if iommu=off (no_iommu=1) */
if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN)
......
......@@ -19,4 +19,6 @@ extern unsigned long MAX_DMA_ADDRESS;
#define free_dma(x)
void dma_mark_clean(void *addr, size_t size);
#endif /* _ASM_IA64_DMA_H */
......@@ -19,7 +19,6 @@ enum esi_proc_type {
ESI_PROC_REENTRANT /* MP-safe and reentrant */
};
extern int ia64_esi_init (void);
extern struct ia64_sal_retval esi_call_phys (void *, u64 *);
extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *,
enum esi_proc_type,
......
......@@ -51,12 +51,13 @@ extern void efi_memmap_init(unsigned long *, unsigned long *);
#define IGNORE_PFN0 1 /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
extern int register_active_ranges(u64 start, u64 end, void *arg);
#ifdef CONFIG_VIRTUAL_MEM_MAP
# define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */
extern unsigned long vmalloc_end;
extern struct page *vmem_map;
extern int find_largest_hole (u64 start, u64 end, void *arg);
extern int register_active_ranges (u64 start, u64 end, void *arg);
extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
extern int vmemmap_find_next_valid_pfn(int, int);
#else
......
......@@ -137,7 +137,8 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte)
static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long addr)
{
return virt_to_page(pgtable_quicklist_alloc());
void *pg = pgtable_quicklist_alloc();
return pg ? virt_to_page(pg) : NULL;
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
......
#ifndef _ASM_SWIOTLB_H
#define _ASM_SWIOTLB_H 1
#include <asm/machvec.h>
#define SWIOTLB_ARCH_NEED_LATE_INIT
#define SWIOTLB_ARCH_NEED_ALLOC
#endif /* _ASM_SWIOTLB_H */
......@@ -84,6 +84,7 @@ struct thread_info {
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_SYSCALL_TRACE 3 /* syscall trace active */
#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */
#define TIF_SINGLESTEP 5 /* restore singlestep on return to user mode */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17
#define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */
......@@ -92,7 +93,8 @@ struct thread_info {
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
......
......@@ -291,11 +291,13 @@
#define __NR_sync_file_range 1300
#define __NR_tee 1301
#define __NR_vmsplice 1302
/* 1303 reserved for move_pages */
#define __NR_getcpu 1304
#ifdef __KERNEL__
#define NR_syscalls 279 /* length of syscall table */
#define NR_syscalls 281 /* length of syscall table */
#define __ARCH_WANT_SYS_RT_SIGACTION
......
#ifndef _ASM_SWIOTLB_H
#define _ASM_SWTIOLB_H 1
#define _ASM_SWIOTLB_H 1
#include <asm/dma-mapping.h>
......@@ -45,6 +44,7 @@ extern void swiotlb_init(void);
extern int swiotlb_force;
#ifdef CONFIG_SWIOTLB
#define SWIOTLB_ARCH_NEED_ALLOC
extern int swiotlb;
#else
#define swiotlb 0
......@@ -52,4 +52,6 @@ extern int swiotlb;
extern void pci_swiotlb_init(void);
#endif /* _ASM_SWTIOLB_H */
static inline void dma_mark_clean(void *addr, size_t size) {}
#endif /* _ASM_SWIOTLB_H */
/*
* Dynamic DMA mapping support.
*
* This implementation is for IA-64 and EM64T platforms that do not support
* This implementation is a fallback for platforms that do not support
* I/O TLBs (aka DMA address translation hardware).
* Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
* Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
......@@ -28,6 +28,7 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/scatterlist.h>
#include <asm/swiotlb.h>
#include <linux/init.h>
#include <linux/bootmem.h>
......@@ -35,8 +36,10 @@
#define OFFSET(val,align) ((unsigned long) \
( (val) & ( (align) - 1)))
#ifndef SG_ENT_VIRT_ADDRESS
#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset)
#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
#define SG_ENT_PHYS_ADDRESS(sg) virt_to_bus(SG_ENT_VIRT_ADDRESS(sg))
#endif
/*
* Maximum allowable number of contiguous slabs to map,
......@@ -101,13 +104,25 @@ static unsigned int io_tlb_index;
* We need to save away the original address corresponding to a mapped entry
* for the sync operations.
*/
static unsigned char **io_tlb_orig_addr;
#ifndef SWIOTLB_ARCH_HAS_IO_TLB_ADDR_T
typedef char *io_tlb_addr_t;
#define swiotlb_orig_addr_null(buffer) (!(buffer))
#define ptr_to_io_tlb_addr(ptr) (ptr)
#define page_to_io_tlb_addr(pg, off) (page_address(pg) + (off))
#define sg_to_io_tlb_addr(sg) SG_ENT_VIRT_ADDRESS(sg)
#endif
static io_tlb_addr_t *io_tlb_orig_addr;
/*
* Protect the above data structures in the map and unmap calls
*/
static DEFINE_SPINLOCK(io_tlb_lock);
#ifdef SWIOTLB_EXTRA_VARIABLES
SWIOTLB_EXTRA_VARIABLES;
#endif
#ifndef SWIOTLB_ARCH_HAS_SETUP_IO_TLB_NPAGES
static int __init
setup_io_tlb_npages(char *str)
{
......@@ -122,30 +137,50 @@ setup_io_tlb_npages(char *str)
swiotlb_force = 1;
return 1;
}
#endif
__setup("swiotlb=", setup_io_tlb_npages);
/* make io_tlb_overflow tunable too? */
#ifndef swiotlb_adjust_size
#define swiotlb_adjust_size(size) ((void)0)
#endif
#ifndef swiotlb_adjust_seg
#define swiotlb_adjust_seg(start, size) ((void)0)
#endif
#ifndef swiotlb_print_info
#define swiotlb_print_info(bytes) \
printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " \
"0x%lx\n", bytes >> 20, \
virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end))
#endif
/*
* Statically reserve bounce buffer space and initialize bounce buffer data
* structures for the software IO TLB used to implement the DMA API.
*/
void
swiotlb_init_with_default_size (size_t default_size)
void __init
swiotlb_init_with_default_size(size_t default_size)
{
unsigned long i;
unsigned long i, bytes;
if (!io_tlb_nslabs) {
io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
swiotlb_adjust_size(io_tlb_nslabs);
swiotlb_adjust_size(io_tlb_overflow);
bytes = io_tlb_nslabs << IO_TLB_SHIFT;
/*
* Get IO TLB memory from the low pages
*/
io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
io_tlb_start = alloc_bootmem_low_pages(bytes);
if (!io_tlb_start)
panic("Cannot allocate SWIOTLB buffer");
io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
io_tlb_end = io_tlb_start + bytes;
/*
* Allocate and initialize the free list array. This array is used
......@@ -153,34 +188,45 @@ swiotlb_init_with_default_size (size_t default_size)
* between io_tlb_start and io_tlb_end.
*/
io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
for (i = 0; i < io_tlb_nslabs; i++)
for (i = 0; i < io_tlb_nslabs; i++) {
if ( !(i % IO_TLB_SEGSIZE) )
swiotlb_adjust_seg(io_tlb_start + (i << IO_TLB_SHIFT),
IO_TLB_SEGSIZE << IO_TLB_SHIFT);
io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
}
io_tlb_index = 0;
io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(io_tlb_addr_t));
/*
* Get the overflow emergency buffer
*/
io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n",
virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
if (!io_tlb_overflow_buffer)
panic("Cannot allocate SWIOTLB overflow buffer!\n");
swiotlb_adjust_seg(io_tlb_overflow_buffer, io_tlb_overflow);
swiotlb_print_info(bytes);
}
#ifndef __swiotlb_init_with_default_size
#define __swiotlb_init_with_default_size swiotlb_init_with_default_size
#endif
void
swiotlb_init (void)
void __init
swiotlb_init(void)
{
swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
__swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
}
#ifdef SWIOTLB_ARCH_NEED_LATE_INIT
/*
* Systems with larger DMA zones (those that don't support ISA) can
* initialize the swiotlb later using the slab allocator if needed.
* This should be just like above, but with some error catching.
*/
int
swiotlb_late_init_with_default_size (size_t default_size)
swiotlb_late_init_with_default_size(size_t default_size)
{
unsigned long i, req_nslabs = io_tlb_nslabs;
unsigned long i, bytes, req_nslabs = io_tlb_nslabs;
unsigned int order;
if (!io_tlb_nslabs) {
......@@ -191,8 +237,9 @@ swiotlb_late_init_with_default_size (size_t default_size)
/*
* Get IO TLB memory from the low pages
*/
order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
order = get_order(io_tlb_nslabs << IO_TLB_SHIFT);
io_tlb_nslabs = SLABS_PER_PAGE << order;
bytes = io_tlb_nslabs << IO_TLB_SHIFT;
while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
......@@ -205,13 +252,14 @@ swiotlb_late_init_with_default_size (size_t default_size)
if (!io_tlb_start)
goto cleanup1;
if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) {
if (order != get_order(bytes)) {
printk(KERN_WARNING "Warning: only able to allocate %ld MB "
"for software IO TLB\n", (PAGE_SIZE << order) >> 20);
io_tlb_nslabs = SLABS_PER_PAGE << order;
bytes = io_tlb_nslabs << IO_TLB_SHIFT;
}
io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT));
io_tlb_end = io_tlb_start + bytes;
memset(io_tlb_start, 0, bytes);
/*
* Allocate and initialize the free list array. This array is used
......@@ -227,12 +275,12 @@ swiotlb_late_init_with_default_size (size_t default_size)
io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
io_tlb_index = 0;
io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL,
get_order(io_tlb_nslabs * sizeof(char *)));
io_tlb_orig_addr = (io_tlb_addr_t *)__get_free_pages(GFP_KERNEL,
get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
if (!io_tlb_orig_addr)
goto cleanup3;
memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *));
memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(io_tlb_addr_t));
/*
* Get the overflow emergency buffer
......@@ -242,29 +290,29 @@ swiotlb_late_init_with_default_size (size_t default_size)
if (!io_tlb_overflow_buffer)
goto cleanup4;
printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - "
"0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20,
virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
swiotlb_print_info(bytes);
return 0;
cleanup4:
free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs *
sizeof(char *)));
free_pages((unsigned long)io_tlb_orig_addr,
get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
io_tlb_orig_addr = NULL;
cleanup3:
free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
sizeof(int)));
free_pages((unsigned long)io_tlb_list,
get_order(io_tlb_nslabs * sizeof(int)));
io_tlb_list = NULL;
io_tlb_end = NULL;
cleanup2:
io_tlb_end = NULL;
free_pages((unsigned long)io_tlb_start, order);
io_tlb_start = NULL;
cleanup1:
io_tlb_nslabs = req_nslabs;
return -ENOMEM;
}
#endif
#ifndef SWIOTLB_ARCH_HAS_NEEDS_MAPPING
static inline int
address_needs_mapping(struct device *hwdev, dma_addr_t addr)
{
......@@ -275,11 +323,35 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr)
return (addr & ~mask) != 0;
}
static inline int range_needs_mapping(const void *ptr, size_t size)
{
return swiotlb_force;
}
static inline int order_needs_mapping(unsigned int order)
{
return 0;
}
#endif
static void
__sync_single(io_tlb_addr_t buffer, char *dma_addr, size_t size, int dir)
{
#ifndef SWIOTLB_ARCH_HAS_SYNC_SINGLE
if (dir == DMA_TO_DEVICE)
memcpy(dma_addr, buffer, size);
else
memcpy(buffer, dma_addr, size);
#else
__swiotlb_arch_sync_single(buffer, dma_addr, size, dir);
#endif
}
/*
* Allocates bounce buffer and returns its kernel virtual address.
*/
static void *
map_single(struct device *hwdev, char *buffer, size_t size, int dir)
map_single(struct device *hwdev, io_tlb_addr_t buffer, size_t size, int dir)
{
unsigned long flags;
char *dma_addr;
......@@ -352,7 +424,7 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
*/
io_tlb_orig_addr[index] = buffer;
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
memcpy(dma_addr, buffer, size);
__sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
return dma_addr;
}
......@@ -366,17 +438,18 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
unsigned long flags;
int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
char *buffer = io_tlb_orig_addr[index];
io_tlb_addr_t buffer = io_tlb_orig_addr[index];
/*
* First, sync the memory before unmapping the entry
*/
if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
if (!swiotlb_orig_addr_null(buffer)
&& ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
/*
* bounce... copy the data back into the original buffer * and
* delete the bounce buffer.
*/
memcpy(buffer, dma_addr, size);
__sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
/*
* Return the buffer to the free list by setting the corresponding
......@@ -409,18 +482,18 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
int dir, int target)
{
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
char *buffer = io_tlb_orig_addr[index];
io_tlb_addr_t buffer = io_tlb_orig_addr[index];
switch (target) {
case SYNC_FOR_CPU:
if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
memcpy(buffer, dma_addr, size);
__sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
else
BUG_ON(dir != DMA_TO_DEVICE);
break;
case SYNC_FOR_DEVICE:
if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
memcpy(dma_addr, buffer, size);
__sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
else
BUG_ON(dir != DMA_FROM_DEVICE);
break;
......@@ -429,11 +502,13 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
}
}
#ifdef SWIOTLB_ARCH_NEED_ALLOC
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags)
{
unsigned long dev_addr;
dma_addr_t dev_addr;
void *ret;
int order = get_order(size);
......@@ -444,8 +519,11 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
*/
flags |= GFP_DMA;
ret = (void *)__get_free_pages(flags, order);
if (ret && address_needs_mapping(hwdev, virt_to_phys(ret))) {
if (!order_needs_mapping(order))
ret = (void *)__get_free_pages(flags, order);
else
ret = NULL;
if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) {
/*
* The allocated memory isn't reachable by the device.
* Fall back on swiotlb_map_single().
......@@ -465,22 +543,24 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
if (swiotlb_dma_mapping_error(handle))
return NULL;
ret = phys_to_virt(handle);
ret = bus_to_virt(handle);
}
memset(ret, 0, size);
dev_addr = virt_to_phys(ret);
dev_addr = virt_to_bus(ret);
/* Confirm address can be DMA'd by device */
if (address_needs_mapping(hwdev, dev_addr)) {
printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016lx\n",
(unsigned long long)*hwdev->dma_mask, dev_addr);
printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
(unsigned long long)*hwdev->dma_mask,
(unsigned long long)dev_addr);
panic("swiotlb_alloc_coherent: allocated memory is out of "
"range for device");
}
*dma_handle = dev_addr;
return ret;
}
EXPORT_SYMBOL(swiotlb_alloc_coherent);
void
swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
......@@ -493,6 +573,9 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE);
}
EXPORT_SYMBOL(swiotlb_free_coherent);
#endif
static void
swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
......@@ -504,7 +587,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
* When the mapping is small enough return a static buffer to limit
* the damage, or panic when the transfer is too big.
*/
printk(KERN_ERR "DMA: Out of SW-IOMMU space for %lu bytes at "
printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at "
"device %s\n", size, dev ? dev->bus_id : "?");
if (size > io_tlb_overflow && do_panic) {
......@@ -525,7 +608,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
dma_addr_t
swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
{
unsigned long dev_addr = virt_to_phys(ptr);
dma_addr_t dev_addr = virt_to_bus(ptr);
void *map;
BUG_ON(dir == DMA_NONE);
......@@ -534,19 +617,20 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
* we can safely return the device addr and not worry about bounce
* buffering it.
*/
if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force)
if (!range_needs_mapping(ptr, size)
&& !address_needs_mapping(hwdev, dev_addr))
return dev_addr;
/*
* Oh well, have to allocate and map a bounce buffer.
*/
map = map_single(hwdev, ptr, size, dir);
map = map_single(hwdev, ptr_to_io_tlb_addr(ptr), size, dir);
if (!map) {
swiotlb_full(hwdev, size, dir, 1);
map = io_tlb_overflow_buffer;
}
dev_addr = virt_to_phys(map);
dev_addr = virt_to_bus(map);
/*
* Ensure that the address returned is DMA'ble
......@@ -557,25 +641,6 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
return dev_addr;
}
/*
* Since DMA is i-cache coherent, any (complete) pages that were written via
* DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
* flush them when they get mapped into an executable vm-area.
*/
static void
mark_clean(void *addr, size_t size)
{
unsigned long pg_addr, end;
pg_addr = PAGE_ALIGN((unsigned long) addr);
end = (unsigned long) addr + size;
while (pg_addr + PAGE_SIZE <= end) {
struct page *page = virt_to_page(pg_addr);
set_bit(PG_arch_1, &page->flags);
pg_addr += PAGE_SIZE;
}
}
/*
* Unmap a single streaming mode DMA translation. The dma_addr and size must
* match what was provided for in a previous swiotlb_map_single call. All
......@@ -588,13 +653,13 @@ void
swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
int dir)
{
char *dma_addr = phys_to_virt(dev_addr);
char *dma_addr = bus_to_virt(dev_addr);
BUG_ON(dir == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
unmap_single(hwdev, dma_addr, size, dir);
else if (dir == DMA_FROM_DEVICE)
mark_clean(dma_addr, size);
dma_mark_clean(dma_addr, size);
}
/*
......@@ -611,13 +676,13 @@ static inline void
swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
size_t size, int dir, int target)
{
char *dma_addr = phys_to_virt(dev_addr);
char *dma_addr = bus_to_virt(dev_addr);
BUG_ON(dir == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
sync_single(hwdev, dma_addr, size, dir, target);
else if (dir == DMA_FROM_DEVICE)
mark_clean(dma_addr, size);
dma_mark_clean(dma_addr, size);
}
void
......@@ -642,13 +707,13 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
unsigned long offset, size_t size,
int dir, int target)
{
char *dma_addr = phys_to_virt(dev_addr) + offset;
char *dma_addr = bus_to_virt(dev_addr) + offset;
BUG_ON(dir == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
sync_single(hwdev, dma_addr, size, dir, target);
else if (dir == DMA_FROM_DEVICE)
mark_clean(dma_addr, size);
dma_mark_clean(dma_addr, size);
}
void
......@@ -687,18 +752,16 @@ int
swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
int dir)
{
void *addr;
unsigned long dev_addr;
dma_addr_t dev_addr;
int i;
BUG_ON(dir == DMA_NONE);
for (i = 0; i < nelems; i++, sg++) {
addr = SG_ENT_VIRT_ADDRESS(sg);
dev_addr = virt_to_phys(addr);
if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) {
void *map = map_single(hwdev, addr, sg->length, dir);
sg->dma_address = virt_to_bus(map);
dev_addr = SG_ENT_PHYS_ADDRESS(sg);
if (range_needs_mapping(SG_ENT_VIRT_ADDRESS(sg), sg->length)
|| address_needs_mapping(hwdev, dev_addr)) {
void *map = map_single(hwdev, sg_to_io_tlb_addr(sg), sg->length, dir);
if (!map) {
/* Don't panic here, we expect map_sg users
to do proper error handling. */
......@@ -707,6 +770,7 @@ swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
sg[0].dma_length = 0;
return 0;
}
sg->dma_address = virt_to_bus(map);
} else
sg->dma_address = dev_addr;
sg->dma_length = sg->length;
......@@ -728,9 +792,10 @@ swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
for (i = 0; i < nelems; i++, sg++)
if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir);
unmap_single(hwdev, bus_to_virt(sg->dma_address),
sg->dma_length, dir);
else if (dir == DMA_FROM_DEVICE)
mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
}
/*
......@@ -750,8 +815,10 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sg,
for (i = 0; i < nelems; i++, sg++)
if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
sync_single(hwdev, (void *) sg->dma_address,
sync_single(hwdev, bus_to_virt(sg->dma_address),
sg->dma_length, dir, target);
else if (dir == DMA_FROM_DEVICE)
dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
}
void
......@@ -768,10 +835,48 @@ swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
}
#ifdef SWIOTLB_ARCH_NEED_MAP_PAGE
dma_addr_t
swiotlb_map_page(struct device *hwdev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction direction)
{
dma_addr_t dev_addr;
char *map;
dev_addr = page_to_bus(page) + offset;
if (address_needs_mapping(hwdev, dev_addr)) {
map = map_single(hwdev, page_to_io_tlb_addr(page, offset), size, direction);
if (!map) {
swiotlb_full(hwdev, size, direction, 1);
map = io_tlb_overflow_buffer;
}
dev_addr = virt_to_bus(map);
}
return dev_addr;
}
void
swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction direction)
{
char *dma_addr = bus_to_virt(dev_addr);
BUG_ON(direction == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
unmap_single(hwdev, dma_addr, size, direction);
else if (direction == DMA_FROM_DEVICE)
dma_mark_clean(dma_addr, size);
}
#endif
int
swiotlb_dma_mapping_error(dma_addr_t dma_addr)
{
return (dma_addr == virt_to_phys(io_tlb_overflow_buffer));
return (dma_addr == virt_to_bus(io_tlb_overflow_buffer));
}
/*
......@@ -780,10 +885,13 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr)
* during bus mastering, then you would pass 0x00ffffff as the mask to
* this function.
*/
#ifndef __swiotlb_dma_supported
#define __swiotlb_dma_supported(hwdev, mask) (virt_to_bus(io_tlb_end - 1) <= (mask))
#endif
int
swiotlb_dma_supported (struct device *hwdev, u64 mask)
swiotlb_dma_supported(struct device *hwdev, u64 mask)
{
return (virt_to_phys (io_tlb_end) - 1) <= mask;
return __swiotlb_dma_supported(hwdev, mask);
}
EXPORT_SYMBOL(swiotlb_init);
......@@ -798,6 +906,4 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
EXPORT_SYMBOL(swiotlb_dma_mapping_error);
EXPORT_SYMBOL(swiotlb_alloc_coherent);
EXPORT_SYMBOL(swiotlb_free_coherent);
EXPORT_SYMBOL(swiotlb_dma_supported);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册