diff --git a/kernel.spec b/kernel.spec index 32faf28..595d79f 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1976,6 +1976,12 @@ fi # || || %changelog +* Sun Jan 09 2011 Michael Young +- reorganize xen.pcifront.fixes.patch to be a combination of + stable/bug-fixes stable/generic and stable/irq.rework for fixes + in the previous stable/bug-fixes plus other fixes + also devel/ttm.pci-api.v3 for some KMS fixes + * Fri Jan 07 2011 Kyle McMartin 2.6.37-2 - drm_i915-check-eDP-encoder-correctly-when-setting-modes.patch reported to fix HP/Sony eDP issues by adamw and airlied. diff --git a/xen.pcifront.fixes.patch b/xen.pcifront.fixes.patch index fef3372..fff6708 100644 --- a/xen.pcifront.fixes.patch +++ b/xen.pcifront.fixes.patch @@ -1,7 +1,7 @@ From d1b758ebc2a82d738092cb42e742470f9d0ea53e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 9 Dec 2010 14:53:29 -0500 -Subject: [PATCH 1/4] xen/irq: Cleanup the find_unbound_irq +Subject: [PATCH 1/6] xen/irq: Cleanup the find_unbound_irq The "find_unbound_irq" is a bit unusual - it allocates virtual IRQ (event channels) in reverse order. This means @@ -58,58 +58,10 @@ index 31af0ac..4d4a23d 100644 1.7.3.4 -From 67b0ea2bdcd781c17bb2d7949b42059c13c8bfb1 Mon Sep 17 00:00:00 2001 -From: Konrad Rzeszutek Wilk -Date: Thu, 9 Dec 2010 15:01:11 -0500 -Subject: [PATCH 2/4] xen/irq: Don't fall over when nr_irqs_gsi > nr_irqs. - -This scenario where the nr_irq_gsi is greater than nr_irqs -is rather strange but lets still try to survive. Make sure -to print a warning so the user wouldn't be surprised in case -things don't work. - -Solves a bootup-crash when booting Xen and Linux under QEMU. - -Signed-off-by: Konrad Rzeszutek Wilk ---- - drivers/xen/events.c | 9 +++++++++ - 1 files changed, 9 insertions(+), 0 deletions(-) - -diff --git a/drivers/xen/events.c b/drivers/xen/events.c -index 4d4a23d..98b7220 100644 ---- a/drivers/xen/events.c -+++ b/drivers/xen/events.c -@@ -411,6 +411,7 @@ static int find_unbound_irq(void) - if (bottom == nr_irqs) - goto no_irqs; - -+retry: - /* This loop starts from the top of IRQ space and goes down. - * We need this b/c if we have a PCI device in a Xen PV guest - * we do not have an IO-APIC (though the backend might have them) -@@ -434,6 +435,14 @@ static int find_unbound_irq(void) - goto no_irqs; - - res = irq_alloc_desc_at(irq, -1); -+ if (res == -EEXIST) { -+ top--; -+ if (bottom > top) -+ printk(KERN_ERR "Eating in GSI/MSI space (%d)!" \ -+ " Your PCI device might not work!\n", top); -+ if (top > NR_IRQS_LEGACY) -+ goto retry; -+ } - - if (WARN_ON(res != irq)) - return -1; --- -1.7.3.4 - - -From 2e9876d91d05d8d76c260b9e525d88ce6216dedd Mon Sep 17 00:00:00 2001 +From 25c95c6ab7b9e257a60ac3eac73fa1acb120c692 Mon Sep 17 00:00:00 2001 From: Kenji Wakamiya Date: Tue, 14 Dec 2010 14:31:36 +0900 -Subject: [PATCH 3/4] xen/manage: fix "xm save -c" issue +Subject: [PATCH 2/6] xen/manage: fix "xm save -c" issue When using 'xm save -c' (which checkpoints the guest) on PV guests, the dpms_resume_end() should be surpressed. It is OK @@ -143,10 +95,206 @@ index db8c4c4..e32b9c0 100644 1.7.3.4 -From f4ae15846ee57116dcddfd71094e211e5cdefecf Mon Sep 17 00:00:00 2001 +From b225ec7d9bd6009b9885b7359b86fe6f46f4ae4c Mon Sep 17 00:00:00 2001 +From: Joe Jin +Date: Fri, 7 Jan 2011 18:17:17 +0800 +Subject: [PATCH 4/6] xen/fb: fix xenfb suspend/resume race. + +When migrating guests over a long period we hit this: + +<1>BUG: unable to handle kernel paging request at 0000000b819fdb98 +<1>IP: [] notify_remote_via_irq+0x13/0x34 +<4>PGD 94b10067 PUD 0 +<0>Oops: 0000 [#1] SMP +.. snip.. +Call Trace: + [] xenfb_send_event+0x5c/0x5e + [] ? xen_restore_fl_direct_end+0x0/0x1 + [] ? _spin_unlock_irqrestore+0x16/0x18 + [] xenfb_refresh+0x1b1/0x1d7 + [] ? sys_imageblit+0x1ac/0x458 + [] xenfb_imageblit+0x2f/0x34 + [] soft_cursor+0x1b5/0x1c8 + [] bit_cursor+0x4b6/0x4d7 + [] ? xen_restore_fl_direct_end+0x0/0x1 + [] ? _spin_unlock_irqrestore+0x16/0x18 + [] ? bit_cursor+0x0/0x4d7 + [] fb_flashcursor+0xff/0x111 + [] ? fb_flashcursor+0x0/0x111 + [] worker_thread+0x14d/0x1ed + [] ? autoremove_wake_function+0x0/0x3d + [] ? _spin_unlock_irqrestore+0x16/0x18 + [] ? worker_thread+0x0/0x1ed + [] kthread+0x6e/0x76 + [] child_rip+0xa/0x20 + [] ? int_ret_from_sys_call+0x7/0x1b + [] ? retint_restore_args+0x5/0x6 + [] ? child_rip+0x0/0x20 +Code: 6b ff 0c 8b 87 a4 db 9f 81 66 85 c0 74 08 0f b7 f8 e8 3b ff ff ff c9 +c3 55 48 89 e5 48 83 ec 10 0f 1f 44 00 00 89 ff 48 6b ff 0c <8b> 87 a4 db 9f +81 66 85 c0 74 14 48 8d 75 f0 0f b7 c0 bf 04 00 +RIP [] notify_remote_via_irq+0x13/0x34 + RSP +CR2: 0000000b819fdb98 +---[ end trace 098b4b74827595d0 ]--- + +The root cause of the panic is the race between the resume and reconnect to the backend. + +Clearing the 'update_wanted' flag of xenfb before disconnecting from the +backend fixes this issue. + +Signed-off-by: Joe Jin +Signed-off-by: Konrad Rzeszutek Wilk +Tested-by: Gurudas Pai +Acked-by: Ian Campbell +Cc: Jeremy Fitzhardinge +Cc: Andrew Morton +--- + drivers/video/xen-fbfront.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c +index 428d273..f92313d 100644 +--- a/drivers/video/xen-fbfront.c ++++ b/drivers/video/xen-fbfront.c +@@ -617,6 +617,8 @@ static int xenfb_connect_backend(struct xenbus_device *dev, + + static void xenfb_disconnect_backend(struct xenfb_info *info) + { ++ /* Prevent xenfb refresh */ ++ info->update_wanted = 0; + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +-- +1.7.3.4 + + +From c837d281ea3bcba81f7cef24bc6d6037be121f02 Mon Sep 17 00:00:00 2001 +From: Joe Jin +Date: Fri, 7 Jan 2011 18:20:54 +0800 +Subject: [PATCH 5/6] xen/fb: fix potential memory leak + +This patch fixes a potential memory leak when xenfb connect to +the backend fails. + +Thanks for Ian's review and comments. + +[v2: reworded the commit message a bit] + +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Joe Jin +Tested-by: Gurudas Pai +Acked-by: Ian Campbell +Cc: Jeremy Fitzhardinge +Cc: Andrew Morton +--- + drivers/video/xen-fbfront.c | 17 +++++++++-------- + 1 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c +index f92313d..95bbd0a 100644 +--- a/drivers/video/xen-fbfront.c ++++ b/drivers/video/xen-fbfront.c +@@ -562,26 +562,24 @@ static void xenfb_init_shared_page(struct xenfb_info *info, + static int xenfb_connect_backend(struct xenbus_device *dev, + struct xenfb_info *info) + { +- int ret, evtchn; ++ int ret, evtchn, irq; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &evtchn); + if (ret) + return ret; +- ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, ++ irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, + 0, dev->devicetype, info); +- if (ret < 0) { ++ if (irq < 0) { + xenbus_free_evtchn(dev, evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); +- return ret; ++ return irq; + } +- info->irq = ret; +- + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); +- return ret; ++ goto unbind_irq; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); +@@ -603,15 +601,18 @@ static int xenfb_connect_backend(struct xenbus_device *dev, + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); +- return ret; ++ goto unbind_irq; + } + + xenbus_switch_state(dev, XenbusStateInitialised); ++ info->irq = irq; + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); ++ unbind_irq: ++ unbind_from_irqhandler(irq, info); + return ret; + } + +-- +1.7.3.4 + + +From 58b70037b6eab3520bd875d352afbefdb3949dd8 Mon Sep 17 00:00:00 2001 +From: Joe Jin +Date: Fri, 7 Jan 2011 14:50:12 +0800 +Subject: [PATCH 6/6] xen/event: validate irq before get evtchn by irq + +When retrieving the event channel number from irq, the irq +number may not be valid under some conditions. + +So far that can be when we suspend/resume and irq ends with -1. +Validate and return sanitized irq and provide diagnostics information. + +[v2: reworded the commit message] +Signed-off-by: Joe Jin +Signed-off-by: Konrad Rzeszutek Wilk +Tested-by: Gurudas Pai +Cc: Ian Campbell +Cc: Jeremy Fitzhardinge +Cc: Andrew Morton +--- + drivers/xen/events.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/drivers/xen/events.c b/drivers/xen/events.c +index 4d4a23d..25ffe12 100644 +--- a/drivers/xen/events.c ++++ b/drivers/xen/events.c +@@ -170,6 +170,9 @@ static struct irq_info *info_for_irq(unsigned irq) + + static unsigned int evtchn_from_irq(unsigned irq) + { ++ if (WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq)) ++ return 0; ++ + return info_for_irq(irq)->evtchn; + } + +-- +1.7.3.4 + +From 2904ed8dd5a748c52caf4d8b09d3d9834b5932fa Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 21 Dec 2010 14:18:48 +0800 -Subject: [PATCH 4/4] apic: Move hypervisor detection of x2apic to hypervisor.h +Subject: [PATCH 1/2] apic: Move hypervisor detection of x2apic to hypervisor.h Then we can reuse it for Xen later. @@ -212,3 +360,778 @@ index 3f838d5..8408f2d 100644 -- 1.7.3.4 + +From d9b8ca8474fd4fdd43ba6d97a4fee8b49b978067 Mon Sep 17 00:00:00 2001 +From: Sheng Yang +Date: Tue, 21 Dec 2010 14:18:49 +0800 +Subject: [PATCH 2/2] xen: HVM X2APIC support + +This patch is similiar to Gleb Natapov's patch for KVM, which enable the +hypervisor to emulate x2apic feature for the guest. By this way, the emulation +of lapic would be simpler with x2apic interface(MSR), and faster. + +[v2: Re-organized 'xen_hvm_need_lapic' per Ian Campbell suggestion] + +Acked-by: Jeremy Fitzhardinge +Signed-off-by: Sheng Yang +Signed-off-by: Konrad Rzeszutek Wilk +--- + arch/x86/include/asm/hypervisor.h | 3 ++ + arch/x86/include/asm/xen/hypervisor.h | 35 +++++++++++++++++++++++++++++++++ + arch/x86/xen/enlighten.c | 31 +++++++++++----------------- + 3 files changed, 50 insertions(+), 19 deletions(-) + +diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h +index 0c6f7af..7a15153 100644 +--- a/arch/x86/include/asm/hypervisor.h ++++ b/arch/x86/include/asm/hypervisor.h +@@ -21,6 +21,7 @@ + #define _ASM_X86_HYPERVISOR_H + + #include ++#include + + extern void init_hypervisor(struct cpuinfo_x86 *c); + extern void init_hypervisor_platform(void); +@@ -53,6 +54,8 @@ static inline bool hypervisor_x2apic_available(void) + { + if (kvm_para_available()) + return true; ++ if (xen_x2apic_para_available()) ++ return true; + return false; + } + +diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h +index 396ff4c..66d0fff 100644 +--- a/arch/x86/include/asm/xen/hypervisor.h ++++ b/arch/x86/include/asm/xen/hypervisor.h +@@ -37,4 +37,39 @@ + extern struct shared_info *HYPERVISOR_shared_info; + extern struct start_info *xen_start_info; + ++#include ++ ++static inline uint32_t xen_cpuid_base(void) ++{ ++ uint32_t base, eax, ebx, ecx, edx; ++ char signature[13]; ++ ++ for (base = 0x40000000; base < 0x40010000; base += 0x100) { ++ cpuid(base, &eax, &ebx, &ecx, &edx); ++ *(uint32_t *)(signature + 0) = ebx; ++ *(uint32_t *)(signature + 4) = ecx; ++ *(uint32_t *)(signature + 8) = edx; ++ signature[12] = 0; ++ ++ if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2)) ++ return base; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_XEN ++extern bool xen_hvm_need_lapic(void); ++ ++static inline bool xen_x2apic_para_available(void) ++{ ++ return xen_hvm_need_lapic(); ++} ++#else ++static inline bool xen_x2apic_para_available(void) ++{ ++ return (xen_cpuid_base() != 0); ++} ++#endif ++ + #endif /* _ASM_X86_XEN_HYPERVISOR_H */ +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 44dcad4..5b8986f 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -1256,25 +1256,6 @@ asmlinkage void __init xen_start_kernel(void) + #endif + } + +-static uint32_t xen_cpuid_base(void) +-{ +- uint32_t base, eax, ebx, ecx, edx; +- char signature[13]; +- +- for (base = 0x40000000; base < 0x40010000; base += 0x100) { +- cpuid(base, &eax, &ebx, &ecx, &edx); +- *(uint32_t *)(signature + 0) = ebx; +- *(uint32_t *)(signature + 4) = ecx; +- *(uint32_t *)(signature + 8) = edx; +- signature[12] = 0; +- +- if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2)) +- return base; +- } +- +- return 0; +-} +- + static int init_hvm_pv_info(int *major, int *minor) + { + uint32_t eax, ebx, ecx, edx, pages, msr, base; +@@ -1384,6 +1365,18 @@ static bool __init xen_hvm_platform(void) + return true; + } + ++bool xen_hvm_need_lapic(void) ++{ ++ if (xen_pv_domain()) ++ return false; ++ if (!xen_hvm_domain()) ++ return false; ++ if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback) ++ return false; ++ return true; ++} ++EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); ++ + const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { + .name = "Xen HVM", + .detect = xen_hvm_platform, +-- +1.7.3.4 + +From 105aad363797212fbd2a4c887b723407c5851175 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Thu, 9 Dec 2010 15:01:11 -0500 +Subject: [PATCH 2/2] xen/irq: Don't fall over when nr_irqs_gsi > nr_irqs. + +This scenario where the nr_irq_gsi is greater than nr_irqs +is rather strange but lets still try to survive. Make sure +to print a warning so the user wouldn't be surprised in case +things don't work. + +Solves a bootup-crash when booting Xen and Linux under QEMU. + +Signed-off-by: Konrad Rzeszutek Wilk +--- + drivers/xen/events.c | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/drivers/xen/events.c b/drivers/xen/events.c +index 4d4a23d..98b7220 100644 +--- a/drivers/xen/events.c ++++ b/drivers/xen/events.c +@@ -411,6 +411,7 @@ static int find_unbound_irq(void) + if (bottom == nr_irqs) + goto no_irqs; + ++retry: + /* This loop starts from the top of IRQ space and goes down. + * We need this b/c if we have a PCI device in a Xen PV guest + * we do not have an IO-APIC (though the backend might have them) +@@ -434,6 +435,14 @@ static int find_unbound_irq(void) + goto no_irqs; + + res = irq_alloc_desc_at(irq, -1); ++ if (res == -EEXIST) { ++ top--; ++ if (bottom > top) ++ printk(KERN_ERR "Eating in GSI/MSI space (%d)!" \ ++ " Your PCI device might not work!\n", top); ++ if (top > NR_IRQS_LEGACY) ++ goto retry; ++ } + + if (WARN_ON(res != irq)) + return -1; +-- +1.7.3.4 + +From 3c6613fb55517f444358d07d2da9d39352d080d9 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Mon, 29 Nov 2010 13:52:18 -0500 +Subject: [PATCH 1/5] ttm: Introduce a placeholder for DMA (bus) addresses. + +This is right now limited to only non-pool constructs. + +Signed-off-by: Konrad Rzeszutek Wilk +--- + drivers/gpu/drm/ttm/ttm_page_alloc.c | 9 ++++++--- + drivers/gpu/drm/ttm/ttm_tt.c | 10 ++++++++-- + include/drm/ttm/ttm_bo_driver.h | 2 ++ + include/drm/ttm/ttm_page_alloc.h | 8 ++++++-- + 4 files changed, 22 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c +index b1e02ff..6859288 100644 +--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c ++++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c +@@ -38,6 +38,7 @@ + #include + #include /* for seq_printf */ + #include ++#include + + #include + +@@ -662,7 +663,8 @@ out: + * cached pages. + */ + int ttm_get_pages(struct list_head *pages, int flags, +- enum ttm_caching_state cstate, unsigned count) ++ enum ttm_caching_state cstate, unsigned count, ++ dma_addr_t *dma_address) + { + struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); + struct page *p = NULL; +@@ -720,7 +722,7 @@ int ttm_get_pages(struct list_head *pages, int flags, + printk(KERN_ERR TTM_PFX + "Failed to allocate extra pages " + "for large request."); +- ttm_put_pages(pages, 0, flags, cstate); ++ ttm_put_pages(pages, 0, flags, cstate, NULL); + return r; + } + } +@@ -731,7 +733,8 @@ int ttm_get_pages(struct list_head *pages, int flags, + + /* Put all pages in pages list to correct pool to wait for reuse */ + void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags, +- enum ttm_caching_state cstate) ++ enum ttm_caching_state cstate, ++ dma_addr_t *dma_address) + { + unsigned long irq_flags; + struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); +diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c +index af789dc..0d39001 100644 +--- a/drivers/gpu/drm/ttm/ttm_tt.c ++++ b/drivers/gpu/drm/ttm/ttm_tt.c +@@ -49,12 +49,16 @@ static int ttm_tt_swapin(struct ttm_tt *ttm); + static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm) + { + ttm->pages = drm_calloc_large(ttm->num_pages, sizeof(*ttm->pages)); ++ ttm->dma_address = drm_calloc_large(ttm->num_pages, ++ sizeof(*ttm->dma_address)); + } + + static void ttm_tt_free_page_directory(struct ttm_tt *ttm) + { + drm_free_large(ttm->pages); + ttm->pages = NULL; ++ drm_free_large(ttm->dma_address); ++ ttm->dma_address = NULL; + } + + static void ttm_tt_free_user_pages(struct ttm_tt *ttm) +@@ -105,7 +109,8 @@ static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index) + + INIT_LIST_HEAD(&h); + +- ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1); ++ ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1, ++ &ttm->dma_address[index]); + + if (ret != 0) + return NULL; +@@ -298,7 +303,8 @@ static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm) + count++; + } + } +- ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state); ++ ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state, ++ ttm->dma_address); + ttm->state = tt_unpopulated; + ttm->first_himem_page = ttm->num_pages; + ttm->last_lomem_page = -1; +diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h +index 8e0c848..6dc4fcc 100644 +--- a/include/drm/ttm/ttm_bo_driver.h ++++ b/include/drm/ttm/ttm_bo_driver.h +@@ -149,6 +149,7 @@ enum ttm_caching_state { + * @swap_storage: Pointer to shmem struct file for swap storage. + * @caching_state: The current caching state of the pages. + * @state: The current binding state of the pages. ++ * @dma_address: The DMA (bus) addresses of the pages (if TTM_PAGE_FLAG_DMA32) + * + * This is a structure holding the pages, caching- and aperture binding + * status for a buffer object that isn't backed by fixed (VRAM / AGP) +@@ -173,6 +174,7 @@ struct ttm_tt { + tt_unbound, + tt_unpopulated, + } state; ++ dma_addr_t *dma_address; + }; + + #define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */ +diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h +index 1168214..8062890 100644 +--- a/include/drm/ttm/ttm_page_alloc.h ++++ b/include/drm/ttm/ttm_page_alloc.h +@@ -36,11 +36,13 @@ + * @flags: ttm flags for page allocation. + * @cstate: ttm caching state for the page. + * @count: number of pages to allocate. ++ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set). + */ + int ttm_get_pages(struct list_head *pages, + int flags, + enum ttm_caching_state cstate, +- unsigned count); ++ unsigned count, ++ dma_addr_t *dma_address); + /** + * Put linked list of pages to pool. + * +@@ -49,11 +51,13 @@ int ttm_get_pages(struct list_head *pages, + * count. + * @flags: ttm flags for page allocation. + * @cstate: ttm caching state. ++ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set). + */ + void ttm_put_pages(struct list_head *pages, + unsigned page_count, + int flags, +- enum ttm_caching_state cstate); ++ enum ttm_caching_state cstate, ++ dma_addr_t *dma_address); + /** + * Initialize pool allocator. + */ +-- +1.7.3.4 + + +From 6ea9ff7ffcfce13d16110c85e002f07b57c8894e Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Mon, 29 Nov 2010 14:03:30 -0500 +Subject: [PATCH 2/5] tm: Utilize the dma_addr_t array for pages that are to in DMA32 pool. + +We only use the "if (pool == NULL)" path for right now. + +Signed-off-by: Konrad Rzeszutek Wilk +--- + drivers/gpu/drm/ttm/ttm_page_alloc.c | 26 +++++++++++++++++++++++--- + 1 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c +index 6859288..5d09677 100644 +--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c ++++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c +@@ -683,14 +683,22 @@ int ttm_get_pages(struct list_head *pages, int flags, + gfp_flags |= GFP_HIGHUSER; + + for (r = 0; r < count; ++r) { +- p = alloc_page(gfp_flags); ++ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) { ++ void *addr; ++ addr = dma_alloc_coherent(NULL, PAGE_SIZE, ++ &dma_address[r], ++ gfp_flags); ++ if (addr == NULL) ++ return -ENOMEM; ++ p = virt_to_page(addr); ++ } else ++ p = alloc_page(gfp_flags); + if (!p) { + + printk(KERN_ERR TTM_PFX + "Unable to allocate page."); + return -ENOMEM; + } +- + list_add(&p->lru, pages); + } + return 0; +@@ -739,12 +747,24 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags, + unsigned long irq_flags; + struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); + struct page *p, *tmp; ++ unsigned r; + + if (pool == NULL) { + /* No pool for this memory type so free the pages */ + ++ r = page_count-1; + list_for_each_entry_safe(p, tmp, pages, lru) { +- __free_page(p); ++ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) { ++ void *addr = page_address(p); ++ WARN_ON(!addr || !dma_address[r]); ++ if (addr) ++ dma_free_coherent(NULL, PAGE_SIZE, ++ addr, ++ dma_address[r]); ++ dma_address[r] = 0; ++ } else ++ __free_page(p); ++ r--; + } + /* Make the pages list empty */ + INIT_LIST_HEAD(pages); +-- +1.7.3.4 + + +From f6d1461c3203cad0655d97674104547f2cc7a624 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Thu, 2 Dec 2010 10:24:13 -0500 +Subject: [PATCH 3/5] ttm: Expand (*populate) to support an array of DMA addresses. + +We pass in the array of ttm pages to be populated in the GART/MM +of the card (or AGP). Patch titled: "ttm: Utilize the dma_addr_t array +for pages that are to in DMA32 pool." uses the DMA API to make those +pages have a proper DMA addresses (in the situation where +page_to_phys or virt_to_phys do not give use the DMA (bus) address). + +Since we are using the DMA API on those pages, we should pass in the +DMA address to this function so it can save it in its proper fields +(later patches use it). + +Signed-off-by: Konrad Rzeszutek Wilk +--- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 3 ++- + drivers/gpu/drm/radeon/radeon_ttm.c | 3 ++- + drivers/gpu/drm/ttm/ttm_agp_backend.c | 3 ++- + drivers/gpu/drm/ttm/ttm_tt.c | 2 +- + drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 3 ++- + include/drm/ttm/ttm_bo_driver.h | 4 +++- + 6 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +index 288baca..edc140a 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +@@ -20,7 +20,8 @@ struct nouveau_sgdma_be { + + static int + nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, +- struct page **pages, struct page *dummy_read_page) ++ struct page **pages, struct page *dummy_read_page, ++ dma_addr_t *dma_addrs) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_device *dev = nvbe->dev; +diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c +index 01c2c73..6f156e9 100644 +--- a/drivers/gpu/drm/radeon/radeon_ttm.c ++++ b/drivers/gpu/drm/radeon/radeon_ttm.c +@@ -655,7 +655,8 @@ struct radeon_ttm_backend { + static int radeon_ttm_backend_populate(struct ttm_backend *backend, + unsigned long num_pages, + struct page **pages, +- struct page *dummy_read_page) ++ struct page *dummy_read_page, ++ dma_addr_t *dma_addrs) + { + struct radeon_ttm_backend *gtt; + +diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c +index f999e36..1c4a72f 100644 +--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c ++++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c +@@ -47,7 +47,8 @@ struct ttm_agp_backend { + + static int ttm_agp_populate(struct ttm_backend *backend, + unsigned long num_pages, struct page **pages, +- struct page *dummy_read_page) ++ struct page *dummy_read_page, ++ dma_addr_t *dma_addrs) + { + struct ttm_agp_backend *agp_be = + container_of(backend, struct ttm_agp_backend, backend); +diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c +index 0d39001..86d5b17 100644 +--- a/drivers/gpu/drm/ttm/ttm_tt.c ++++ b/drivers/gpu/drm/ttm/ttm_tt.c +@@ -169,7 +169,7 @@ int ttm_tt_populate(struct ttm_tt *ttm) + } + + be->func->populate(be, ttm->num_pages, ttm->pages, +- ttm->dummy_read_page); ++ ttm->dummy_read_page, ttm->dma_address); + ttm->state = tt_unbound; + return 0; + } +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +index 80bc37b..87e43e0 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +@@ -102,7 +102,8 @@ struct vmw_ttm_backend { + + static int vmw_ttm_populate(struct ttm_backend *backend, + unsigned long num_pages, struct page **pages, +- struct page *dummy_read_page) ++ struct page *dummy_read_page, ++ dma_addr_t *dma_addrs) + { + struct vmw_ttm_backend *vmw_be = + container_of(backend, struct vmw_ttm_backend, backend); +diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h +index 6dc4fcc..ebcd3dd 100644 +--- a/include/drm/ttm/ttm_bo_driver.h ++++ b/include/drm/ttm/ttm_bo_driver.h +@@ -50,13 +50,15 @@ struct ttm_backend_func { + * @pages: Array of pointers to ttm pages. + * @dummy_read_page: Page to be used instead of NULL pages in the + * array @pages. ++ * @dma_addrs: Array of DMA (bus) address of the ttm pages. + * + * Populate the backend with ttm pages. Depending on the backend, + * it may or may not copy the @pages array. + */ + int (*populate) (struct ttm_backend *backend, + unsigned long num_pages, struct page **pages, +- struct page *dummy_read_page); ++ struct page *dummy_read_page, ++ dma_addr_t *dma_addrs); + /** + * struct ttm_backend_func member clear + * +-- +1.7.3.4 + + +From 2c88605f61ea99179e67e341f0ba4c8e8f356542 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Thu, 2 Dec 2010 11:04:29 -0500 +Subject: [PATCH 4/5] radeon/ttm/PCIe: Use dma_addr if TTM has set it. + +If the TTM layer has used the DMA API to setup pages that are +TTM_PAGE_FLAG_DMA32 (look at patch titled: "ttm: Utilize the dma_addr_t +array for pages that are to in DMA32 pool."), lets use it +when programming the GART in the PCIe type cards. + +This patch skips doing the pci_map_page (and pci_unmap_page) if +there is a DMA addresses passed in for that page. If the dma_address +is zero (or DMA_ERROR_CODE), then we continue on with our old +behaviour. + +Signed-off-by: Konrad Rzeszutek Wilk +--- + drivers/gpu/drm/radeon/radeon.h | 4 ++- + drivers/gpu/drm/radeon/radeon_gart.c | 36 ++++++++++++++++++++++++--------- + drivers/gpu/drm/radeon/radeon_ttm.c | 5 +++- + 3 files changed, 33 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h +index 73f600d..c9bbab9 100644 +--- a/drivers/gpu/drm/radeon/radeon.h ++++ b/drivers/gpu/drm/radeon/radeon.h +@@ -317,6 +317,7 @@ struct radeon_gart { + union radeon_gart_table table; + struct page **pages; + dma_addr_t *pages_addr; ++ bool *ttm_alloced; + bool ready; + }; + +@@ -329,7 +330,8 @@ void radeon_gart_fini(struct radeon_device *rdev); + void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, + int pages); + int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, +- int pages, struct page **pagelist); ++ int pages, struct page **pagelist, ++ dma_addr_t *dma_addr); + + + /* +diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c +index e65b903..4a5ac4b 100644 +--- a/drivers/gpu/drm/radeon/radeon_gart.c ++++ b/drivers/gpu/drm/radeon/radeon_gart.c +@@ -149,8 +149,9 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, + p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); + for (i = 0; i < pages; i++, p++) { + if (rdev->gart.pages[p]) { +- pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], +- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ++ if (!rdev->gart.ttm_alloced[p]) ++ pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], ++ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + rdev->gart.pages[p] = NULL; + rdev->gart.pages_addr[p] = rdev->dummy_page.addr; + page_base = rdev->gart.pages_addr[p]; +@@ -165,7 +166,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, + } + + int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, +- int pages, struct page **pagelist) ++ int pages, struct page **pagelist, dma_addr_t *dma_addr) + { + unsigned t; + unsigned p; +@@ -180,15 +181,22 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, + p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); + + for (i = 0; i < pages; i++, p++) { +- /* we need to support large memory configurations */ +- /* assume that unbind have already been call on the range */ +- rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i], ++ /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32 ++ * is requested. */ ++ if (dma_addr[i] != DMA_ERROR_CODE) { ++ rdev->gart.ttm_alloced[p] = true; ++ rdev->gart.pages_addr[p] = dma_addr[i]; ++ } else { ++ /* we need to support large memory configurations */ ++ /* assume that unbind have already been call on the range */ ++ rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i], + 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); +- if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) { +- /* FIXME: failed to map page (return -ENOMEM?) */ +- radeon_gart_unbind(rdev, offset, pages); +- return -ENOMEM; ++ if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) { ++ /* FIXME: failed to map page (return -ENOMEM?) */ ++ radeon_gart_unbind(rdev, offset, pages); ++ return -ENOMEM; ++ } + } + rdev->gart.pages[p] = pagelist[i]; + page_base = rdev->gart.pages_addr[p]; +@@ -251,6 +259,12 @@ int radeon_gart_init(struct radeon_device *rdev) + radeon_gart_fini(rdev); + return -ENOMEM; + } ++ rdev->gart.ttm_alloced = kzalloc(sizeof(bool) * ++ rdev->gart.num_cpu_pages, GFP_KERNEL); ++ if (rdev->gart.ttm_alloced == NULL) { ++ radeon_gart_fini(rdev); ++ return -ENOMEM; ++ } + /* set GART entry to point to the dummy page by default */ + for (i = 0; i < rdev->gart.num_cpu_pages; i++) { + rdev->gart.pages_addr[i] = rdev->dummy_page.addr; +@@ -267,6 +281,8 @@ void radeon_gart_fini(struct radeon_device *rdev) + rdev->gart.ready = false; + kfree(rdev->gart.pages); + kfree(rdev->gart.pages_addr); ++ kfree(rdev->gart.ttm_alloced); + rdev->gart.pages = NULL; + rdev->gart.pages_addr = NULL; ++ rdev->gart.ttm_alloced = NULL; + } +diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c +index 6f156e9..ca04505 100644 +--- a/drivers/gpu/drm/radeon/radeon_ttm.c ++++ b/drivers/gpu/drm/radeon/radeon_ttm.c +@@ -647,6 +647,7 @@ struct radeon_ttm_backend { + unsigned long num_pages; + struct page **pages; + struct page *dummy_read_page; ++ dma_addr_t *dma_addrs; + bool populated; + bool bound; + unsigned offset; +@@ -662,6 +663,7 @@ static int radeon_ttm_backend_populate(struct ttm_backend *backend, + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + gtt->pages = pages; ++ gtt->dma_addrs = dma_addrs; + gtt->num_pages = num_pages; + gtt->dummy_read_page = dummy_read_page; + gtt->populated = true; +@@ -674,6 +676,7 @@ static void radeon_ttm_backend_clear(struct ttm_backend *backend) + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + gtt->pages = NULL; ++ gtt->dma_addrs = NULL; + gtt->num_pages = 0; + gtt->dummy_read_page = NULL; + gtt->populated = false; +@@ -694,7 +697,7 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend, + gtt->num_pages, bo_mem, backend); + } + r = radeon_gart_bind(gtt->rdev, gtt->offset, +- gtt->num_pages, gtt->pages); ++ gtt->num_pages, gtt->pages, gtt->dma_addrs); + if (r) { + DRM_ERROR("failed to bind %lu pages at 0x%08X\n", + gtt->num_pages, gtt->offset); +-- +1.7.3.4 + + +From b5f054f501d394d6e6064c9227db2927a3014d06 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Thu, 2 Dec 2010 11:36:24 -0500 +Subject: [PATCH 5/5] nouveau/ttm/PCIe: Use dma_addr if TTM has set it. + +If the TTM layer has used the DMA API to setup pages that are +TTM_PAGE_FLAG_DMA32 (look at patch titled: "ttm: Utilize the dma_addr_t +array for pages that are to in DMA32 pool."), lets use it +when programming the GART in the PCIe type cards. + +This patch skips doing the pci_map_page (and pci_unmap_page) if +there is a DMA addresses passed in for that page. If the dma_address +is zero (or DMA_ERROR_CODE), then we continue on with our old +behaviour. + +Signed-off-by: Konrad Rzeszutek Wilk +--- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 28 +++++++++++++++++++++------- + 1 files changed, 21 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +index edc140a..bbdd982 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +@@ -12,6 +12,7 @@ struct nouveau_sgdma_be { + struct drm_device *dev; + + dma_addr_t *pages; ++ bool *ttm_alloced; + unsigned nr_pages; + + unsigned pte_start; +@@ -35,15 +36,25 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, + if (!nvbe->pages) + return -ENOMEM; + ++ nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL); ++ if (!nvbe->ttm_alloced) ++ return -ENOMEM; ++ + nvbe->nr_pages = 0; + while (num_pages--) { +- nvbe->pages[nvbe->nr_pages] = +- pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0, ++ if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) { ++ nvbe->pages[nvbe->nr_pages] = ++ dma_addrs[nvbe->nr_pages]; ++ nvbe->ttm_alloced[nvbe->nr_pages] = true; ++ } else { ++ nvbe->pages[nvbe->nr_pages] = ++ pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); +- if (pci_dma_mapping_error(dev->pdev, +- nvbe->pages[nvbe->nr_pages])) { +- be->func->clear(be); +- return -EFAULT; ++ if (pci_dma_mapping_error(dev->pdev, ++ nvbe->pages[nvbe->nr_pages])) { ++ be->func->clear(be); ++ return -EFAULT; ++ } + } + + nvbe->nr_pages++; +@@ -66,11 +77,14 @@ nouveau_sgdma_clear(struct ttm_backend *be) + be->func->unbind(be); + + while (nvbe->nr_pages--) { +- pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], ++ if (!nvbe->ttm_alloced[nvbe->nr_pages]) ++ pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + } + kfree(nvbe->pages); ++ kfree(nvbe->ttm_alloced); + nvbe->pages = NULL; ++ nvbe->ttm_alloced = NULL; + nvbe->nr_pages = 0; + } + } +-- +1.7.3.4 +