The kernel''s ISA DMA API is just not fitting virtualization requirements. While I didn''t get a response on a query regarding the change to pnpacpi, I am going to submit both this and the floppy.c change to mainline Linux. This was tested on 2.6.22.1, and only made apply to 2.6.18 without further testing. Signed-off-by: Jan Beulich <jbeulich@novell.com> Index: head-2007-08-07/arch/i386/kernel/setup-xen.c ==================================================================--- head-2007-08-07.orig/arch/i386/kernel/setup-xen.c 2007-08-08 08:33:24.000000000 +0200 +++ head-2007-08-07/arch/i386/kernel/setup-xen.c 2007-08-07 10:40:43.000000000 +0200 @@ -1826,6 +1826,11 @@ void __init setup_arch(char **cmdline_p) virt_to_mfn(pfn_to_mfn_frame_list_list); } + /* Mark all ISA DMA channels in-use - using them wouldn''t work. */ + for (i = 0; i < MAX_DMA_CHANNELS; ++i) + if (i != 4 && request_dma(i, "xen") != 0) + BUG(); + /* * NOTE: at this point the bootmem allocator is fully available. */ Index: head-2007-08-07/arch/x86_64/kernel/setup-xen.c ==================================================================--- head-2007-08-07.orig/arch/x86_64/kernel/setup-xen.c 2007-08-08 08:33:24.000000000 +0200 +++ head-2007-08-07/arch/x86_64/kernel/setup-xen.c 2007-08-07 10:40:43.000000000 +0200 @@ -863,6 +863,10 @@ void __init setup_arch(char **cmdline_p) virt_to_mfn(pfn_to_mfn_frame_list_list); } + /* Mark all ISA DMA channels in-use - using them wouldn''t work. */ + for (i = 0; i < MAX_DMA_CHANNELS; ++i) + if (i != 4 && request_dma(i, "xen") != 0) + BUG(); } if (!is_initial_xendomain()) { Index: head-2007-08-07/drivers/block/floppy.c ==================================================================--- head-2007-08-07.orig/drivers/block/floppy.c 2007-07-09 01:32:17.000000000 +0200 +++ head-2007-08-07/drivers/block/floppy.c 2007-08-07 10:40:43.000000000 +0200 @@ -4397,11 +4397,15 @@ static int floppy_grab_irq_and_dma(void) if (fd_request_dma()) { DPRINT("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA); - fd_free_irq(); - spin_lock_irqsave(&floppy_usage_lock, flags); - usage_count--; - spin_unlock_irqrestore(&floppy_usage_lock, flags); - return -1; + if (can_use_virtual_dma & 2) + use_virtual_dma = can_use_virtual_dma = 1; + if (!(can_use_virtual_dma & 1)) { + fd_free_irq(); + spin_lock_irqsave(&floppy_usage_lock, flags); + usage_count--; + spin_unlock_irqrestore(&floppy_usage_lock, flags); + return -1; + } } for (fdc = 0; fdc < N_FDC; fdc++) { Index: head-2007-08-07/drivers/pnp/manager.c ==================================================================--- head-2007-08-07.orig/drivers/pnp/manager.c 2007-04-26 05:08:32.000000000 +0200 +++ head-2007-08-07/drivers/pnp/manager.c 2007-08-07 10:40:43.000000000 +0200 @@ -168,7 +168,7 @@ static int pnp_assign_irq(struct pnp_dev return 0; } -static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) +static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { resource_size_t *start, *end; unsigned long *flags; @@ -179,18 +179,14 @@ static int pnp_assign_dma(struct pnp_dev 1, 3, 5, 6, 7, 0, 2, 4 }; - if (!dev || !rule) - return -EINVAL; - if (idx >= PNP_MAX_DMA) { pnp_err("More than 2 dmas is incompatible with pnp specifications."); - /* pretend we were successful so at least the manager won''t try again */ - return 1; + return; } /* check if this resource has been manually set, if so skip */ if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) - return 1; + return; start = &dev->res.dma_resource[idx].start; end = &dev->res.dma_resource[idx].end; @@ -200,19 +196,17 @@ static int pnp_assign_dma(struct pnp_dev *flags |= rule->flags | IORESOURCE_DMA; *flags &= ~IORESOURCE_UNSET; - if (!rule->map) { - *flags |= IORESOURCE_DISABLED; - return 1; /* skip disabled resource requests */ - } - for (i = 0; i < 8; i++) { if(rule->map & (1<<xtab[i])) { *start = *end = xtab[i]; if(pnp_check_dma(dev, idx)) - return 1; + return; } } - return 0; +#ifdef MAX_DMA_CHANNELS + *start = *end = MAX_DMA_CHANNELS; +#endif + *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; } /** @@ -331,8 +325,7 @@ static int pnp_assign_resources(struct p irq = irq->next; } while (dma) { - if (!pnp_assign_dma(dev, dma, ndma)) - goto fail; + pnp_assign_dma(dev, dma, ndma); ndma++; dma = dma->next; } @@ -367,8 +360,7 @@ static int pnp_assign_resources(struct p irq = irq->next; } while (dma) { - if (!pnp_assign_dma(dev, dma, ndma)) - goto fail; + pnp_assign_dma(dev, dma, ndma); ndma++; dma = dma->next; } Index: head-2007-08-07/include/asm-i386/mach-xen/asm/floppy.h ==================================================================--- head-2007-08-07.orig/include/asm-i386/mach-xen/asm/floppy.h 2007-08-08 08:33:24.000000000 +0200 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* - * Architecture specific parts of the Floppy driver - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1995 - * - * Modifications for Xen are Copyright (c) 2004, Keir Fraser. - */ -#ifndef __ASM_XEN_I386_FLOPPY_H -#define __ASM_XEN_I386_FLOPPY_H - -#include <linux/vmalloc.h> - -/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */ -#include <asm/dma.h> -#undef MAX_DMA_ADDRESS -#define MAX_DMA_ADDRESS 0 -#define CROSS_64KB(a,s) (0) - -#define fd_inb(port) inb_p(port) -#define fd_outb(value,port) outb_p(value,port) - -#define fd_request_dma() (0) -#define fd_free_dma() ((void)0) -#define fd_enable_irq() enable_irq(FLOPPY_IRQ) -#define fd_disable_irq() disable_irq(FLOPPY_IRQ) -#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) -#define fd_get_dma_residue() (virtual_dma_count + virtual_dma_residue) -#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io) -/* - * Do not use vmalloc/vfree: floppy_release_irq_and_dma() gets called from - * softirq context via motor_off_callback. A generic bug we happen to trigger. - */ -#define fd_dma_mem_alloc(size) __get_free_pages(GFP_KERNEL, get_order(size)) -#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) - -static int virtual_dma_count; -static int virtual_dma_residue; -static char *virtual_dma_addr; -static int virtual_dma_mode; -static int doing_pdma; - -static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) -{ - register unsigned char st; - register int lcount; - register char *lptr; - - if (!doing_pdma) - return floppy_interrupt(irq, dev_id, regs); - - st = 1; - for(lcount=virtual_dma_count, lptr=virtual_dma_addr; - lcount; lcount--, lptr++) { - st=inb(virtual_dma_port+4) & 0xa0 ; - if(st != 0xa0) - break; - if(virtual_dma_mode) - outb_p(*lptr, virtual_dma_port+5); - else - *lptr = inb_p(virtual_dma_port+5); - } - virtual_dma_count = lcount; - virtual_dma_addr = lptr; - st = inb(virtual_dma_port+4); - - if(st == 0x20) - return IRQ_HANDLED; - if(!(st & 0x20)) { - virtual_dma_residue += virtual_dma_count; - virtual_dma_count=0; - doing_pdma = 0; - floppy_interrupt(irq, dev_id, regs); - return IRQ_HANDLED; - } - return IRQ_HANDLED; -} - -static void fd_disable_dma(void) -{ - doing_pdma = 0; - virtual_dma_residue += virtual_dma_count; - virtual_dma_count=0; -} - -static int fd_request_irq(void) -{ - return request_irq(FLOPPY_IRQ, floppy_hardint, - IRQF_DISABLED, "floppy", NULL); -} - -static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) -{ - doing_pdma = 1; - virtual_dma_port = io; - virtual_dma_mode = (mode == DMA_MODE_WRITE); - virtual_dma_addr = addr; - virtual_dma_count = size; - virtual_dma_residue = 0; - return 0; -} - -/* XEN: This trick to force ''virtual DMA'' is from include/asm-m68k/floppy.h. */ -#define FDC1 xen_floppy_init() -static int FDC2 = -1; - -static int xen_floppy_init(void) -{ - use_virtual_dma = 1; - can_use_virtual_dma = 1; - return 0x3f0; -} - -/* - * Floppy types are stored in the rtc''s CMOS RAM and so rtc_lock - * is needed to prevent corrupted CMOS RAM in case "insmod floppy" - * coincides with another rtc CMOS user. Paul G. - */ -#define FLOPPY0_TYPE ({ \ - unsigned long flags; \ - unsigned char val; \ - spin_lock_irqsave(&rtc_lock, flags); \ - val = (CMOS_READ(0x10) >> 4) & 15; \ - spin_unlock_irqrestore(&rtc_lock, flags); \ - val; \ -}) - -#define FLOPPY1_TYPE ({ \ - unsigned long flags; \ - unsigned char val; \ - spin_lock_irqsave(&rtc_lock, flags); \ - val = CMOS_READ(0x10) & 15; \ - spin_unlock_irqrestore(&rtc_lock, flags); \ - val; \ -}) - -#define N_FDC 2 -#define N_DRIVE 8 - -#define FLOPPY_MOTOR_MASK 0xf0 - -#define EXTRA_FLOPPY_PARAMS - -#endif /* __ASM_XEN_I386_FLOPPY_H */ Index: head-2007-08-07/include/asm-i386/mach-xen/asm/io.h ==================================================================--- head-2007-08-07.orig/include/asm-i386/mach-xen/asm/io.h 2007-08-08 08:33:56.000000000 +0200 +++ head-2007-08-07/include/asm-i386/mach-xen/asm/io.h 2007-08-08 08:34:11.000000000 +0200 @@ -152,7 +152,7 @@ extern void bt_iounmap(void *addr, unsig /* * ISA I/O bus memory addresses are 1:1 with the physical address. */ -#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x +#define isa_virt_to_bus(_x) ({ BUG(); virt_to_bus(_x); }) #define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x #define isa_bus_to_virt(_x) (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + (_x)) Index: head-2007-08-07/include/asm-x86_64/mach-xen/asm/floppy.h ==================================================================--- head-2007-08-07.orig/include/asm-x86_64/mach-xen/asm/floppy.h 2007-08-08 08:33:24.000000000 +0200 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,206 +0,0 @@ -/* - * Architecture specific parts of the Floppy driver - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1995 - * - * Modifications for Xen are Copyright (c) 2004, Keir Fraser. - */ -#ifndef __ASM_XEN_X86_64_FLOPPY_H -#define __ASM_XEN_X86_64_FLOPPY_H - -#include <linux/vmalloc.h> - -/* - * The DMA channel used by the floppy controller cannot access data at - * addresses >= 16MB - * - * Went back to the 1MB limit, as some people had problems with the floppy - * driver otherwise. It doesn''t matter much for performance anyway, as most - * floppy accesses go through the track buffer. - */ -#define _CROSS_64KB(a,s,vdma) \ -(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)) - -/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */ -#include <asm/dma.h> -#undef MAX_DMA_ADDRESS -#define MAX_DMA_ADDRESS 0 -#define CROSS_64KB(a,s) (0) - -#define fd_inb(port) inb_p(port) -#define fd_outb(value,port) outb_p(value,port) - -#define fd_request_dma() (0) -#define fd_free_dma() ((void)0) -#define fd_enable_irq() enable_irq(FLOPPY_IRQ) -#define fd_disable_irq() disable_irq(FLOPPY_IRQ) -#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) -#define fd_get_dma_residue() vdma_get_dma_residue(FLOPPY_DMA) -/* - * Do not use vmalloc/vfree: floppy_release_irq_and_dma() gets called from - * softirq context via motor_off_callback. A generic bug we happen to trigger. - */ -#define fd_dma_mem_alloc(size) __get_free_pages(GFP_KERNEL|__GFP_NORETRY, get_order(size)) -#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) -#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io) - -static int virtual_dma_count; -static int virtual_dma_residue; -static char *virtual_dma_addr; -static int virtual_dma_mode; -static int doing_pdma; - -static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) -{ - register unsigned char st; - -#undef TRACE_FLPY_INT - -#ifdef TRACE_FLPY_INT - static int calls=0; - static int bytes=0; - static int dma_wait=0; -#endif - if (!doing_pdma) - return floppy_interrupt(irq, dev_id, regs); - -#ifdef TRACE_FLPY_INT - if(!calls) - bytes = virtual_dma_count; -#endif - - { - register int lcount; - register char *lptr; - - st = 1; - for(lcount=virtual_dma_count, lptr=virtual_dma_addr; - lcount; lcount--, lptr++) { - st=inb(virtual_dma_port+4) & 0xa0 ; - if(st != 0xa0) - break; - if(virtual_dma_mode) - outb_p(*lptr, virtual_dma_port+5); - else - *lptr = inb_p(virtual_dma_port+5); - } - virtual_dma_count = lcount; - virtual_dma_addr = lptr; - st = inb(virtual_dma_port+4); - } - -#ifdef TRACE_FLPY_INT - calls++; -#endif - if(st == 0x20) - return IRQ_HANDLED; - if(!(st & 0x20)) { - virtual_dma_residue += virtual_dma_count; - virtual_dma_count=0; -#ifdef TRACE_FLPY_INT - printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", - virtual_dma_count, virtual_dma_residue, calls, bytes, - dma_wait); - calls = 0; - dma_wait=0; -#endif - doing_pdma = 0; - floppy_interrupt(irq, dev_id, regs); - return IRQ_HANDLED; - } -#ifdef TRACE_FLPY_INT - if(!virtual_dma_count) - dma_wait++; -#endif - return IRQ_HANDLED; -} - -static void fd_disable_dma(void) -{ - doing_pdma = 0; - virtual_dma_residue += virtual_dma_count; - virtual_dma_count=0; -} - -static int vdma_get_dma_residue(unsigned int dummy) -{ - return virtual_dma_count + virtual_dma_residue; -} - - -static int fd_request_irq(void) -{ - return request_irq(FLOPPY_IRQ, floppy_hardint, - IRQF_DISABLED, "floppy", NULL); -} - -#if 0 -static unsigned long vdma_mem_alloc(unsigned long size) -{ - return (unsigned long) vmalloc(size); - -} - -static void vdma_mem_free(unsigned long addr, unsigned long size) -{ - vfree((void *)addr); -} -#endif - -static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) -{ - doing_pdma = 1; - virtual_dma_port = io; - virtual_dma_mode = (mode == DMA_MODE_WRITE); - virtual_dma_addr = addr; - virtual_dma_count = size; - virtual_dma_residue = 0; - return 0; -} - -/* XEN: This trick to force ''virtual DMA'' is from include/asm-m68k/floppy.h. */ -#define FDC1 xen_floppy_init() -static int FDC2 = -1; - -static int xen_floppy_init(void) -{ - use_virtual_dma = 1; - can_use_virtual_dma = 1; - return 0x3f0; -} - -/* - * Floppy types are stored in the rtc''s CMOS RAM and so rtc_lock - * is needed to prevent corrupted CMOS RAM in case "insmod floppy" - * coincides with another rtc CMOS user. Paul G. - */ -#define FLOPPY0_TYPE ({ \ - unsigned long flags; \ - unsigned char val; \ - spin_lock_irqsave(&rtc_lock, flags); \ - val = (CMOS_READ(0x10) >> 4) & 15; \ - spin_unlock_irqrestore(&rtc_lock, flags); \ - val; \ -}) - -#define FLOPPY1_TYPE ({ \ - unsigned long flags; \ - unsigned char val; \ - spin_lock_irqsave(&rtc_lock, flags); \ - val = CMOS_READ(0x10) & 15; \ - spin_unlock_irqrestore(&rtc_lock, flags); \ - val; \ -}) - -#define N_FDC 2 -#define N_DRIVE 8 - -#define FLOPPY_MOTOR_MASK 0xf0 - -#define EXTRA_FLOPPY_PARAMS - -#endif /* __ASM_XEN_X86_64_FLOPPY_H */ Index: head-2007-08-07/include/asm-x86_64/mach-xen/asm/io.h ==================================================================--- head-2007-08-07.orig/include/asm-x86_64/mach-xen/asm/io.h 2007-08-07 10:20:55.000000000 +0200 +++ head-2007-08-07/include/asm-x86_64/mach-xen/asm/io.h 2007-08-07 10:40:43.000000000 +0200 @@ -164,7 +164,7 @@ extern void iounmap(volatile void __iome * ISA I/O bus memory addresses are 1:1 with the physical address. */ -#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x +#define isa_virt_to_bus(_x) ({ BUG(); virt_to_bus(_x); }) #define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x #define isa_bus_to_virt(_x) (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + (_x)) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel