#include "ena.h"
void
ena_dma_attr(const ena_t *ena, ddi_dma_attr_t *attrp,
const ena_dma_conf_t *conf)
{
bzero(attrp, sizeof (*attrp));
const size_t size_up =
P2ROUNDUP_TYPED(conf->edc_size, ena->ena_page_sz, size_t);
attrp->dma_attr_version = DMA_ATTR_V0;
ASSERT3U(ena->ena_dma_width, >=, 32);
ASSERT3U(ena->ena_dma_width, <=, 48);
attrp->dma_attr_addr_lo = 0x0;
attrp->dma_attr_addr_hi = ENA_DMA_BIT_MASK(ena->ena_dma_width);
attrp->dma_attr_count_max = size_up - 1;
attrp->dma_attr_align = conf->edc_align;
attrp->dma_attr_seg = UINT64_MAX;
attrp->dma_attr_burstsizes = size_up;
attrp->dma_attr_minxfer = 0x1;
attrp->dma_attr_maxxfer = size_up;
attrp->dma_attr_granular = 0x1;
attrp->dma_attr_sgllen = conf->edc_sgl;
}
void
ena_dma_free(ena_dma_buf_t *edb)
{
if (edb->edb_cookie != NULL) {
(void) ddi_dma_unbind_handle(edb->edb_dma_hdl);
edb->edb_cookie = NULL;
edb->edb_real_len = 0;
}
if (edb->edb_acc_hdl != NULL) {
ddi_dma_mem_free(&edb->edb_acc_hdl);
edb->edb_acc_hdl = NULL;
edb->edb_va = NULL;
}
if (edb->edb_dma_hdl != NULL) {
ddi_dma_free_handle(&edb->edb_dma_hdl);
edb->edb_dma_hdl = NULL;
}
edb->edb_va = NULL;
edb->edb_len = 0;
}
bool
ena_dma_alloc(ena_t *ena, ena_dma_buf_t *edb, ena_dma_conf_t *conf, size_t size)
{
int ret;
size_t size_allocated;
ddi_dma_attr_t attr;
ddi_device_acc_attr_t acc;
uint_t flags =
conf->edc_stream ? DDI_DMA_STREAMING : DDI_DMA_CONSISTENT;
ena_dma_attr(ena, &attr, conf);
acc.devacc_attr_version = DDI_DEVICE_ATTR_V1;
acc.devacc_attr_endian_flags = conf->edc_endian;
acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
ret = ddi_dma_alloc_handle(ena->ena_dip, &attr, DDI_DMA_DONTWAIT, NULL,
&edb->edb_dma_hdl);
if (ret != DDI_SUCCESS) {
ena_err(ena, "!failed to allocate DMA handle: %d", ret);
return (false);
}
ret = ddi_dma_mem_alloc(edb->edb_dma_hdl, size, &acc, flags,
DDI_DMA_DONTWAIT, NULL, &edb->edb_va, &size_allocated,
&edb->edb_acc_hdl);
if (ret != DDI_SUCCESS) {
ena_err(ena, "!failed to allocate %lu bytes of DMA "
"memory: %d", size, ret);
ena_dma_free(edb);
return (false);
}
bzero(edb->edb_va, size_allocated);
ret = ddi_dma_addr_bind_handle(edb->edb_dma_hdl, NULL, edb->edb_va,
size_allocated, DDI_DMA_RDWR | flags, DDI_DMA_DONTWAIT, NULL, NULL,
NULL);
if (ret != DDI_SUCCESS) {
ena_err(ena, "!failed to bind %lu bytes of DMA "
"memory: %d", size_allocated, ret);
ena_dma_free(edb);
return (false);
}
edb->edb_len = size;
edb->edb_real_len = size_allocated;
edb->edb_cookie = ddi_dma_cookie_one(edb->edb_dma_hdl);
return (true);
}
void
ena_dma_bzero(ena_dma_buf_t *edb)
{
bzero(edb->edb_va, edb->edb_real_len);
}
void
ena_set_dma_addr(const ena_t *ena, const uint64_t phys_addr,
enahw_addr_t *hwaddrp)
{
ENA_DMA_VERIFY_ADDR(ena, phys_addr);
hwaddrp->ea_low = (uint32_t)phys_addr;
hwaddrp->ea_high = (uint16_t)(phys_addr >> 32);
}
void
ena_set_dma_addr_values(const ena_t *ena, const uint64_t phys_addr,
uint32_t *dst_low, uint16_t *dst_high)
{
ENA_DMA_VERIFY_ADDR(ena, phys_addr);
*dst_low = (uint32_t)phys_addr;
*dst_high = (uint16_t)(phys_addr >> 32);
}