#ifndef LIBBSDPORT_SYS_BUS_H #define LIBBSDPORT_SYS_BUS_H #include #include #include #include #include typedef uint32_t bus_addr_t; typedef size_t bus_size_t; typedef enum { bus_space_mem = 0, bus_space_io = 1 } bus_space_tag_t; struct resource; typedef bus_addr_t bus_space_handle_t; /* The 'bus_space_xxx()' inlines can be helped if the * tag is hardcoded in the driver so that the compiler * can optimize part of the implementation away. */ #define BUS_SPACE_BARRIER_WRITE 1 #define BUS_SPACE_BARRIER_READ 2 #if defined(__i386__) #include static inline void bus_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, int width, int type) { } #define BUS_SPACE_DECL(type, width, nwidth) \ static inline type \ bus_space_read_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) \ { \ type v; \ if ( bus_space_io == t ) { \ /* this is a macro setting the second argument */ \ inport_##width( h+o, v ); \ } else { \ v = *(volatile type __attribute__((may_alias)) *)(h+o); \ } \ return v; \ } \ \ static inline void \ bus_space_write_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, type v) \ { \ if ( bus_space_io == t ) { \ outport_##width( h+o, v ); \ } else { \ *(volatile type __attribute__((may_alias)) *)(h+o) = v; \ }\ } BUS_SPACE_DECL(u_int32_t, long, 4) BUS_SPACE_DECL(u_int16_t, word, 2) BUS_SPACE_DECL(u_int8_t, byte, 1) #elif defined(__PPC__) #include #if defined(_IO_BASE) && _IO_BASE == 0 #define BUS_SPACE_ALWAYS_MEM 1 #else #define BUS_SPACE_ALWAYS_MEM 0 #endif static inline void bus_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, int width, int type) { asm volatile("eieio"); } #define BUS_SPACE_DECL(type, width, nwidth, op) \ static inline type \ bus_space_read_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) \ { \ type v; \ if ( !BUS_SPACE_ALWAYS_MEM && bus_space_io == t ) { \ /* this is a macro setting the second argument */ \ v = in_##op((volatile type *)(_IO_BASE+h+o)); \ } else { \ v = in_##op((volatile type *)(h+o)); \ } \ return v; \ } \ \ static inline void \ bus_space_write_##nwidth(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, type v) \ { \ if ( !BUS_SPACE_ALWAYS_MEM && bus_space_io == t ) { \ out_##op((volatile type *)(_IO_BASE+h+o), v); \ } else { \ out_##op((volatile type *)(h+o), v); \ }\ } BUS_SPACE_DECL(u_int32_t, long, 4, le32) BUS_SPACE_DECL(u_int16_t, word, 2, le16) BUS_SPACE_DECL(u_int8_t, byte, 1, 8) #undef BUS_SPACE_ALWAYS_MEM #else #error "Missing definitions of bus_space_XXX() for this CPU architecture" #endif #undef BUS_SPACE_DECL #ifndef BUS_PROBE_DEFAULT #define BUS_PROBE_DEFAULT 0 #endif /* error codes are > 0 ; low priority says that probe * was successful but another driver returning BUS_PROBE_DEFAULT * is to be preferred... */ #ifndef BUS_PROBE_LOW_PRIORITY #define BUS_PROBE_LOW_PRIORITY (-1) #endif /* types -> -1 means unsupported */ #define SYS_RES_IOPORT 1 #define SYS_RES_MEMORY 2 #define SYS_RES_IRQ 3 /* flags (1<<31) means unsupported */ #define RF_ACTIVE (1<<1) #define RF_SHAREABLE (1<<2) struct resource * bus_alloc_resource_any(device_t dev, int type, int *prid, unsigned flags); #define FILTER_STRAY 1 #define FILTER_HANDLED 0 typedef void (*driver_intr_t)(void *); typedef int (*driver_filter_t)(void *); int bus_setup_intr(device_t dev, struct resource *r, int flags, driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep); /* Flags currently ignored... */ #define INTR_MPSAFE 0 #define INTR_TYPE_NET 0 /* * INTR_FAST handlers are already more like 'filters', * i.e., they disable interrupts and schedule work * on a task queue. * * During porting the fast handler has to be slightly * rewritten (must return an int value, FILTER_HANDLED * if a valid IRQ was detected and work has been scheduled * and FILTER_STRAY if this device didn't interrupt). * * You need to then remove INTR_FAST from the flags, * pass the converted handler as the 'filter' argument * and a NULL handler argument to bus_setup_intr(). * */ extern int __INTR_FAST() __attribute__(( error("\n\n==> you need to convert bus_setup_intr(INTR_FAST) to new API;\n" " consult \n\n") )); /* Barf at compile time if they try to use INTR_FAST */ #define INTR_FAST (__INTR_FAST()) int bus_teardown_intr(device_t dev, struct resource *r, void *cookiep); static inline int bus_release_resource(device_t dev, int type, int rid, struct resource *r) { return 0; } #define bus_generic_detach(dev) do {} while (0) #define bus_generic_suspend(dev) (0) #define bus_generic_resume(dev) (0) bus_space_handle_t rman_get_bushandle(struct resource *r); bus_space_tag_t rman_get_bustag(struct resource *r); #ifndef BUS_DMA_NOWAIT /* ignored anyways */ #define BUS_DMA_NOWAIT 0 #endif #ifndef BUS_DMA_WAITOK /* ignored anyways */ #define BUS_DMA_WAITOK 0 #endif #ifndef BUS_DMA_COHERENT /* ignored anyways */ #define BUS_DMA_COHERENT 0 #endif #ifndef BUS_DMA_ZERO /* ignored anyways */ #define BUS_DMA_ZERO 0 #endif #ifndef BUS_DMA_ALLOCNOW /* ignored anyways */ #define BUS_DMA_ALLOCNOW 0 #endif /* unused */ #ifndef BUS_SPACE_MAXADDR #define BUS_SPACE_MAXADDR 0xdeadbeef #endif /* unused */ #ifndef BUS_SPACE_MAXADDR_32BIT #define BUS_SPACE_MAXADDR_32BIT 0xdeadbeef #endif /* unused */ #ifndef BUS_SPACE_MAXSIZE_32BIT #define BUS_SPACE_MAXSIZE_32BIT 0x10000000 #endif typedef struct _bus_dma_tag_t { unsigned alignment; unsigned maxsize; unsigned maxsegs; } * bus_dma_tag_t; typedef struct _bus_dma_segment_t { bus_addr_t ds_addr; bus_size_t ds_len; } bus_dma_segment_t; typedef void *bus_dmamap_t; int bus_dma_tag_create(void *parent, unsigned alignment, unsigned bounds, uint32_t lowadd, uint32_t hiaddr, void (*filter)(void*), void *filterarg, unsigned maxsize, int nsegs, unsigned maxsegsize, unsigned flags, void (*lockfunc)(void*), void *lockarg, bus_dma_tag_t *ptag); void bus_dma_tag_destroy(bus_dma_tag_t tag); int bus_dmamem_alloc(bus_dma_tag_t tag, void **p_vaddr, unsigned flags, bus_dmamap_t *p_map); void bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map); #ifndef CPU2BUSADDR #ifndef PCI_DRAM_OFFSET #define PCI_DRAM_OFFSET 0 #endif #define CPU2BUSADDR(x) ((uint32_t)(x) + (PCI_DRAM_OFFSET)) #endif #define kvtop(a) CPU2BUSADDR((bus_addr_t)(a)) #define vtophys(a) CPU2BUSADDR((bus_addr_t)(a)) static inline int bus_dmamap_load_mbuf_sg(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf *m_head, bus_dma_segment_t *segs, int *pnsegs, unsigned flags) { struct mbuf *m; int n; for ( m=m_head, n=0; m; m=m->m_next, n++ ) { if ( n >= tag->maxsegs ) { return EFBIG; } segs[n].ds_addr = CPU2BUSADDR(mtod(m, unsigned)); segs[n].ds_len = m->m_len; } *pnsegs = n; return 0; } static inline bus_dma_tag_t bus_get_dma_tag(device_t dev) { return 0; } typedef void bus_dmamap_callback_t (void *arg, bus_dma_segment_t *segs, int nseg, int error); static inline int bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t map, caddr_t vaddr, bus_size_t size, bus_dmamap_callback_t cb, void *arg, unsigned flags) { bus_dma_segment_t segs[1]; segs[0].ds_addr = CPU2BUSADDR(vaddr); segs[0].ds_len = size; cb(arg, segs, 1, 0); return 0; } typedef void bus_dmamap_callback2_t (void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize, int error); static inline int bus_dmamap_load_mbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf *m_head, bus_dmamap_callback2_t cb, void *arg, unsigned flags) { /* hopefully there's enough stack ... */ bus_dma_segment_t segs[tag->maxsegs]; struct mbuf *m; int n; bus_size_t sz; for ( m=m_head, sz=0, n=0; m; m=m->m_next, n++ ) { if ( n >= tag->maxsegs ) { cb(arg, segs, n, sz, EFBIG); return EFBIG; } segs[n].ds_addr = CPU2BUSADDR(mtod(m, unsigned)); sz += (segs[n].ds_len = m->m_len); } cb(arg, segs, n, sz, 0); return 0; } #define bus_dmamap_unload(tag, map) do {} while (0) /* should we do something if we have no HW snooping ? */ #define bus_dmamap_sync(tag, map, flags) do { membarrier_rw(); } while (0) #define bus_dmamap_create(tag, flags, pmap) ( *(pmap) = 0, 0 ) #define bus_dmamap_destroy(tag, map) do {} while (0) #endif