Subject: x86 bus_dmamem_alloc vs BUS_DMA_NOWAIT
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: tech-kern
Date: 11/23/2005 22:55:43
--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,
the x86 bus_dmamem_alloc() doesn't look at the BUS_DMA_NOWAIT when calling
uvm_km_alloc(), as a result, an assertion can be triggered in uvm_map_prepare
if called from interrupt context with BUS_DMA_NOWAIT. For example see this
stack trace sent by John R. Shannon in private mail:
panic: kernel diagnostic assertion "doing_shutdown || curlwp != NULL || (map->flags & VM_MAP_INTRSAFE)" failed: file "/usr/src/sys/uvm/uvm_map.c", line 834
Stopped at      netbsd:cpu_Debugger+0x4:        leave
cpu_Debugger(c058ff80,c058ff80,c051a940,7,7) at netbsd:cpu_Debugger+0x4
panic(c043b6c0,c03dc528,c0422820,c03eab1e,342) at netbsd:panic+0x121
__main(c03dc528,c03eab1e,342,c0422820,c058ff80) at netbsd:__main
uvm_map_prepare(c0469940,c0000000,1000,c04698c0,ffffffff) at netbsd:uvm_map_prepare+0x125
uvm_map(c0469940,c051aa2c,1000,c04698c0,ffffffff) at netbsd:uvm_map+0x7e
uvm_km_valloc1(c0469940,1000,0,ffffffff,ffffffff) at netbsd:uvm_km_valloc1+0x81 
_bus_dmamem_map(c044fdc0,c09cd5ac,1,1000,c09cd5a8) at netbsd:_bus_dmamem_map+0x61
ahd_createdmamem(c044fdc0,1000,1,c09cd5a0,c09cd5a8) at netbsd:ahd_createdmamem+0x59
ahd_alloc_scbs(c084e000,c9d7d,18656063,0,1) at netbsd:ahd_alloc_scbs+0x45f
ahd_get_scb(c084e000,ffff,c0832900,c085b300,c051abb2) at netbsd:ahd_get_scb+0x61
ahd_action(c084e038,0,c07c3940,c0520000,c051ac3c) at netbsd:ahd_action+0x3d9
scsipi_run_queue(c084e038,c07c39d4,c051ac70,c0349e82,c07c3950) at netbsd:scsipi_run_queue+0x1c3
scsipi_execute_xs(c07c3940,1,a,c0520000,2000) at netbsd:scsipi_execute_xs+0x21f 
sdstart(c085b300,c07c7cc0,0,6,c051ad2c) at netbsd:sdstart+0x1fc
sdstrategy(c07c7cc0,c0965680,c051ad90,c039d12e,c07c7d48) at netbsd:sdstrategy+0x1db
xbdback_do_io(c07c7cc0,403,c048fe40,c0965680,c039ccec) at netbsd:xbdback_do_io+0x7b
xbdback_co_flush_done(c0965680,c9d7c000,c051add0,fffffffc,c09cd880) at netbsd:xbdback_co_flush_done+0x12
xbdback_trampoline(c0965680,c0965680,fffffffe,800,e) at netbsd:xbdback_trampoline+0x30
xbdback_evthandler(c0965680,c051ae3c,c051ae04,c051ae10,989680) at netbsd:xbdback_evthandler+0x29
evtchn_do_event(13,c051ae3c,0,3b9a0000,c051ca00) at netbsd:evtchn_do_event+0xdc 
do_hypervisor_callback(c051ae3c,0,3b9a0011,31,11) at netbsd:do_hypervisor_callback+0xb8
hypervisor_callback(c04881a0,0,0,c029aa7d,c0488360) at netbsd:hypervisor_callback+0x64
cpu_switch(c0488360,0,c08abccc,2,c079a300) at netbsd:cpu_switch+0x107
ltsleep(c04881a0,4,c03ff532,0,0) at netbsd:ltsleep+0x40f
uvm_scheduler(c0488180,0,c048c79c,c03e4d1f,1) at netbsd:uvm_scheduler+0x10f
main(0,0,0,0,0) at netbsd:main+0x73d

The attached patch should fix this (just translate BUS_DMA_NOWAIT to
UVM_KMF_NOWAIT). Does it looks right ?

-- 
Manuel Bouyer <bouyer@antioche.eu.org>
     NetBSD: 26 ans d'experience feront toujours la difference
--

--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff

Index: x86/bus_dma.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/bus_dma.c,v
retrieving revision 1.23
diff -u -r1.23 bus_dma.c
--- x86/bus_dma.c	22 Aug 2005 11:09:39 -0000	1.23
+++ x86/bus_dma.c	23 Nov 2005 21:48:49 -0000
@@ -1024,13 +1024,14 @@
 	int nocache;
 	int marked;
 	pt_entry_t *pte;
+	int uflags = (flags & BUS_DMA_NOWAIT) ? UVM_KMF_NOWAIT : 0;
 
 	size = round_page(size);
 	cpumask = 0;
 	nocache = (flags & BUS_DMA_NOCACHE) != 0 && pmap_cpu_has_pg_n();
 	marked = 0;
 
-	va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY);
+	va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | uflags);
 
 	if (va == 0)
 		return (ENOMEM);

--Q68bSM7Ycu6FN28Q--