1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 #include "ena.h" 17 18 /* 19 * Create DMA attributes based on the conf parameter. 20 */ 21 void 22 ena_dma_attr(const ena_t *ena, ddi_dma_attr_t *attrp, 23 const ena_dma_conf_t *conf) 24 { 25 bzero(attrp, sizeof (*attrp)); 26 27 /* 28 * Round up maximums to next page. This is what the Linux and 29 * FreeBSD driver do, so we follow suit. 30 */ 31 const size_t size_up = 32 P2ROUNDUP_TYPED(conf->edc_size, ena->ena_page_sz, size_t); 33 34 attrp->dma_attr_version = DMA_ATTR_V0; 35 36 /* 37 * The device tells us the window it supports in terms of 38 * number of bits, we convert that to the appropriate mask. 39 */ 40 ASSERT3U(ena->ena_dma_width, >=, 32); 41 ASSERT3U(ena->ena_dma_width, <=, 48); 42 attrp->dma_attr_addr_lo = 0x0; 43 attrp->dma_attr_addr_hi = ENA_DMA_BIT_MASK(ena->ena_dma_width); 44 45 /* 46 * This indicates the amount of data that can fit in one 47 * cookie/segment. We allow the entire object to live in one 48 * segment, when possible. 49 * 50 * NOTE: This value must be _one less_ than the desired max 51 * (i.e. a value of 4095 indicates a max of 4096). 52 */ 53 attrp->dma_attr_count_max = size_up - 1; 54 55 /* 56 * The alignment of the starting address. 57 */ 58 attrp->dma_attr_align = conf->edc_align; 59 60 /* 61 * The segment boundary dictates the address which a segment 62 * cannot cross. In this case there is no boundary. 63 */ 64 attrp->dma_attr_seg = UINT64_MAX; 65 66 /* 67 * Allow a burst size of the entire object. 68 */ 69 attrp->dma_attr_burstsizes = size_up; 70 71 /* 72 * Minimum and maximum amount of data we can send. This isn't 73 * strictly limited by PCI in hardware, as it'll just make the 74 * appropriate number of requests. Similarly, PCIe allows for 75 * an arbitrary granularity. We set this to one, as it's 76 * really a matter of what hardware is requesting from us. 77 */ 78 attrp->dma_attr_minxfer = 0x1; 79 attrp->dma_attr_maxxfer = size_up; 80 attrp->dma_attr_granular = 0x1; 81 82 /* 83 * The maximum length of the Scatter Gather List, aka the 84 * maximum number of segments a device can address in a 85 * transfer. 86 */ 87 attrp->dma_attr_sgllen = conf->edc_sgl; 88 } 89 90 void 91 ena_dma_free(ena_dma_buf_t *edb) 92 { 93 if (edb->edb_cookie != NULL) { 94 (void) ddi_dma_unbind_handle(edb->edb_dma_hdl); 95 edb->edb_cookie = NULL; 96 edb->edb_real_len = 0; 97 } 98 99 if (edb->edb_acc_hdl != NULL) { 100 ddi_dma_mem_free(&edb->edb_acc_hdl); 101 edb->edb_acc_hdl = NULL; 102 edb->edb_va = NULL; 103 } 104 105 if (edb->edb_dma_hdl != NULL) { 106 ddi_dma_free_handle(&edb->edb_dma_hdl); 107 edb->edb_dma_hdl = NULL; 108 } 109 110 edb->edb_va = NULL; 111 edb->edb_len = 0; 112 } 113 114 bool 115 ena_dma_alloc(ena_t *ena, ena_dma_buf_t *edb, ena_dma_conf_t *conf, size_t size) 116 { 117 int ret; 118 size_t size_allocated; 119 ddi_dma_attr_t attr; 120 ddi_device_acc_attr_t acc; 121 uint_t flags = 122 conf->edc_stream ? DDI_DMA_STREAMING : DDI_DMA_CONSISTENT; 123 124 ena_dma_attr(ena, &attr, conf); 125 126 acc.devacc_attr_version = DDI_DEVICE_ATTR_V1; 127 acc.devacc_attr_endian_flags = conf->edc_endian; 128 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 129 130 ret = ddi_dma_alloc_handle(ena->ena_dip, &attr, DDI_DMA_DONTWAIT, NULL, 131 &edb->edb_dma_hdl); 132 if (ret != DDI_SUCCESS) { 133 ena_err(ena, "!failed to allocate DMA handle: %d", ret); 134 return (false); 135 } 136 137 ret = ddi_dma_mem_alloc(edb->edb_dma_hdl, size, &acc, flags, 138 DDI_DMA_DONTWAIT, NULL, &edb->edb_va, &size_allocated, 139 &edb->edb_acc_hdl); 140 if (ret != DDI_SUCCESS) { 141 ena_err(ena, "!failed to allocate %lu bytes of DMA " 142 "memory: %d", size, ret); 143 ena_dma_free(edb); 144 return (false); 145 } 146 147 bzero(edb->edb_va, size_allocated); 148 149 ret = ddi_dma_addr_bind_handle(edb->edb_dma_hdl, NULL, edb->edb_va, 150 size_allocated, DDI_DMA_RDWR | flags, DDI_DMA_DONTWAIT, NULL, NULL, 151 NULL); 152 if (ret != DDI_SUCCESS) { 153 ena_err(ena, "!failed to bind %lu bytes of DMA " 154 "memory: %d", size_allocated, ret); 155 ena_dma_free(edb); 156 return (false); 157 } 158 159 edb->edb_len = size; 160 edb->edb_real_len = size_allocated; 161 edb->edb_cookie = ddi_dma_cookie_one(edb->edb_dma_hdl); 162 return (true); 163 } 164 165 void 166 ena_dma_bzero(ena_dma_buf_t *edb) 167 { 168 bzero(edb->edb_va, edb->edb_real_len); 169 } 170 171 /* 172 * Write the physical DMA address to the ENA hardware address pointer. 173 * While the DMA engine should guarantee that the allocation is within 174 * the specified range, we double check here to catch programmer error 175 * and avoid hard-to-debug situations. 176 */ 177 void 178 ena_set_dma_addr(const ena_t *ena, const uint64_t phys_addr, 179 enahw_addr_t *hwaddrp) 180 { 181 ENA_DMA_VERIFY_ADDR(ena, phys_addr); 182 hwaddrp->ea_low = (uint32_t)phys_addr; 183 hwaddrp->ea_high = (uint16_t)(phys_addr >> 32); 184 } 185 186 /* 187 * The same as the above function, but writes the physical address to 188 * the supplied value pointers instead. Mostly used as a sanity check 189 * that the address fits in the reported DMA width. 190 */ 191 void 192 ena_set_dma_addr_values(const ena_t *ena, const uint64_t phys_addr, 193 uint32_t *dst_low, uint16_t *dst_high) 194 { 195 ENA_DMA_VERIFY_ADDR(ena, phys_addr); 196 *dst_low = (uint32_t)phys_addr; 197 *dst_high = (uint16_t)(phys_addr >> 32); 198 } 199