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