xref: /freebsd/sys/dev/oce/oce_util.c (revision 71625ec9)
12f345d8eSLuigi Rizzo /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
4291a1934SXin LI  * Copyright (C) 2013 Emulex
52f345d8eSLuigi Rizzo  * All rights reserved.
62f345d8eSLuigi Rizzo  *
72f345d8eSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
82f345d8eSLuigi Rizzo  * modification, are permitted provided that the following conditions are met:
92f345d8eSLuigi Rizzo  *
102f345d8eSLuigi Rizzo  * 1. Redistributions of source code must retain the above copyright notice,
112f345d8eSLuigi Rizzo  *    this list of conditions and the following disclaimer.
122f345d8eSLuigi Rizzo  *
132f345d8eSLuigi Rizzo  * 2. Redistributions in binary form must reproduce the above copyright
142f345d8eSLuigi Rizzo  *    notice, this list of conditions and the following disclaimer in the
152f345d8eSLuigi Rizzo  *    documentation and/or other materials provided with the distribution.
162f345d8eSLuigi Rizzo  *
172f345d8eSLuigi Rizzo  * 3. Neither the name of the Emulex Corporation nor the names of its
182f345d8eSLuigi Rizzo  *    contributors may be used to endorse or promote products derived from
192f345d8eSLuigi Rizzo  *    this software without specific prior written permission.
202f345d8eSLuigi Rizzo  *
212f345d8eSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
222f345d8eSLuigi Rizzo  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232f345d8eSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242f345d8eSLuigi Rizzo  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
252f345d8eSLuigi Rizzo  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
262f345d8eSLuigi Rizzo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
272f345d8eSLuigi Rizzo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
282f345d8eSLuigi Rizzo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
292f345d8eSLuigi Rizzo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302f345d8eSLuigi Rizzo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
312f345d8eSLuigi Rizzo  * POSSIBILITY OF SUCH DAMAGE.
322f345d8eSLuigi Rizzo  *
332f345d8eSLuigi Rizzo  * Contact Information:
342f345d8eSLuigi Rizzo  * freebsd-drivers@emulex.com
352f345d8eSLuigi Rizzo  *
362f345d8eSLuigi Rizzo  * Emulex
372f345d8eSLuigi Rizzo  * 3333 Susan Street
382f345d8eSLuigi Rizzo  * Costa Mesa, CA 92626
392f345d8eSLuigi Rizzo  */
402f345d8eSLuigi Rizzo 
412f345d8eSLuigi Rizzo 
422f345d8eSLuigi Rizzo #include "oce_if.h"
432f345d8eSLuigi Rizzo 
442f345d8eSLuigi Rizzo static void oce_dma_map_ring(void *arg,
452f345d8eSLuigi Rizzo 			     bus_dma_segment_t *segs,
462f345d8eSLuigi Rizzo 			     int nseg,
472f345d8eSLuigi Rizzo 			     int error);
482f345d8eSLuigi Rizzo 
492f345d8eSLuigi Rizzo /**
502f345d8eSLuigi Rizzo  * @brief		Allocate DMA memory
512f345d8eSLuigi Rizzo  * @param sc		software handle to the device
522f345d8eSLuigi Rizzo  * @param size		bus size
532f345d8eSLuigi Rizzo  * @param dma		dma memory area
542f345d8eSLuigi Rizzo  * @param flags		creation flags
552f345d8eSLuigi Rizzo  * @returns		0 on success, error otherwize
562f345d8eSLuigi Rizzo  */
572f345d8eSLuigi Rizzo int
oce_dma_alloc(POCE_SOFTC sc,bus_size_t size,POCE_DMA_MEM dma,int flags)582f345d8eSLuigi Rizzo oce_dma_alloc(POCE_SOFTC sc, bus_size_t size, POCE_DMA_MEM dma, int flags)
592f345d8eSLuigi Rizzo {
602f345d8eSLuigi Rizzo 	int rc;
612f345d8eSLuigi Rizzo 
622f345d8eSLuigi Rizzo 	memset(dma, 0, sizeof(OCE_DMA_MEM));
632f345d8eSLuigi Rizzo 
642f345d8eSLuigi Rizzo 	rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
652f345d8eSLuigi Rizzo 				8, 0,
662f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
672f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
682f345d8eSLuigi Rizzo 				NULL, NULL,
692f345d8eSLuigi Rizzo 				size, 1, size, 0, NULL, NULL, &dma->tag);
702f345d8eSLuigi Rizzo 
712f345d8eSLuigi Rizzo 	if (rc == 0) {
722f345d8eSLuigi Rizzo 		rc = bus_dmamem_alloc(dma->tag,
732f345d8eSLuigi Rizzo 				      &dma->ptr,
74cdaba892SXin LI 				      BUS_DMA_NOWAIT | BUS_DMA_COHERENT |
75cdaba892SXin LI 					BUS_DMA_ZERO,
762f345d8eSLuigi Rizzo 				      &dma->map);
772f345d8eSLuigi Rizzo 	}
782f345d8eSLuigi Rizzo 
792f345d8eSLuigi Rizzo 	dma->paddr = 0;
802f345d8eSLuigi Rizzo 	if (rc == 0) {
812f345d8eSLuigi Rizzo 		rc = bus_dmamap_load(dma->tag,
822f345d8eSLuigi Rizzo 				     dma->map,
832f345d8eSLuigi Rizzo 				     dma->ptr,
842f345d8eSLuigi Rizzo 				     size,
852f345d8eSLuigi Rizzo 				     oce_dma_map_addr,
862f345d8eSLuigi Rizzo 				     &dma->paddr, flags | BUS_DMA_NOWAIT);
872f345d8eSLuigi Rizzo 		if (dma->paddr == 0)
882f345d8eSLuigi Rizzo 			rc = ENXIO;
892f345d8eSLuigi Rizzo 	}
902f345d8eSLuigi Rizzo 
912f345d8eSLuigi Rizzo 	if (rc != 0)
922f345d8eSLuigi Rizzo 		oce_dma_free(sc, dma);
932f345d8eSLuigi Rizzo 
942f345d8eSLuigi Rizzo 	return rc;
952f345d8eSLuigi Rizzo }
962f345d8eSLuigi Rizzo 
972f345d8eSLuigi Rizzo /**
982f345d8eSLuigi Rizzo  * @brief		Free DMA memory
992f345d8eSLuigi Rizzo  * @param sc		software handle to the device
1002f345d8eSLuigi Rizzo  * @param dma		dma area to free
1012f345d8eSLuigi Rizzo  */
1022f345d8eSLuigi Rizzo void
oce_dma_free(POCE_SOFTC sc,POCE_DMA_MEM dma)1032f345d8eSLuigi Rizzo oce_dma_free(POCE_SOFTC sc, POCE_DMA_MEM dma)
1042f345d8eSLuigi Rizzo {
1052f345d8eSLuigi Rizzo 	if (dma->tag == NULL)
1062f345d8eSLuigi Rizzo 		return;
1072f345d8eSLuigi Rizzo 
108c34f1a08SJohn Baldwin 	if (dma->paddr != 0) {
1092f345d8eSLuigi Rizzo 		bus_dmamap_sync(dma->tag, dma->map,
1102f345d8eSLuigi Rizzo 				BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1112f345d8eSLuigi Rizzo 		bus_dmamap_unload(dma->tag, dma->map);
112c34f1a08SJohn Baldwin 		dma->paddr = 0;
1132f345d8eSLuigi Rizzo 	}
1142f345d8eSLuigi Rizzo 
1152f345d8eSLuigi Rizzo 	if (dma->ptr != NULL) {
1162f345d8eSLuigi Rizzo 		bus_dmamem_free(dma->tag, dma->ptr, dma->map);
1172f345d8eSLuigi Rizzo 		dma->ptr = NULL;
1182f345d8eSLuigi Rizzo 	}
1192f345d8eSLuigi Rizzo 
1202f345d8eSLuigi Rizzo 	bus_dma_tag_destroy(dma->tag);
1212f345d8eSLuigi Rizzo 	dma->tag = NULL;
1222f345d8eSLuigi Rizzo 
1232f345d8eSLuigi Rizzo 	return;
1242f345d8eSLuigi Rizzo }
1252f345d8eSLuigi Rizzo 
1262f345d8eSLuigi Rizzo /**
1272f345d8eSLuigi Rizzo  * @brief		Map DMA memory segment addresses
1282f345d8eSLuigi Rizzo  * @param arg		physical address pointer
1292f345d8eSLuigi Rizzo  * @param segs		dma memory segments
1302f345d8eSLuigi Rizzo  * @param nseg		number of dma memory segments
1312f345d8eSLuigi Rizzo  * @param error		if error, zeroes the physical address
1322f345d8eSLuigi Rizzo  */
1332f345d8eSLuigi Rizzo void
oce_dma_map_addr(void * arg,bus_dma_segment_t * segs,int nseg,int error)1342f345d8eSLuigi Rizzo oce_dma_map_addr(void *arg, bus_dma_segment_t * segs, int nseg, int error)
1352f345d8eSLuigi Rizzo {
1362f345d8eSLuigi Rizzo 	bus_addr_t *paddr = arg;
1372f345d8eSLuigi Rizzo 
1382f345d8eSLuigi Rizzo 	if (error)
1392f345d8eSLuigi Rizzo 		*paddr = 0;
1402f345d8eSLuigi Rizzo 	else
1412f345d8eSLuigi Rizzo 		*paddr = segs->ds_addr;
1422f345d8eSLuigi Rizzo }
1432f345d8eSLuigi Rizzo 
1442f345d8eSLuigi Rizzo /**
1452f345d8eSLuigi Rizzo  * @brief		Destroy a ring buffer
1462f345d8eSLuigi Rizzo  * @param sc		software handle to the device
1472f345d8eSLuigi Rizzo  * @param ring		ring buffer
1482f345d8eSLuigi Rizzo  */
1492f345d8eSLuigi Rizzo 
1502f345d8eSLuigi Rizzo void
oce_destroy_ring_buffer(POCE_SOFTC sc,oce_ring_buffer_t * ring)1512f345d8eSLuigi Rizzo oce_destroy_ring_buffer(POCE_SOFTC sc, oce_ring_buffer_t *ring)
1522f345d8eSLuigi Rizzo {
1532f345d8eSLuigi Rizzo 	oce_dma_free(sc, &ring->dma);
1542f345d8eSLuigi Rizzo 	free(ring, M_DEVBUF);
1552f345d8eSLuigi Rizzo }
1562f345d8eSLuigi Rizzo 
1572f345d8eSLuigi Rizzo oce_ring_buffer_t *
oce_create_ring_buffer(POCE_SOFTC sc,uint32_t q_len,uint32_t item_size)1582f345d8eSLuigi Rizzo oce_create_ring_buffer(POCE_SOFTC sc,
1592f345d8eSLuigi Rizzo 		uint32_t q_len, uint32_t item_size)
1602f345d8eSLuigi Rizzo {
1612f345d8eSLuigi Rizzo 	uint32_t size = q_len * item_size;
1622f345d8eSLuigi Rizzo 	int rc;
1632f345d8eSLuigi Rizzo 	oce_ring_buffer_t *ring;
1642f345d8eSLuigi Rizzo 
1652f345d8eSLuigi Rizzo 	ring = malloc(sizeof(oce_ring_buffer_t), M_DEVBUF, M_NOWAIT | M_ZERO);
1662f345d8eSLuigi Rizzo 	if (ring == NULL)
1672f345d8eSLuigi Rizzo 		return NULL;
1682f345d8eSLuigi Rizzo 
1692f345d8eSLuigi Rizzo 	ring->item_size = item_size;
1702f345d8eSLuigi Rizzo 	ring->num_items = q_len;
1712f345d8eSLuigi Rizzo 
1722f345d8eSLuigi Rizzo 	rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
1732f345d8eSLuigi Rizzo 				4096, 0,
1742f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
1752f345d8eSLuigi Rizzo 				BUS_SPACE_MAXADDR,
1762f345d8eSLuigi Rizzo 				NULL, NULL,
1772f345d8eSLuigi Rizzo 				size, 8, 4096, 0, NULL, NULL, &ring->dma.tag);
1782f345d8eSLuigi Rizzo 	if (rc)
1792f345d8eSLuigi Rizzo 		goto fail;
1802f345d8eSLuigi Rizzo 
1812f345d8eSLuigi Rizzo 	rc = bus_dmamem_alloc(ring->dma.tag,
1822f345d8eSLuigi Rizzo 				&ring->dma.ptr,
1832f345d8eSLuigi Rizzo 				BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
1842f345d8eSLuigi Rizzo 				&ring->dma.map);
1852f345d8eSLuigi Rizzo 	if (rc)
1862f345d8eSLuigi Rizzo 		goto fail;
1872f345d8eSLuigi Rizzo 
1882f345d8eSLuigi Rizzo 	bzero(ring->dma.ptr, size);
1892f345d8eSLuigi Rizzo 	bus_dmamap_sync(ring->dma.tag, ring->dma.map,
1902f345d8eSLuigi Rizzo 			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1912f345d8eSLuigi Rizzo 	ring->dma.paddr = 0;
1922f345d8eSLuigi Rizzo 
1932f345d8eSLuigi Rizzo 	return ring;
1942f345d8eSLuigi Rizzo 
1952f345d8eSLuigi Rizzo fail:
1962f345d8eSLuigi Rizzo 	oce_dma_free(sc, &ring->dma);
1972f345d8eSLuigi Rizzo 	free(ring, M_DEVBUF);
1982f345d8eSLuigi Rizzo 	ring = NULL;
1992f345d8eSLuigi Rizzo 	return NULL;
2002f345d8eSLuigi Rizzo }
2012f345d8eSLuigi Rizzo 
2022f345d8eSLuigi Rizzo struct _oce_dmamap_paddr_table {
2032f345d8eSLuigi Rizzo 	uint32_t max_entries;
2042f345d8eSLuigi Rizzo 	uint32_t num_entries;
2052f345d8eSLuigi Rizzo 	struct phys_addr *paddrs;
2062f345d8eSLuigi Rizzo };
2072f345d8eSLuigi Rizzo 
2082f345d8eSLuigi Rizzo /**
2092f345d8eSLuigi Rizzo  * @brief		Map ring buffer
2102f345d8eSLuigi Rizzo  * @param arg		dma map phyical address table pointer
2112f345d8eSLuigi Rizzo  * @param segs		dma memory segments
2122f345d8eSLuigi Rizzo  * @param nseg		number of dma memory segments
2132f345d8eSLuigi Rizzo  * @param error		maps only if error is 0
2142f345d8eSLuigi Rizzo  */
2152f345d8eSLuigi Rizzo static void
oce_dma_map_ring(void * arg,bus_dma_segment_t * segs,int nseg,int error)2162f345d8eSLuigi Rizzo oce_dma_map_ring(void *arg, bus_dma_segment_t * segs, int nseg, int error)
2172f345d8eSLuigi Rizzo {
2182f345d8eSLuigi Rizzo 	int i;
2192f345d8eSLuigi Rizzo 	struct _oce_dmamap_paddr_table *dpt =
2202f345d8eSLuigi Rizzo 	    (struct _oce_dmamap_paddr_table *)arg;
2212f345d8eSLuigi Rizzo 
2222f345d8eSLuigi Rizzo 	if (error == 0) {
2232f345d8eSLuigi Rizzo 		if (nseg <= dpt->max_entries) {
2242f345d8eSLuigi Rizzo 			for (i = 0; i < nseg; i++) {
2252f345d8eSLuigi Rizzo 				dpt->paddrs[i].lo = ADDR_LO(segs[i].ds_addr);
2262f345d8eSLuigi Rizzo 				dpt->paddrs[i].hi = ADDR_HI(segs[i].ds_addr);
2272f345d8eSLuigi Rizzo 			}
2282f345d8eSLuigi Rizzo 			dpt->num_entries = nseg;
2292f345d8eSLuigi Rizzo 		}
2302f345d8eSLuigi Rizzo 	}
2312f345d8eSLuigi Rizzo }
2322f345d8eSLuigi Rizzo 
2332f345d8eSLuigi Rizzo /**
2342f345d8eSLuigi Rizzo  * @brief		Load bus dma map for a ring buffer
2352f345d8eSLuigi Rizzo  * @param ring		ring buffer pointer
2362f345d8eSLuigi Rizzo  * @param pa_list	physical address list
2372f345d8eSLuigi Rizzo  * @returns		number entries
2382f345d8eSLuigi Rizzo  */
2392f345d8eSLuigi Rizzo uint32_t
oce_page_list(oce_ring_buffer_t * ring,struct phys_addr * pa_list)2402f345d8eSLuigi Rizzo oce_page_list(oce_ring_buffer_t *ring, struct phys_addr *pa_list)
2412f345d8eSLuigi Rizzo {
2422f345d8eSLuigi Rizzo 	struct _oce_dmamap_paddr_table dpt;
2432f345d8eSLuigi Rizzo 
2442f345d8eSLuigi Rizzo 	dpt.max_entries = 8;
2452f345d8eSLuigi Rizzo 	dpt.num_entries = 0;
2462f345d8eSLuigi Rizzo 	dpt.paddrs = pa_list;
2472f345d8eSLuigi Rizzo 
2482f345d8eSLuigi Rizzo 	bus_dmamap_load(ring->dma.tag,
2492f345d8eSLuigi Rizzo 			ring->dma.map,
2502f345d8eSLuigi Rizzo 			ring->dma.ptr,
2512f345d8eSLuigi Rizzo 			ring->item_size * ring->num_items,
2522f345d8eSLuigi Rizzo 			oce_dma_map_ring, &dpt, BUS_DMA_NOWAIT);
2532f345d8eSLuigi Rizzo 
2542f345d8eSLuigi Rizzo 	return dpt.num_entries;
2552f345d8eSLuigi Rizzo }
256