xref: /illumos-gate/usr/src/uts/common/io/ena/ena_dma.c (revision 6f443ebc)
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 2021 Oxide Computer Company
14  */
15 
16 #include "ena.h"
17 
18 /*
19  * Create DMA attributes based on the conf parameter.
20  */
21 void
ena_dma_attr(const ena_t * ena,ddi_dma_attr_t * attrp,const ena_dma_conf_t * conf)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. Simiarly, 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
ena_dma_free(ena_dma_buf_t * edb)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_len = 0;
111 }
112 
113 boolean_t
ena_dma_alloc(ena_t * ena,ena_dma_buf_t * edb,ena_dma_conf_t * conf,size_t size)114 ena_dma_alloc(ena_t *ena, ena_dma_buf_t *edb, ena_dma_conf_t *conf, size_t size)
115 {
116 	int ret;
117 	size_t size_allocated;
118 	ddi_dma_attr_t attr;
119 	ddi_device_acc_attr_t acc;
120 	uint_t flags =
121 	    conf->edc_stream ? DDI_DMA_STREAMING : DDI_DMA_CONSISTENT;
122 
123 	ena_dma_attr(ena, &attr, conf);
124 
125 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V1;
126 	acc.devacc_attr_endian_flags = conf->edc_endian;
127 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
128 
129 	ret = ddi_dma_alloc_handle(ena->ena_dip, &attr, DDI_DMA_DONTWAIT, NULL,
130 	    &edb->edb_dma_hdl);
131 	if (ret != DDI_SUCCESS) {
132 		ena_err(ena, "!failed to allocate DMA handle: %d", ret);
133 		return (B_FALSE);
134 	}
135 
136 	ret = ddi_dma_mem_alloc(edb->edb_dma_hdl, size, &acc, flags,
137 	    DDI_DMA_DONTWAIT, NULL, &edb->edb_va, &size_allocated,
138 	    &edb->edb_acc_hdl);
139 	if (ret != DDI_SUCCESS) {
140 		ena_err(ena, "!failed to allocate %lu bytes of DMA "
141 		    "memory: %d", size, ret);
142 		ena_dma_free(edb);
143 		return (B_FALSE);
144 	}
145 
146 	bzero(edb->edb_va, size_allocated);
147 
148 	ret = ddi_dma_addr_bind_handle(edb->edb_dma_hdl, NULL, edb->edb_va,
149 	    size_allocated, DDI_DMA_RDWR | flags, DDI_DMA_DONTWAIT, NULL, NULL,
150 	    NULL);
151 	if (ret != DDI_SUCCESS) {
152 		ena_err(ena, "!failed to bind %lu bytes of DMA "
153 		    "memory: %d", size_allocated, ret);
154 		ena_dma_free(edb);
155 		return (B_FALSE);
156 	}
157 
158 	edb->edb_len = size;
159 	edb->edb_real_len = size_allocated;
160 	edb->edb_cookie = ddi_dma_cookie_one(edb->edb_dma_hdl);
161 	return (B_TRUE);
162 }
163 
164 /*
165  * Write the physical DMA address to the ENA hardware address pointer.
166  * While the DMA engine should guarantee that the allocation is within
167  * the specified range, we double check here to catch programmer error
168  * and avoid hard-to-debug situations.
169  */
170 void
ena_set_dma_addr(const ena_t * ena,const uint64_t phys_addr,enahw_addr_t * hwaddrp)171 ena_set_dma_addr(const ena_t *ena, const uint64_t phys_addr,
172     enahw_addr_t *hwaddrp)
173 {
174 	ENA_DMA_VERIFY_ADDR(ena, phys_addr);
175 	hwaddrp->ea_low = (uint32_t)phys_addr;
176 	hwaddrp->ea_high = (uint16_t)(phys_addr >> 32);
177 }
178 
179 /*
180  * The same as the above function, but writes the phsyical address to
181  * the supplied value pointers instead. Mostly used as a sanity check
182  * that the address fits in the reported DMA width.
183  */
184 void
ena_set_dma_addr_values(const ena_t * ena,const uint64_t phys_addr,uint32_t * dst_low,uint16_t * dst_high)185 ena_set_dma_addr_values(const ena_t *ena, const uint64_t phys_addr,
186     uint32_t *dst_low, uint16_t *dst_high)
187 {
188 	ENA_DMA_VERIFY_ADDR(ena, phys_addr);
189 	*dst_low = (uint32_t)phys_addr;
190 	*dst_high = (uint16_t)(phys_addr >> 32);
191 }
192