Subject: Re: DVMA
To: Chuck Cranor <chuck@maria.wustl.edu>
From: David Brownlee <D.K.Brownlee@city.ac.uk>
List: port-sparc
Date: 06/06/1995 14:07:34
	You'll have to excuse the dumb suggestion, but maybe dumb
	suggestions can start the seed of a good idea :)

On Tue, 6 Jun 1995, Chuck Cranor wrote:

> hi-
> 
>    i am looking for ideas on how to handle DVMA with VME devices under
> NetBSD/sparc.  here is the problem i am facing:
> 
>    the hardware maps the lower addresses of the VME bus into the kernel
> virtual address space.   VME address zero maps to DVMA_BASE (0xfff00000),
> and the mappings end at DVMA_END (0xfffc0000).   in order to do DMA
> to a VME device, the kernel's buffer must be mapped in that range
> of virtual addresses.   the address given to the hardware is simply
> the kernel virtual address minus DVMA_BASE.  for example, if there was 
> a kernel buffer at KVA 0xfffc8000 then the hardware would see it at
> VME address 0x8000.

	Sorry, is that 0xfff08000 rather than 0xfffc8000?
> 
>    in NetBSD/sparc, DVMA space is mapped by "phys_map" (a vm_map_t
> declared in vm/vm_kern.h).
> 
>    i have written a device driver for the xylogics 7053 VME/SMD disk
> controller ("xd").   all I/O requests come in via the xdstragegy() routine
> in "struct buf *"s.   there are two types of "struct buf *"s that my
> driver understands.    if (bp->b_flags & B_PHYS) != 0, then the buffer
> is from an I/O operation on the raw disk device (e.g. /dev/rxd0a) and
> the buffer is already mapped into DVMA space due to the vmapbuf()
> function in sparc/vm_machdep.c.    if (bp->b_flags & B_PHYS) == 0, then
> the buffer is part of the kernel's "struct buf" array, and is not
> mapped in DVMA space (but is in kernel space).   if that is the case, 
> then it must be mapped into DVMA space before I/O can begin.   also, 
> once I/O is done this mapping must be removed.
> 
>    what I wanted to do was to establish the mapping for the non-B_PHYS
> case before I started I/O and the remove it in the xdintr() routine.
> to test this, I ran a "while (1) ; fsck /dev/rxd0a ; end" in one window
> while doing "iozone" on /dev/xrd1g in another.    I discovered that my 
> scheme didn't work.   the problem was that the "fsck" would do an I/O 
> on the raw device and it would call vmapbuf().   this would cause phys_map 
> to be locked.  in the mean time an xd interrupt would happen (due to 
> the "iozone") and the interrupt routine would try and unmap a buffer 
> while the phys_map was locked by the vmapbuf() call.   this would cause 
> the interrupt to try and go to sleep in lock_write() by calling 
> thread_sleep() [vm/kern_lock.c].   this would cause my system to crash.
> 
>    i solved this problem by protecting all accesses to "phys_map"
> with splbio().   this works just fine.   however, it is unclear to
> me if phys_map can be handled this way.   in fact, pk and theo say 
> that it is unwise to call kmem_free_wakeup() at interrupt time and
> that I should try and to all my memory mappings in the context of a
> process rather than in an interrupt.   for the mapin, this is easy enough
> to do... you just map it in in the top of the strategy routine
> (although this is somewhat wasteful of DVMA space).   however, I am
> not sure what to do with the map out operation.   the map out is triggered
> by an interrupt.  one thing that was suggested was keeping a queue
> of buffers to map out in the device driver's softc structure and then wait
> until a non-interrupt time to do it (e.g. hope that someone calls xdstragegy
> soon?).   that seems pretty ugly to me.  what else can I do?   i'm
> looking for ideas or insight that can help me.
> 
	Please exuse my ignorance here, but I hope you'll allow me to throw
	out a few ideas & excuse the fact I don't know many basic premises.

	Presumably the kernel calls xdstragegy()  which sets everything 
	up & initiates the read request then exits, leaving the process in
	disk wait.
	Sometime later the interrupt of 'data ready' is triggered, which
	transfers the data across & marks the process as runnable.

	Is there a facility for xdstragegy() to mark the process in
	such a way the when it runs again it runs a routine in the
	kernel? xdbuffertidyup(), when then continues the process?

	Just a quick question: Are the buffers double mapped into kernel
	& DVMA space (I said I was ignorant)

	Then again, how big would your original ideas queue get?
	There shouldn't be that many processes waiting on xdstragegy()'s 
	interrupt result- and even if there were the odds are very high
	there would be more disk io coming from someone very soon after to
	clear the queue.

	Final dumb idea: Some DMA implementations on an ISA bus have 'bounce
	buffers' mapped in below 16Mb to permit DMA to those buffers, then
	the result is 'bounced' up above the 16Mb limit (& vica versa).
	You could have a pool of memory permenantly mapped into DVMA, and
	each interrupt routine would grab a block, do the DMA & then copy
	it across into the kernel buffer. The number of bounce buffers
	could be kept very low as there shouldn't be many simultaneous DVMA
	interrupts active...
	Its a permenant overhead of a few (one?) buffers, plus an extra
	memory to memory copy, but its simpler (if less efficient :( ).
	This feels off the mark, but I said it was dumb :)
	
		Thanks for your patience.

			David
  D.K.Brownlee@city.ac.uk (MIME) +44 171 477 8186 {post,host}master (abs) 
 Network Analyst, UCS, City University, Northampton Square, London EC1V 0HB.
   --- Bite and I'll bite back until one of us lies dead and bleeding ---