#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mcadma_machdep.c,v 1.5 2026/01/09 22:54:34 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/kmem.h>
#include <sys/proc.h>
#include <sys/mbuf.h>
#define _POWERPC_BUS_DMA_PRIVATE
#include <sys/bus.h>
#include <machine/pio.h>
#include <dev/mca/mcavar.h>
#include <dev/mca/mcareg.h>
struct rs6000_dma_cookie {
int id_flags;
uint32_t bid;
uint32_t tce_off;
uint32_t nroftce;
uint32_t nrofslaves;
uint32_t slave_regs;
uint32_t dma_regs;
};
struct powerpc_bus_dma_tag mca_bus_dma_tag = {
0, 0,
_mca_bus_dmamap_create,
_bus_dmamap_destroy,
_bus_dmamap_load,
_bus_dmamap_load_mbuf,
_bus_dmamap_load_uio,
_bus_dmamap_load_raw,
_bus_dmamap_unload,
NULL,
_bus_dmamem_alloc,
_bus_dmamem_free,
_bus_dmamem_map,
_bus_dmamem_unmap,
_bus_dmamem_mmap,
};
static int
_mca_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int flags,
bus_dmamap_t *dmamp, int dmach)
{
int error;
struct rs6000_dma_cookie *cookie;
#ifdef DEBUG
if (dmach < 0 || dmach >= MAX_DMA_CHANNELS) {
printf("mcadma_create: invalid DMA channel %d\n", dmach);
return EINVAL;
}
if (size > 65536) {
panic("mca_dmamap_create: dmamap sz %ld > 65536", (long) size);
}
#endif
if ((error = _bus_dmamap_create(t, size, 1, 65536, 0, flags, dmamp)))
return error;
cookie = (struct rs6000_dma_cookie *) (*dmamp)->_dm_cookie;
if (cookie == NULL) {
cookie = kmem_zalloc(sizeof(struct rs6000_dma_cookie),
((flags & BUS_DMA_NOWAIT) ? KM_NOSLEEP : KM_SLEEP));
if (cookie == NULL) {
return ENOMEM;
}
(*dmamp)->_dm_cookie = cookie;
}
cookie->id_flags &= 0x0f;
cookie->id_flags |= dmach << 4;
(*dmamp)->_dm_flags |= _MCABUS_DMA_USEDMACTRL;
return 0;
}
static void
_mca_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
{
struct rs6000_dma_cookie *cookie = map->_dm_cookie;
kmem_free(cookie, sizeof(struct rs6000_dma_cookie));
_bus_dmamap_destroy(t, map);
}
static int
_mca_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
bus_size_t buflen, struct proc *p, int flags)
{
struct rs6000_dma_cookie *cookie = map->_dm_cookie;
int error;
map->dm_mapsize = 0;
map->dm_nsegs = 0;
error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
return error;
}
static int
_mca_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
int flags)
{
struct rs6000_dma_cookie *cookie = map->_dm_cookie;
int error;
map->dm_mapsize = 0;
map->dm_nsegs = 0;
#ifdef DIAGNOSTIC
if ((m0->m_flags & M_PKTHDR) == 0)
panic("_mca_bus_dmamap_load_mbuf: no packet header");
#endif
if (m0->m_pkthdr.len > map->_dm_size)
return EINVAL;
error = _bus_dmamap_load_mbuf(t, map, m0, flags);
return error;
}
static int
_mca_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
int flags)
{
panic("_mca_bus_dmamap_load_uio: not implemented");
}
static int
_mca_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
{
panic("_mca_bus_dmamap_load_raw: not implemented");
}
static void
_mca_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
{
_bus_dmamap_unload(t, map);
}
static int
_mca_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
int flags)
{
paddr_t high;
high = trunc_page(avail_end);
return _bus_dmamem_alloc_range(t, size, alignment, boundary,
segs, nsegs, rsegs, flags, 0, high);
}