Subject: Re: vme device configuration on sparc
To: Paul Kranenburg , Jason Thorpe <thorpej@nas.nasa.gov>
From: Matthias Drochner <drochner@zelux6.zel.kfa-juelich.de>
List: port-sparc
Date: 06/17/1997 15:33:13
Since the VME framework thread seems to trickle away again,
I'll throw in something constructive: a <sys/dev/vmevar.h>
which defines what I consider necessary for a generic VME
interface.
Not that I want to hard-sell my solution here, nor that I'm
desperately looking for more work... it's perhaps a starting point
and a base for discussion. 
The DMA framework used here is not exactly Jason's, but
it's structure is similar (it's derived from an early draft).

I know that a limited kernel stack is an argument against too
much call nesting. This is perhaps a weakness in the layout
of the mapping functions here. I haven't a better idea which
still allows to pass the bus dependant parameters.

Comments?

best regards
Matthias



#ifndef _vmevar_h_
#define _vmevar_h_

typedef u_int32_t vme_addr_t, vme_size_t;
typedef int vme_am_t;

typedef enum {
	VME_D8 = 1,
	VME_D16 = 2,
	VME_D32 = 4
} vme_datasize_t; /* can be or'ed to express multiple capabilities */

typedef int vme_swap_t; /* hardware swap capabilities,
			 contents to be specified */

#ifdef _KERNEL

/* generic placeholder for any ressources needed for a mapping,
 overloaded by bus interface driver */
typedef void *vme_mapresc_t; 

/*
 * tag structure passed to VME bus devices,
 * contains the bus dependant functions, accessed via macros below
 */
typedef struct vme_chipset_tag {
	void *cookie;

	int (*vct_map) __P((void*, vme_addr_t, vme_size_t,
			    vme_am_t, vme_datasize_t, vme_swap_t,
			    bus_space_tag_t*, bus_space_handle_t*,
			    vme_mapresc_t*));
	void (*vct_unmap) __P((void*, vme_mapresc_t));

	int (*vct_badaddr) __P((void*, bus_space_tag_t, bus_space_handle_t,
				bus_size_t, vme_datasize_t));

	void *(*vct_int_map) __P((void*, int, int,
				  int (*)(void*), void*));
	void (*vct_int_unmap) __P((void*, void*));

	int (*vct_dmamap_create) __P((void*, vme_size_t,
				      vme_am_t*, vme_datasize_t*, vme_swap_t*,
				      int, bus_dma_handle_t*));
	void (*vct_dmamap_destroy) __P((void*, bus_dma_handle_t));

	int (*vct_cntlrdmamap_create) __P((void*, vme_addr_t, vme_size_t,
					   vme_am_t, vme_datasize_t, vme_swap_t,
					   int, bus_cntlrdma_handle_t*));
	void (*vct_cntlrdmamap_destroy) __P((void*, bus_cntlrdma_handle_t));

	struct vmebus_softc *bus;
} *vme_chipset_tag_t;

/*
 * map / unmap: map VME address ranges into kernel address space
 * XXX should have mapping to CPU only to allow user mmap() without
 *     wasting kvm
 */
#define vme_space_map(vc, vmeaddr, len, am, datasize, swap, tag, handle,
resc) \
  (*((vc)->vct_map))((vc)->cookie, (vmeaddr), (len), (am), (datasize), \
  (swap), (tag), (handle), (resc))
#define vme_space_unmap(vc, resc) \
  (*((vc)->vct_unmap))((vc)->cookie, (resc))

/*
 * badaddr: check readability
 */
#define vme_badaddr(vc, tag, handle, offset, datasize) \
  (*((vc)->vct_badaddr))((vc)->cookie, (tag), (handle), (offset), (datasize))

/*
 * install / deinstall VME interrupt handler
 */
#define vme_intr_establish(vc, level, vector, func, arg) \
  (*((vc)->vct_int_map))((vc)->cookie, \
                        (level), (vector), (func), (arg))
#define vme_intr_disestablish(vc, hdl) \
  (*((vc)->vct_int_unmap))((vc)->cookie, (hdl))

/*
 * create DMA handle (which is later used by bus independant
 * DMA functions
 */
#define vme_dmamap_create(vc, size, am, datasize, swap, flags, handle) \
  (*((vc)->vct_dmamap_create))((vc)->cookie, (size), (am), (datasize),
(swap), \
  (flags), (handle))
#define vme_dmamap_destroy(vc, handle) \
  (*((vc)->vct_dmamap_destroy))((vc)->cookie, (handle))

/*
 * create handle for "controller DMA" or "data mover",
 * later used by bus independant functions
 */
#define vme_cntlrdmamap_create(vc, vmeaddr, size, am, datasize, swap,
flags, handle) \
  (*((vc)->vct_cntlrdmamap_create))((vc)->cookie, (vmeaddr), (size),
(am), (datasize), \
  (swap), (flags), (handle))
#define vme_cntlrdmamap_destroy(vc, handle) \
  (*((vc)->vct_cntlrdmamap_destroy))((vc)->cookie, (handle))


/*
 * autoconfiguration data structures
 */
struct vmebus_attach_args{
	vme_chipset_tag_t va_vct;
	bus_dma_tag_t va_bdt;
	bus_cntlrdma_tag_t va_bcdt;
	bus_lock_tag_t va_bltt;
};

struct vmebus_softc{
	struct device sc_dev;

	vme_chipset_tag_t sc_vct;
	bus_dma_tag_t sc_bdt;
	bus_cntlrdma_tag_t sc_bcdt;
	bus_lock_tag_t sc_bltt;

	struct extent *vme32ext, *vme24ext, *vme16ext;
};

/* nr of addresses given in the kernel configuration file */
#define VME_NUMCFRANGES 3

struct vme_range {
	vme_addr_t offset;
	vme_size_t size;
	vme_am_t am;
};

struct vme_attach_args{
	struct vme_range r[VME_NUMCFRANGES];
	int ivector, ilevel;

	vme_chipset_tag_t va_vct;
	bus_dma_tag_t va_bdt;
	bus_cntlrdma_tag_t va_bcdt;
	bus_lock_tag_t va_bltt;
};

/*
 * address space accounting
 */
int _vme_space_alloc __P((struct vmebus_softc*, vme_addr_t, vme_size_t,
vme_am_t));
void _vme_space_free __P((struct vmebus_softc*, vme_addr_t, vme_size_t,
vme_am_t));
int _vme_space_get __P((struct vmebus_softc*, vme_size_t, vme_am_t,
u_long, vme_addr_t*));

#define vme_space_alloc(tag, addr, size, ams) \
  _vme_space_alloc(tag->bus, addr, size, ams)

#define vme_space_free(tag, addr, size, ams) \
  _vme_space_free(tag->bus, addr, size, ams)

#define vme_space_get(tag, size, ams, align, addr) \
  _vme_space_get(tag->bus, size, ams, align, addr)

#endif /* KERNEL */
#endif /* _vmevar_h_ */