xref: /freebsd/sys/dev/ocs_fc/ocs_os.c (revision 61a74c5ccd65d1a00a96779f16eda8c41ff3a426)
1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry  *
5ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry  *
8ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry  *
11ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry  *
15ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18ef270ab1SKenneth D. Merry  *
19ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry  *
31ef270ab1SKenneth D. Merry  * $FreeBSD$
32ef270ab1SKenneth D. Merry  */
33ef270ab1SKenneth D. Merry 
34ef270ab1SKenneth D. Merry /**
35ef270ab1SKenneth D. Merry  * @file
36ef270ab1SKenneth D. Merry  * Implementation of common BSD OS abstraction functions
37ef270ab1SKenneth D. Merry  */
38ef270ab1SKenneth D. Merry 
39ef270ab1SKenneth D. Merry #include "ocs.h"
40ef270ab1SKenneth D. Merry 
41ef270ab1SKenneth D. Merry static MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data");
42ef270ab1SKenneth D. Merry 
43ef270ab1SKenneth D. Merry #include <dev/pci/pcireg.h>
44ef270ab1SKenneth D. Merry #include <dev/pci/pcivar.h>
45ef270ab1SKenneth D. Merry 
46ef270ab1SKenneth D. Merry #include <machine/bus.h>
47ef270ab1SKenneth D. Merry 
485773ac11SJohn Baldwin callout_func_t	__ocs_callout;
49ef270ab1SKenneth D. Merry 
50ef270ab1SKenneth D. Merry uint32_t
51ef270ab1SKenneth D. Merry ocs_config_read32(ocs_os_handle_t os, uint32_t reg)
52ef270ab1SKenneth D. Merry {
53ef270ab1SKenneth D. Merry 	return pci_read_config(os->dev, reg, 4);
54ef270ab1SKenneth D. Merry }
55ef270ab1SKenneth D. Merry 
56ef270ab1SKenneth D. Merry uint16_t
57ef270ab1SKenneth D. Merry ocs_config_read16(ocs_os_handle_t os, uint32_t reg)
58ef270ab1SKenneth D. Merry {
59ef270ab1SKenneth D. Merry 	return pci_read_config(os->dev, reg, 2);
60ef270ab1SKenneth D. Merry }
61ef270ab1SKenneth D. Merry 
62ef270ab1SKenneth D. Merry uint8_t
63ef270ab1SKenneth D. Merry ocs_config_read8(ocs_os_handle_t os, uint32_t reg)
64ef270ab1SKenneth D. Merry {
65ef270ab1SKenneth D. Merry 	return pci_read_config(os->dev, reg, 1);
66ef270ab1SKenneth D. Merry }
67ef270ab1SKenneth D. Merry 
68ef270ab1SKenneth D. Merry void
69ef270ab1SKenneth D. Merry ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val)
70ef270ab1SKenneth D. Merry {
71ef270ab1SKenneth D. Merry 	return pci_write_config(os->dev, reg, val, 1);
72ef270ab1SKenneth D. Merry }
73ef270ab1SKenneth D. Merry 
74ef270ab1SKenneth D. Merry void
75ef270ab1SKenneth D. Merry ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val)
76ef270ab1SKenneth D. Merry {
77ef270ab1SKenneth D. Merry 	return pci_write_config(os->dev, reg, val, 2);
78ef270ab1SKenneth D. Merry }
79ef270ab1SKenneth D. Merry 
80ef270ab1SKenneth D. Merry void
81ef270ab1SKenneth D. Merry ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val)
82ef270ab1SKenneth D. Merry {
83ef270ab1SKenneth D. Merry 	return pci_write_config(os->dev, reg, val, 4);
84ef270ab1SKenneth D. Merry }
85ef270ab1SKenneth D. Merry 
86ef270ab1SKenneth D. Merry /**
87ef270ab1SKenneth D. Merry  * @ingroup os
88ef270ab1SKenneth D. Merry  * @brief Read a 32bit PCI register
89ef270ab1SKenneth D. Merry  *
90ef270ab1SKenneth D. Merry  * The SLI documentation uses the term "register set" to describe one or more
91ef270ab1SKenneth D. Merry  * PCI BARs which form a logical address. For example, a 64-bit address uses
92ef270ab1SKenneth D. Merry  * two BARs, and thus constitute a register set.
93ef270ab1SKenneth D. Merry  *
94ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
95ef270ab1SKenneth D. Merry  * @param rset Register Set to use
96ef270ab1SKenneth D. Merry  * @param off Offset from the base address of the Register Set
97ef270ab1SKenneth D. Merry  *
98ef270ab1SKenneth D. Merry  * @return register value
99ef270ab1SKenneth D. Merry  */
100ef270ab1SKenneth D. Merry uint32_t
101ef270ab1SKenneth D. Merry ocs_reg_read32(ocs_t *ocs, uint32_t rset, uint32_t off)
102ef270ab1SKenneth D. Merry {
103ef270ab1SKenneth D. Merry 	ocs_pci_reg_t		*reg = NULL;
104ef270ab1SKenneth D. Merry 
105ef270ab1SKenneth D. Merry 	reg = &ocs->reg[rset];
106ef270ab1SKenneth D. Merry 
107ef270ab1SKenneth D. Merry 	return bus_space_read_4(reg->btag, reg->bhandle, off);
108ef270ab1SKenneth D. Merry }
109ef270ab1SKenneth D. Merry 
110ef270ab1SKenneth D. Merry /**
111ef270ab1SKenneth D. Merry  * @ingroup os
112ef270ab1SKenneth D. Merry  * @brief Read a 16bit PCI register
113ef270ab1SKenneth D. Merry  *
114ef270ab1SKenneth D. Merry  * The SLI documentation uses the term "register set" to describe one or more
115ef270ab1SKenneth D. Merry  * PCI BARs which form a logical address. For example, a 64-bit address uses
116ef270ab1SKenneth D. Merry  * two BARs, and thus constitute a register set.
117ef270ab1SKenneth D. Merry  *
118ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
119ef270ab1SKenneth D. Merry  * @param rset Register Set to use
120ef270ab1SKenneth D. Merry  * @param off Offset from the base address of the Register Set
121ef270ab1SKenneth D. Merry  *
122ef270ab1SKenneth D. Merry  * @return register value
123ef270ab1SKenneth D. Merry  */
124ef270ab1SKenneth D. Merry uint16_t
125ef270ab1SKenneth D. Merry ocs_reg_read16(ocs_t *ocs, uint32_t rset, uint32_t off)
126ef270ab1SKenneth D. Merry {
127ef270ab1SKenneth D. Merry 	ocs_pci_reg_t		*reg = NULL;
128ef270ab1SKenneth D. Merry 
129ef270ab1SKenneth D. Merry 	reg = &ocs->reg[rset];
130ef270ab1SKenneth D. Merry 
131ef270ab1SKenneth D. Merry 	return bus_space_read_2(reg->btag, reg->bhandle, off);
132ef270ab1SKenneth D. Merry }
133ef270ab1SKenneth D. Merry 
134ef270ab1SKenneth D. Merry /**
135ef270ab1SKenneth D. Merry  * @ingroup os
136ef270ab1SKenneth D. Merry  * @brief Read a 8bit PCI register
137ef270ab1SKenneth D. Merry  *
138ef270ab1SKenneth D. Merry  * The SLI documentation uses the term "register set" to describe one or more
139ef270ab1SKenneth D. Merry  * PCI BARs which form a logical address. For example, a 64-bit address uses
140ef270ab1SKenneth D. Merry  * two BARs, and thus constitute a register set.
141ef270ab1SKenneth D. Merry  *
142ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
143ef270ab1SKenneth D. Merry  * @param rset Register Set to use
144ef270ab1SKenneth D. Merry  * @param off Offset from the base address of the Register Set
145ef270ab1SKenneth D. Merry  *
146ef270ab1SKenneth D. Merry  * @return register value
147ef270ab1SKenneth D. Merry  */
148ef270ab1SKenneth D. Merry uint8_t
149ef270ab1SKenneth D. Merry ocs_reg_read8(ocs_t *ocs, uint32_t rset, uint32_t off)
150ef270ab1SKenneth D. Merry {
151ef270ab1SKenneth D. Merry 	ocs_pci_reg_t		*reg = NULL;
152ef270ab1SKenneth D. Merry 
153ef270ab1SKenneth D. Merry 	reg = &ocs->reg[rset];
154ef270ab1SKenneth D. Merry 
155ef270ab1SKenneth D. Merry 	return bus_space_read_1(reg->btag, reg->bhandle, off);
156ef270ab1SKenneth D. Merry }
157ef270ab1SKenneth D. Merry 
158ef270ab1SKenneth D. Merry /**
159ef270ab1SKenneth D. Merry  * @ingroup os
160ef270ab1SKenneth D. Merry  * @brief Write a 32bit PCI register
161ef270ab1SKenneth D. Merry  *
162ef270ab1SKenneth D. Merry  * The SLI documentation uses the term "register set" to describe one or more
163ef270ab1SKenneth D. Merry  * PCI BARs which form a logical address. For example, a 64-bit address uses
164ef270ab1SKenneth D. Merry  * two BARs, and thus constitute a register set.
165ef270ab1SKenneth D. Merry  *
166ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
167ef270ab1SKenneth D. Merry  * @param rset Register Set to use
168ef270ab1SKenneth D. Merry  * @param off Offset from the base address of the Register Set
169ef270ab1SKenneth D. Merry  * @param val Value to write
170ef270ab1SKenneth D. Merry  *
171ef270ab1SKenneth D. Merry  * @return none
172ef270ab1SKenneth D. Merry  */
173ef270ab1SKenneth D. Merry void
174ef270ab1SKenneth D. Merry ocs_reg_write32(ocs_t *ocs, uint32_t rset, uint32_t off, uint32_t val)
175ef270ab1SKenneth D. Merry {
176ef270ab1SKenneth D. Merry 	ocs_pci_reg_t		*reg = NULL;
177ef270ab1SKenneth D. Merry 
178ef270ab1SKenneth D. Merry 	reg = &ocs->reg[rset];
179ef270ab1SKenneth D. Merry 
180ef270ab1SKenneth D. Merry 	return bus_space_write_4(reg->btag, reg->bhandle, off, val);
181ef270ab1SKenneth D. Merry }
182ef270ab1SKenneth D. Merry 
183ef270ab1SKenneth D. Merry /**
184ef270ab1SKenneth D. Merry  * @ingroup os
185ef270ab1SKenneth D. Merry  * @brief Write a 16-bit PCI register
186ef270ab1SKenneth D. Merry  *
187ef270ab1SKenneth D. Merry  * The SLI documentation uses the term "register set" to describe one or more
188ef270ab1SKenneth D. Merry  * PCI BARs which form a logical address. For example, a 64-bit address uses
189ef270ab1SKenneth D. Merry  * two BARs, and thus constitute a register set.
190ef270ab1SKenneth D. Merry  *
191ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
192ef270ab1SKenneth D. Merry  * @param rset Register Set to use
193ef270ab1SKenneth D. Merry  * @param off Offset from the base address of the Register Set
194ef270ab1SKenneth D. Merry  * @param val Value to write
195ef270ab1SKenneth D. Merry  *
196ef270ab1SKenneth D. Merry  * @return none
197ef270ab1SKenneth D. Merry  */
198ef270ab1SKenneth D. Merry void
199ef270ab1SKenneth D. Merry ocs_reg_write16(ocs_t *ocs, uint32_t rset, uint32_t off, uint16_t val)
200ef270ab1SKenneth D. Merry {
201ef270ab1SKenneth D. Merry 	ocs_pci_reg_t		*reg = NULL;
202ef270ab1SKenneth D. Merry 
203ef270ab1SKenneth D. Merry 	reg = &ocs->reg[rset];
204ef270ab1SKenneth D. Merry 
205ef270ab1SKenneth D. Merry 	return bus_space_write_2(reg->btag, reg->bhandle, off, val);
206ef270ab1SKenneth D. Merry }
207ef270ab1SKenneth D. Merry 
208ef270ab1SKenneth D. Merry /**
209ef270ab1SKenneth D. Merry  * @ingroup os
210ef270ab1SKenneth D. Merry  * @brief Write a 8-bit PCI register
211ef270ab1SKenneth D. Merry  *
212ef270ab1SKenneth D. Merry  * The SLI documentation uses the term "register set" to describe one or more
213ef270ab1SKenneth D. Merry  * PCI BARs which form a logical address. For example, a 64-bit address uses
214ef270ab1SKenneth D. Merry  * two BARs, and thus constitute a register set.
215ef270ab1SKenneth D. Merry  *
216ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
217ef270ab1SKenneth D. Merry  * @param rset Register Set to use
218ef270ab1SKenneth D. Merry  * @param off Offset from the base address of the Register Set
219ef270ab1SKenneth D. Merry  * @param val Value to write
220ef270ab1SKenneth D. Merry  *
221ef270ab1SKenneth D. Merry  * @return none
222ef270ab1SKenneth D. Merry  */
223ef270ab1SKenneth D. Merry void
224ef270ab1SKenneth D. Merry ocs_reg_write8(ocs_t *ocs, uint32_t rset, uint32_t off, uint8_t val)
225ef270ab1SKenneth D. Merry {
226ef270ab1SKenneth D. Merry 	ocs_pci_reg_t		*reg = NULL;
227ef270ab1SKenneth D. Merry 
228ef270ab1SKenneth D. Merry 	reg = &ocs->reg[rset];
229ef270ab1SKenneth D. Merry 
230ef270ab1SKenneth D. Merry 	return bus_space_write_1(reg->btag, reg->bhandle, off, val);
231ef270ab1SKenneth D. Merry }
232ef270ab1SKenneth D. Merry 
233ef270ab1SKenneth D. Merry /**
234ef270ab1SKenneth D. Merry  * @ingroup os
235ef270ab1SKenneth D. Merry  * @brief Allocate host memory
236ef270ab1SKenneth D. Merry  *
237ef270ab1SKenneth D. Merry  * @param os OS handle
238ef270ab1SKenneth D. Merry  * @param size number of bytes to allocate
239ef270ab1SKenneth D. Merry  * @param flags additional options
240ef270ab1SKenneth D. Merry  *
241ef270ab1SKenneth D. Merry  * @return pointer to allocated memory, NULL otherwise
242ef270ab1SKenneth D. Merry  */
243ef270ab1SKenneth D. Merry void *
244ef270ab1SKenneth D. Merry ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags)
245ef270ab1SKenneth D. Merry {
246ef270ab1SKenneth D. Merry 	if ((flags & OCS_M_NOWAIT) == 0) {
247ef270ab1SKenneth D. Merry 		flags |= M_WAITOK;
248ef270ab1SKenneth D. Merry 	}
249ef270ab1SKenneth D. Merry 
250ef270ab1SKenneth D. Merry #ifndef OCS_DEBUG_MEMORY
251ef270ab1SKenneth D. Merry 	return malloc(size, M_OCS, flags);
252ef270ab1SKenneth D. Merry #else
253ef270ab1SKenneth D. Merry 	char nameb[80];
254ef270ab1SKenneth D. Merry 	long offset = 0;
255ef270ab1SKenneth D. Merry 	void *addr = malloc(size, M_OCS, flags);
256ef270ab1SKenneth D. Merry 
257ef270ab1SKenneth D. Merry 	linker_ddb_search_symbol_name(__builtin_return_address(1), nameb, sizeof(nameb), &offset);
258ef270ab1SKenneth D. Merry 	printf("A: %p %ld @ %s+%#lx\n", addr, size, nameb, offset);
259ef270ab1SKenneth D. Merry 
260ef270ab1SKenneth D. Merry 	return addr;
261ef270ab1SKenneth D. Merry #endif
262ef270ab1SKenneth D. Merry }
263ef270ab1SKenneth D. Merry 
264ef270ab1SKenneth D. Merry /**
265ef270ab1SKenneth D. Merry  * @ingroup os
266ef270ab1SKenneth D. Merry  * @brief Free host memory
267ef270ab1SKenneth D. Merry  *
268ef270ab1SKenneth D. Merry  * @param os OS handle
269ef270ab1SKenneth D. Merry  * @param addr pointer to memory
270ef270ab1SKenneth D. Merry  * @param size bytes to free
271ef270ab1SKenneth D. Merry  *
272ef270ab1SKenneth D. Merry  * @note size ignored in BSD
273ef270ab1SKenneth D. Merry  */
274ef270ab1SKenneth D. Merry void
275ef270ab1SKenneth D. Merry ocs_free(ocs_os_handle_t os, void *addr, size_t size)
276ef270ab1SKenneth D. Merry {
277ef270ab1SKenneth D. Merry #ifndef OCS_DEBUG_MEMORY
278ef270ab1SKenneth D. Merry 	free(addr, M_OCS);
279ef270ab1SKenneth D. Merry #else
280ef270ab1SKenneth D. Merry 	printf("F: %p %ld\n", addr, size);
281ef270ab1SKenneth D. Merry 	free(addr, M_OCS);
282ef270ab1SKenneth D. Merry #endif
283ef270ab1SKenneth D. Merry }
284ef270ab1SKenneth D. Merry 
285ef270ab1SKenneth D. Merry /**
286ef270ab1SKenneth D. Merry  * @brief Callback function provided to bus_dmamap_load
287ef270ab1SKenneth D. Merry  *
288ef270ab1SKenneth D. Merry  * Function loads the physical / bus address into the DMA descriptor. The caller
289ef270ab1SKenneth D. Merry  * can detect a mapping failure if a descriptor's phys element is zero.
290ef270ab1SKenneth D. Merry  *
291ef270ab1SKenneth D. Merry  * @param arg Argument provided to bus_dmamap_load is a ocs_dma_t
292ef270ab1SKenneth D. Merry  * @param seg Array of DMA segment(s), each describing segment's address and length
293ef270ab1SKenneth D. Merry  * @param nseg Number of elements in array
294ef270ab1SKenneth D. Merry  * @param error Indicates success (0) or failure of mapping
295ef270ab1SKenneth D. Merry  */
296ef270ab1SKenneth D. Merry static void
297ef270ab1SKenneth D. Merry ocs_dma_load(void *arg, bus_dma_segment_t *seg, int nseg, int error)
298ef270ab1SKenneth D. Merry {
299ef270ab1SKenneth D. Merry 	ocs_dma_t	*dma = arg;
300ef270ab1SKenneth D. Merry 
301ef270ab1SKenneth D. Merry 	if (error) {
302ef270ab1SKenneth D. Merry 		printf("%s: error=%d\n", __func__, error);
303ef270ab1SKenneth D. Merry 		dma->phys = 0;
304ef270ab1SKenneth D. Merry 	} else {
305ef270ab1SKenneth D. Merry 		dma->phys = seg->ds_addr;
306ef270ab1SKenneth D. Merry 	}
307ef270ab1SKenneth D. Merry }
308ef270ab1SKenneth D. Merry 
309ef270ab1SKenneth D. Merry /**
310ef270ab1SKenneth D. Merry  * @ingroup os
311ef270ab1SKenneth D. Merry  * @brief Free a DMA capable block of memory
312ef270ab1SKenneth D. Merry  *
313ef270ab1SKenneth D. Merry  * @param os Device abstraction
314ef270ab1SKenneth D. Merry  * @param dma DMA descriptor for memory to be freed
315ef270ab1SKenneth D. Merry  *
316ef270ab1SKenneth D. Merry  * @return 0 if memory is de-allocated, -1 otherwise
317ef270ab1SKenneth D. Merry  */
318ef270ab1SKenneth D. Merry int32_t
319ef270ab1SKenneth D. Merry ocs_dma_free(ocs_os_handle_t os, ocs_dma_t *dma)
320ef270ab1SKenneth D. Merry {
321ef270ab1SKenneth D. Merry 	struct ocs_softc	*ocs = os;
322ef270ab1SKenneth D. Merry 
323ef270ab1SKenneth D. Merry 	if (!dma) {
324ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: bad parameter(s) dma=%p\n", __func__, dma);
325ef270ab1SKenneth D. Merry 		return -1;
326ef270ab1SKenneth D. Merry 	}
327ef270ab1SKenneth D. Merry 
328ef270ab1SKenneth D. Merry 	if (dma->size == 0) {
329ef270ab1SKenneth D. Merry 		return 0;
330ef270ab1SKenneth D. Merry 	}
331ef270ab1SKenneth D. Merry 
332ef270ab1SKenneth D. Merry 	if (dma->map) {
333ef270ab1SKenneth D. Merry 		bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD |
334ef270ab1SKenneth D. Merry 				BUS_DMASYNC_POSTWRITE);
335ef270ab1SKenneth D. Merry 		bus_dmamap_unload(dma->tag, dma->map);
336ef270ab1SKenneth D. Merry 	}
337ef270ab1SKenneth D. Merry 
338ef270ab1SKenneth D. Merry 	if (dma->virt) {
339ef270ab1SKenneth D. Merry 		bus_dmamem_free(dma->tag, dma->virt, dma->map);
340ef270ab1SKenneth D. Merry 		bus_dmamap_destroy(dma->tag, dma->map);
341ef270ab1SKenneth D. Merry 	}
342ef270ab1SKenneth D. Merry 	bus_dma_tag_destroy(dma->tag);
343ef270ab1SKenneth D. Merry 
344ef270ab1SKenneth D. Merry 	bzero(dma, sizeof(ocs_dma_t));
345ef270ab1SKenneth D. Merry 
346ef270ab1SKenneth D. Merry 	return 0;
347ef270ab1SKenneth D. Merry }
348ef270ab1SKenneth D. Merry 
349ef270ab1SKenneth D. Merry /**
350ef270ab1SKenneth D. Merry  * @ingroup os
351ef270ab1SKenneth D. Merry  * @brief Allocate a DMA capable block of memory
352ef270ab1SKenneth D. Merry  *
353ef270ab1SKenneth D. Merry  * @param os Device abstraction
354ef270ab1SKenneth D. Merry  * @param dma DMA descriptor containing results of memory allocation
355ef270ab1SKenneth D. Merry  * @param size Size in bytes of desired allocation
356ef270ab1SKenneth D. Merry  * @param align Alignment in bytes
357ef270ab1SKenneth D. Merry  *
358ef270ab1SKenneth D. Merry  * @return 0 on success, ENOMEM otherwise
359ef270ab1SKenneth D. Merry  */
360ef270ab1SKenneth D. Merry int32_t
361ef270ab1SKenneth D. Merry ocs_dma_alloc(ocs_os_handle_t os, ocs_dma_t *dma, size_t size, size_t align)
362ef270ab1SKenneth D. Merry {
363ef270ab1SKenneth D. Merry 	struct ocs_softc	*ocs = os;
364ef270ab1SKenneth D. Merry 
365ef270ab1SKenneth D. Merry 	if (!dma || !size) {
366ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s bad parameter(s) dma=%p size=%zd\n",
367ef270ab1SKenneth D. Merry 				__func__, dma, size);
368ef270ab1SKenneth D. Merry 		return ENOMEM;
369ef270ab1SKenneth D. Merry 	}
370ef270ab1SKenneth D. Merry 
371ef270ab1SKenneth D. Merry 	bzero(dma, sizeof(ocs_dma_t));
372ef270ab1SKenneth D. Merry 
373ef270ab1SKenneth D. Merry 	/* create a "tag" that describes the desired memory allocation */
374ef270ab1SKenneth D. Merry 	if (bus_dma_tag_create(ocs->dmat, align, 0, BUS_SPACE_MAXADDR,
375ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXADDR, NULL, NULL,
376ef270ab1SKenneth D. Merry 				size, 1, size, 0, NULL, NULL, &dma->tag)) {
377ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "DMA tag allocation failed\n");
378ef270ab1SKenneth D. Merry 		return ENOMEM;
379ef270ab1SKenneth D. Merry 	}
380ef270ab1SKenneth D. Merry 
381ef270ab1SKenneth D. Merry 	dma->size = size;
382ef270ab1SKenneth D. Merry 
383ef270ab1SKenneth D. Merry 	/* allocate the memory */
384ef270ab1SKenneth D. Merry 	if (bus_dmamem_alloc(dma->tag, &dma->virt, BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
385ef270ab1SKenneth D. Merry 				&dma->map)) {
386ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "DMA memory allocation failed s=%zd a=%zd\n", size, align);
387ef270ab1SKenneth D. Merry 		ocs_dma_free(ocs, dma);
388ef270ab1SKenneth D. Merry 		return ENOMEM;
389ef270ab1SKenneth D. Merry 	}
390ef270ab1SKenneth D. Merry 
391ef270ab1SKenneth D. Merry 	dma->alloc = dma->virt;
392ef270ab1SKenneth D. Merry 
393ef270ab1SKenneth D. Merry 	/* map virtual address to device visible address */
394ef270ab1SKenneth D. Merry 	if (bus_dmamap_load(dma->tag, dma->map, dma->virt, dma->size, ocs_dma_load,
395ef270ab1SKenneth D. Merry 				dma, 0)) {
396ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "DMA memory load failed\n");
397ef270ab1SKenneth D. Merry 		ocs_dma_free(ocs, dma);
398ef270ab1SKenneth D. Merry 		return ENOMEM;
399ef270ab1SKenneth D. Merry 	}
400ef270ab1SKenneth D. Merry 
401ef270ab1SKenneth D. Merry 	/* if the DMA map load callback fails, it sets the physical address to zero */
402ef270ab1SKenneth D. Merry 	if (0 == dma->phys) {
403ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "ocs_dma_load failed\n");
404ef270ab1SKenneth D. Merry 		ocs_dma_free(ocs, dma);
405ef270ab1SKenneth D. Merry 		return ENOMEM;
406ef270ab1SKenneth D. Merry 	}
407ef270ab1SKenneth D. Merry 
408ef270ab1SKenneth D. Merry 	return 0;
409ef270ab1SKenneth D. Merry }
410ef270ab1SKenneth D. Merry 
411ef270ab1SKenneth D. Merry /**
412ef270ab1SKenneth D. Merry  * @ingroup os
413ef270ab1SKenneth D. Merry  * @brief Synchronize the DMA buffer memory
414ef270ab1SKenneth D. Merry  *
415ef270ab1SKenneth D. Merry  * Ensures memory coherency between the CPU and device
416ef270ab1SKenneth D. Merry  *
417ef270ab1SKenneth D. Merry  * @param dma DMA descriptor of memory to synchronize
418ef270ab1SKenneth D. Merry  * @param flags Describes direction of synchronization
419ef270ab1SKenneth D. Merry  *   See BUS_DMA(9) for details
420ef270ab1SKenneth D. Merry  *   - BUS_DMASYNC_PREWRITE
421ef270ab1SKenneth D. Merry  *   - BUS_DMASYNC_POSTREAD
422ef270ab1SKenneth D. Merry  */
423ef270ab1SKenneth D. Merry void
424ef270ab1SKenneth D. Merry ocs_dma_sync(ocs_dma_t *dma, uint32_t flags)
425ef270ab1SKenneth D. Merry {
426ef270ab1SKenneth D. Merry 	bus_dmamap_sync(dma->tag, dma->map, flags);
427ef270ab1SKenneth D. Merry }
428ef270ab1SKenneth D. Merry 
429ef270ab1SKenneth D. Merry int32_t
430ef270ab1SKenneth D. Merry ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length)
431ef270ab1SKenneth D. Merry {
432ef270ab1SKenneth D. Merry 	if (!dma)
433ef270ab1SKenneth D. Merry 		return -1;
434ef270ab1SKenneth D. Merry 	if (!buffer)
435ef270ab1SKenneth D. Merry 		return -1;
436ef270ab1SKenneth D. Merry 	if (buffer_length == 0)
437ef270ab1SKenneth D. Merry 		return 0;
438ef270ab1SKenneth D. Merry 	if (buffer_length > dma->size)
439ef270ab1SKenneth D. Merry 		buffer_length = dma->size;
440ef270ab1SKenneth D. Merry 	ocs_memcpy(dma->virt, buffer, buffer_length);
441ef270ab1SKenneth D. Merry 	dma->len = buffer_length;
442ef270ab1SKenneth D. Merry 	return buffer_length;
443ef270ab1SKenneth D. Merry }
444ef270ab1SKenneth D. Merry 
445ef270ab1SKenneth D. Merry int32_t
446ef270ab1SKenneth D. Merry ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length)
447ef270ab1SKenneth D. Merry {
448ef270ab1SKenneth D. Merry 	if (!dma)
449ef270ab1SKenneth D. Merry 		return -1;
450ef270ab1SKenneth D. Merry 	if (!buffer)
451ef270ab1SKenneth D. Merry 		return -1;
452ef270ab1SKenneth D. Merry 	if (buffer_length == 0)
453ef270ab1SKenneth D. Merry 		return 0;
454ef270ab1SKenneth D. Merry 	if (buffer_length > dma->len)
455ef270ab1SKenneth D. Merry 		buffer_length = dma->len;
456ef270ab1SKenneth D. Merry 	ocs_memcpy(buffer, dma->virt, buffer_length);
457ef270ab1SKenneth D. Merry 	return buffer_length;
458ef270ab1SKenneth D. Merry }
459ef270ab1SKenneth D. Merry 
460ef270ab1SKenneth D. Merry /**
461ef270ab1SKenneth D. Merry  * @ingroup os
462ef270ab1SKenneth D. Merry  * @brief Initialize a lock
463ef270ab1SKenneth D. Merry  *
464ef270ab1SKenneth D. Merry  * @param lock lock to initialize
465ef270ab1SKenneth D. Merry  * @param name string identifier for the lock
466ef270ab1SKenneth D. Merry  */
467ef270ab1SKenneth D. Merry void
468ef270ab1SKenneth D. Merry ocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...)
469ef270ab1SKenneth D. Merry {
470ef270ab1SKenneth D. Merry 	va_list ap;
471ef270ab1SKenneth D. Merry 
472ef270ab1SKenneth D. Merry 	va_start(ap, name);
473ef270ab1SKenneth D. Merry 	ocs_vsnprintf(lock->name, MAX_LOCK_DESC_LEN, name, ap);
474ef270ab1SKenneth D. Merry 	va_end(ap);
475ef270ab1SKenneth D. Merry 
476ef270ab1SKenneth D. Merry 	mtx_init(&lock->lock, lock->name, NULL, MTX_DEF);
477ef270ab1SKenneth D. Merry }
478ef270ab1SKenneth D. Merry 
479ef270ab1SKenneth D. Merry /**
480ef270ab1SKenneth D. Merry  * @brief Allocate a bit map
481ef270ab1SKenneth D. Merry  *
482ef270ab1SKenneth D. Merry  * For BSD, this is a simple character string
483ef270ab1SKenneth D. Merry  *
484ef270ab1SKenneth D. Merry  * @param n_bits number of bits in bit map
485ef270ab1SKenneth D. Merry  *
486ef270ab1SKenneth D. Merry  * @return pointer to the bit map, NULL on error
487ef270ab1SKenneth D. Merry  */
488ef270ab1SKenneth D. Merry ocs_bitmap_t *
489ef270ab1SKenneth D. Merry ocs_bitmap_alloc(uint32_t n_bits)
490ef270ab1SKenneth D. Merry {
491ef270ab1SKenneth D. Merry 
492ef270ab1SKenneth D. Merry 	return malloc(bitstr_size(n_bits), M_OCS, M_ZERO | M_NOWAIT);
493ef270ab1SKenneth D. Merry }
494ef270ab1SKenneth D. Merry 
495ef270ab1SKenneth D. Merry /**
496ef270ab1SKenneth D. Merry  * @brief Free a bit map
497ef270ab1SKenneth D. Merry  *
498ef270ab1SKenneth D. Merry  * @param bitmap pointer to previously allocated bit map
499ef270ab1SKenneth D. Merry  */
500ef270ab1SKenneth D. Merry void
501ef270ab1SKenneth D. Merry ocs_bitmap_free(ocs_bitmap_t *bitmap)
502ef270ab1SKenneth D. Merry {
503ef270ab1SKenneth D. Merry 
504ef270ab1SKenneth D. Merry 	free(bitmap, M_OCS);
505ef270ab1SKenneth D. Merry }
506ef270ab1SKenneth D. Merry 
507ef270ab1SKenneth D. Merry /**
508ef270ab1SKenneth D. Merry  * @brief find next unset bit and set it
509ef270ab1SKenneth D. Merry  *
510ef270ab1SKenneth D. Merry  * @param bitmap bit map to search
511ef270ab1SKenneth D. Merry  * @param n_bits number of bits in map
512ef270ab1SKenneth D. Merry  *
513ef270ab1SKenneth D. Merry  * @return bit position or -1 if map is full
514ef270ab1SKenneth D. Merry  */
515ef270ab1SKenneth D. Merry int32_t
516ef270ab1SKenneth D. Merry ocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits)
517ef270ab1SKenneth D. Merry {
518ef270ab1SKenneth D. Merry 	int32_t		position = -1;
519ef270ab1SKenneth D. Merry 
520ef270ab1SKenneth D. Merry 	bit_ffc(bitmap, n_bits, &position);
521ef270ab1SKenneth D. Merry 
522ef270ab1SKenneth D. Merry 	if (-1 != position) {
523ef270ab1SKenneth D. Merry 		bit_set(bitmap, position);
524ef270ab1SKenneth D. Merry 	}
525ef270ab1SKenneth D. Merry 
526ef270ab1SKenneth D. Merry 	return position;
527ef270ab1SKenneth D. Merry }
528ef270ab1SKenneth D. Merry 
529ef270ab1SKenneth D. Merry /**
530ef270ab1SKenneth D. Merry  * @brief search for next (un)set bit
531ef270ab1SKenneth D. Merry  *
532ef270ab1SKenneth D. Merry  * @param bitmap bit map to search
533ef270ab1SKenneth D. Merry  * @param set search for a set or unset bit
534ef270ab1SKenneth D. Merry  * @param n_bits number of bits in map
535ef270ab1SKenneth D. Merry  *
536ef270ab1SKenneth D. Merry  * @return bit position or -1
537ef270ab1SKenneth D. Merry  */
538ef270ab1SKenneth D. Merry int32_t
539ef270ab1SKenneth D. Merry ocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits)
540ef270ab1SKenneth D. Merry {
541ef270ab1SKenneth D. Merry 	int32_t		position;
542ef270ab1SKenneth D. Merry 
543ef270ab1SKenneth D. Merry 	if (!bitmap) {
544ef270ab1SKenneth D. Merry 		return -1;
545ef270ab1SKenneth D. Merry 	}
546ef270ab1SKenneth D. Merry 
547ef270ab1SKenneth D. Merry 	if (set) {
548ef270ab1SKenneth D. Merry 		bit_ffs(bitmap, n_bits, &position);
549ef270ab1SKenneth D. Merry 	} else {
550ef270ab1SKenneth D. Merry 		bit_ffc(bitmap, n_bits, &position);
551ef270ab1SKenneth D. Merry 	}
552ef270ab1SKenneth D. Merry 
553ef270ab1SKenneth D. Merry 	return position;
554ef270ab1SKenneth D. Merry }
555ef270ab1SKenneth D. Merry 
556ef270ab1SKenneth D. Merry /**
557ef270ab1SKenneth D. Merry  * @brief clear the specified bit
558ef270ab1SKenneth D. Merry  *
559ef270ab1SKenneth D. Merry  * @param bitmap pointer to bit map
560ef270ab1SKenneth D. Merry  * @param bit bit number to clear
561ef270ab1SKenneth D. Merry  */
562ef270ab1SKenneth D. Merry void
563ef270ab1SKenneth D. Merry ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit)
564ef270ab1SKenneth D. Merry {
565ef270ab1SKenneth D. Merry 	bit_clear(bitmap, bit);
566ef270ab1SKenneth D. Merry }
567ef270ab1SKenneth D. Merry 
568ef270ab1SKenneth D. Merry void _ocs_log(ocs_t *ocs, const char *func_name, int line, const char *fmt, ...)
569ef270ab1SKenneth D. Merry {
570ef270ab1SKenneth D. Merry 	va_list ap;
571ef270ab1SKenneth D. Merry 	char buf[256];
572ef270ab1SKenneth D. Merry 	char *p = buf;
573ef270ab1SKenneth D. Merry 
574ef270ab1SKenneth D. Merry 	va_start(ap, fmt);
575ef270ab1SKenneth D. Merry 
576ef270ab1SKenneth D. Merry 	/* TODO: Add Current PID info here. */
577ef270ab1SKenneth D. Merry 
578ef270ab1SKenneth D. Merry 	p += snprintf(p, sizeof(buf) - (p - buf), "%s: ", DRV_NAME);
579ef270ab1SKenneth D. Merry 	p += snprintf(p, sizeof(buf) - (p - buf), "%s:", func_name);
580ef270ab1SKenneth D. Merry 	p += snprintf(p, sizeof(buf) - (p - buf), "%i:", line);
581ef270ab1SKenneth D. Merry 	p += snprintf(p, sizeof(buf) - (p - buf), "%s:", (ocs != NULL) ? device_get_nameunit(ocs->dev) : "");
582ef270ab1SKenneth D. Merry 	p += vsnprintf(p, sizeof(buf) - (p - buf), fmt, ap);
583ef270ab1SKenneth D. Merry 
584ef270ab1SKenneth D. Merry 	va_end(ap);
585ef270ab1SKenneth D. Merry 
586ef270ab1SKenneth D. Merry 	printf("%s", buf);
587ef270ab1SKenneth D. Merry }
588ef270ab1SKenneth D. Merry 
589ef270ab1SKenneth D. Merry /**
590ef270ab1SKenneth D. Merry  * @brief Common thread call function
591ef270ab1SKenneth D. Merry  *
592ef270ab1SKenneth D. Merry  * This is the common function called whenever a thread instantiated by ocs_thread_create() is started.
593ef270ab1SKenneth D. Merry  * It captures the return value from the actual thread function and stashes it in the thread object, to
594ef270ab1SKenneth D. Merry  * be later retrieved by ocs_thread_get_retval(), and calls kthread_exit(), the proscribed method to terminate
595ef270ab1SKenneth D. Merry  * a thread.
596ef270ab1SKenneth D. Merry  *
597ef270ab1SKenneth D. Merry  * @param arg a pointer to the thread object
598ef270ab1SKenneth D. Merry  *
599ef270ab1SKenneth D. Merry  * @return none
600ef270ab1SKenneth D. Merry  */
601ef270ab1SKenneth D. Merry 
602ef270ab1SKenneth D. Merry static void
603ef270ab1SKenneth D. Merry ocs_thread_call_fctn(void *arg)
604ef270ab1SKenneth D. Merry {
605ef270ab1SKenneth D. Merry 	ocs_thread_t *thread = arg;
606ef270ab1SKenneth D. Merry 	thread->retval = (*thread->fctn)(thread->arg);
607ef270ab1SKenneth D. Merry 	ocs_free(NULL, thread->name, ocs_strlen(thread->name+1));
608ef270ab1SKenneth D. Merry 	kthread_exit();
609ef270ab1SKenneth D. Merry }
610ef270ab1SKenneth D. Merry 
611ef270ab1SKenneth D. Merry /**
612ef270ab1SKenneth D. Merry  * @brief Create a kernel thread
613ef270ab1SKenneth D. Merry  *
614ef270ab1SKenneth D. Merry  * Creates a kernel thread and optionally starts it.   If the thread is not immediately
615ef270ab1SKenneth D. Merry  * started, ocs_thread_start() should be called at some later point.
616ef270ab1SKenneth D. Merry  *
617ef270ab1SKenneth D. Merry  * @param os OS handle
618ef270ab1SKenneth D. Merry  * @param thread pointer to thread object
619ef270ab1SKenneth D. Merry  * @param fctn function for thread to be begin executing
620ef270ab1SKenneth D. Merry  * @param name text name to identify thread
621ef270ab1SKenneth D. Merry  * @param arg application specific argument passed to thread function
622ef270ab1SKenneth D. Merry  * @param start start option, OCS_THREAD_RUN will start the thread immediately,
623ef270ab1SKenneth D. Merry  *			OCS_THREAD_CREATE will create but not start the thread
624ef270ab1SKenneth D. Merry  *
625ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
626ef270ab1SKenneth D. Merry  */
627ef270ab1SKenneth D. Merry 
628ef270ab1SKenneth D. Merry int32_t
629ef270ab1SKenneth D. Merry ocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn, const char *name, void *arg, ocs_thread_start_e start)
630ef270ab1SKenneth D. Merry {
631ef270ab1SKenneth D. Merry 	int32_t rc = 0;
632ef270ab1SKenneth D. Merry 
633e440863eSKenneth D. Merry 	ocs_memset(thread, 0, sizeof(*thread));
634ef270ab1SKenneth D. Merry 
635ef270ab1SKenneth D. Merry 	thread->fctn = fctn;
636ef270ab1SKenneth D. Merry 	thread->name = ocs_strdup(name);
637ef270ab1SKenneth D. Merry 	if (thread->name == NULL) {
638ef270ab1SKenneth D. Merry 		thread->name = "unknown";
639ef270ab1SKenneth D. Merry 	}
640ef270ab1SKenneth D. Merry 	thread->arg = arg;
641ef270ab1SKenneth D. Merry 
642ef270ab1SKenneth D. Merry 	ocs_atomic_set(&thread->terminate, 0);
643ef270ab1SKenneth D. Merry 
644ef270ab1SKenneth D. Merry 	rc = kthread_add(ocs_thread_call_fctn, thread, NULL, &thread->tcb, (start == OCS_THREAD_CREATE) ? RFSTOPPED : 0,
645ef270ab1SKenneth D. Merry 		OCS_THREAD_DEFAULT_STACK_SIZE_PAGES, "%s", name);
646ef270ab1SKenneth D. Merry 
647ef270ab1SKenneth D. Merry 	return rc;
648ef270ab1SKenneth D. Merry }
649ef270ab1SKenneth D. Merry 
650ef270ab1SKenneth D. Merry /**
651ef270ab1SKenneth D. Merry  * @brief Start a thread
652ef270ab1SKenneth D. Merry  *
653ef270ab1SKenneth D. Merry  * Starts a thread that was created with OCS_THREAD_CREATE rather than OCS_THREAD_RUN
654ef270ab1SKenneth D. Merry  *
655ef270ab1SKenneth D. Merry  * @param thread pointer to thread object
656ef270ab1SKenneth D. Merry  *
657ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
658ef270ab1SKenneth D. Merry  */
659ef270ab1SKenneth D. Merry 
660ef270ab1SKenneth D. Merry int32_t ocs_thread_start(ocs_thread_t *thread)
661ef270ab1SKenneth D. Merry {
662*61a74c5cSJeff Roberson 
663*61a74c5cSJeff Roberson 	thread_lock(thread->tcb);
664ef270ab1SKenneth D. Merry 	sched_add(thread->tcb, SRQ_BORING);
665ef270ab1SKenneth D. Merry 	return 0;
666ef270ab1SKenneth D. Merry }
667ef270ab1SKenneth D. Merry 
668ef270ab1SKenneth D. Merry /**
669ef270ab1SKenneth D. Merry  * @brief return thread argument
670ef270ab1SKenneth D. Merry  *
671ef270ab1SKenneth D. Merry  * Returns a pointer to the thread's application specific argument
672ef270ab1SKenneth D. Merry  *
673ef270ab1SKenneth D. Merry  * @param mythread pointer to the thread object
674ef270ab1SKenneth D. Merry  *
675ef270ab1SKenneth D. Merry  * @return pointer to application specific argument
676ef270ab1SKenneth D. Merry  */
677ef270ab1SKenneth D. Merry 
678ef270ab1SKenneth D. Merry void *ocs_thread_get_arg(ocs_thread_t *mythread)
679ef270ab1SKenneth D. Merry {
680ef270ab1SKenneth D. Merry 	return mythread->arg;
681ef270ab1SKenneth D. Merry }
682ef270ab1SKenneth D. Merry 
683ef270ab1SKenneth D. Merry /**
684ef270ab1SKenneth D. Merry  * @brief Request thread stop
685ef270ab1SKenneth D. Merry  *
686ef270ab1SKenneth D. Merry  * A stop request is made to the thread.  This is a voluntary call, the thread needs
687ef270ab1SKenneth D. Merry  * to periodically query its terminate request using ocs_thread_terminate_requested()
688ef270ab1SKenneth D. Merry  *
689ef270ab1SKenneth D. Merry  * @param thread pointer to thread object
690ef270ab1SKenneth D. Merry  *
691ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
692ef270ab1SKenneth D. Merry  */
693ef270ab1SKenneth D. Merry 
694ef270ab1SKenneth D. Merry int32_t
695ef270ab1SKenneth D. Merry ocs_thread_terminate(ocs_thread_t *thread)
696ef270ab1SKenneth D. Merry {
697ef270ab1SKenneth D. Merry 	ocs_atomic_set(&thread->terminate, 1);
698ef270ab1SKenneth D. Merry 	return 0;
699ef270ab1SKenneth D. Merry }
700ef270ab1SKenneth D. Merry 
701ef270ab1SKenneth D. Merry /**
702ef270ab1SKenneth D. Merry  * @brief See if a terminate request has been made
703ef270ab1SKenneth D. Merry  *
704ef270ab1SKenneth D. Merry  * Check to see if a stop request has been made to the current thread.  This
705ef270ab1SKenneth D. Merry  * function would be used by a thread to see if it should terminate.
706ef270ab1SKenneth D. Merry  *
707ef270ab1SKenneth D. Merry  * @return returns non-zero if a stop has been requested
708ef270ab1SKenneth D. Merry  */
709ef270ab1SKenneth D. Merry 
710ef270ab1SKenneth D. Merry int32_t ocs_thread_terminate_requested(ocs_thread_t *thread)
711ef270ab1SKenneth D. Merry {
712ef270ab1SKenneth D. Merry 	return ocs_atomic_read(&thread->terminate);
713ef270ab1SKenneth D. Merry }
714ef270ab1SKenneth D. Merry 
715ef270ab1SKenneth D. Merry /**
716ef270ab1SKenneth D. Merry  * @brief Retrieve threads return value
717ef270ab1SKenneth D. Merry  *
718ef270ab1SKenneth D. Merry  * After a thread has terminated, it's return value may be retrieved with this function.
719ef270ab1SKenneth D. Merry  *
720ef270ab1SKenneth D. Merry  * @param thread pointer to thread object
721ef270ab1SKenneth D. Merry  *
722ef270ab1SKenneth D. Merry  * @return return value from thread function
723ef270ab1SKenneth D. Merry  */
724ef270ab1SKenneth D. Merry 
725ef270ab1SKenneth D. Merry int32_t
726ef270ab1SKenneth D. Merry ocs_thread_get_retval(ocs_thread_t *thread)
727ef270ab1SKenneth D. Merry {
728ef270ab1SKenneth D. Merry 	return thread->retval;
729ef270ab1SKenneth D. Merry }
730ef270ab1SKenneth D. Merry 
731ef270ab1SKenneth D. Merry /**
732ef270ab1SKenneth D. Merry  * @brief Request that the currently running thread yield
733ef270ab1SKenneth D. Merry  *
734ef270ab1SKenneth D. Merry  * The currently running thread yields to the scheduler
735ef270ab1SKenneth D. Merry  *
736ef270ab1SKenneth D. Merry  * @param thread pointer to thread (ignored)
737ef270ab1SKenneth D. Merry  *
738ef270ab1SKenneth D. Merry  * @return none
739ef270ab1SKenneth D. Merry  */
740ef270ab1SKenneth D. Merry 
741ef270ab1SKenneth D. Merry void
742ef270ab1SKenneth D. Merry ocs_thread_yield(ocs_thread_t *thread) {
743ef270ab1SKenneth D. Merry 	pause("thread yield", 1);
744ef270ab1SKenneth D. Merry }
745ef270ab1SKenneth D. Merry 
746ef270ab1SKenneth D. Merry ocs_thread_t *
747ef270ab1SKenneth D. Merry ocs_thread_self(void)
748ef270ab1SKenneth D. Merry {
749ef270ab1SKenneth D. Merry 	ocs_printf(">>> %s not implemented\n", __func__);
750ef270ab1SKenneth D. Merry 	ocs_abort();
751ef270ab1SKenneth D. Merry }
752ef270ab1SKenneth D. Merry 
753ef270ab1SKenneth D. Merry int32_t
754ef270ab1SKenneth D. Merry ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu)
755ef270ab1SKenneth D. Merry {
756ef270ab1SKenneth D. Merry 	ocs_printf(">>> %s not implemented\n", __func__);
757ef270ab1SKenneth D. Merry 	return -1;
758ef270ab1SKenneth D. Merry }
759ef270ab1SKenneth D. Merry 
760ef270ab1SKenneth D. Merry int32_t
761ef270ab1SKenneth D. Merry ocs_thread_getcpu(void)
762ef270ab1SKenneth D. Merry {
763ef270ab1SKenneth D. Merry 	return curcpu;
764ef270ab1SKenneth D. Merry }
765ef270ab1SKenneth D. Merry 
766ef270ab1SKenneth D. Merry int
767ef270ab1SKenneth D. Merry ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...)
768ef270ab1SKenneth D. Merry {
769ef270ab1SKenneth D. Merry 	va_list ap;
770ef270ab1SKenneth D. Merry 
771ef270ab1SKenneth D. Merry 	va_start(ap, name);
772ef270ab1SKenneth D. Merry 	ocs_vsnprintf(sem->name, sizeof(sem->name), name, ap);
773ef270ab1SKenneth D. Merry 	va_end(ap);
774ef270ab1SKenneth D. Merry 
775ef270ab1SKenneth D. Merry 	sema_init(&sem->sem, val, sem->name);
776ef270ab1SKenneth D. Merry 	return 0;
777ef270ab1SKenneth D. Merry }
778ef270ab1SKenneth D. Merry 
779ef270ab1SKenneth D. Merry /**
780ef270ab1SKenneth D. Merry  * @ingroup os
781ef270ab1SKenneth D. Merry  * @brief  Copy user arguments in to kernel space for an ioctl
782ef270ab1SKenneth D. Merry  * @par Description
783ef270ab1SKenneth D. Merry  * This function is called at the beginning of an ioctl function
784ef270ab1SKenneth D. Merry  * to copy the ioctl argument from user space to kernel space.
785ef270ab1SKenneth D. Merry  *
786ef270ab1SKenneth D. Merry  * BSD handles this for us - arg is already in kernel space,
787ef270ab1SKenneth D. Merry  * so we just return it.
788ef270ab1SKenneth D. Merry  *
789ef270ab1SKenneth D. Merry  * @param os OS handle
790ef270ab1SKenneth D. Merry  * @param arg The argument passed to the ioctl function
791ef270ab1SKenneth D. Merry  * @param size The size of the structure pointed to by arg
792ef270ab1SKenneth D. Merry  *
793ef270ab1SKenneth D. Merry  * @return A pointer to a kernel space copy of the argument on
794ef270ab1SKenneth D. Merry  *	success; NULL on failure
795ef270ab1SKenneth D. Merry  */
796ef270ab1SKenneth D. Merry void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size)
797ef270ab1SKenneth D. Merry {
798ef270ab1SKenneth D. Merry 	 return arg;
799ef270ab1SKenneth D. Merry }
800ef270ab1SKenneth D. Merry 
801ef270ab1SKenneth D. Merry /**
802ef270ab1SKenneth D. Merry  * @ingroup os
803ef270ab1SKenneth D. Merry  * @brief  Copy results of an ioctl back to user space
804ef270ab1SKenneth D. Merry  * @par Description
805ef270ab1SKenneth D. Merry  * This function is called at the end of ioctl processing to
806ef270ab1SKenneth D. Merry  * copy the argument back to user space.
807ef270ab1SKenneth D. Merry  *
808ef270ab1SKenneth D. Merry  * BSD handles this for us.
809ef270ab1SKenneth D. Merry  *
810ef270ab1SKenneth D. Merry  * @param os OS handle
811ef270ab1SKenneth D. Merry  * @param arg The argument passed to the ioctl function
812ef270ab1SKenneth D. Merry  * @param kern_ptr A pointer to the kernel space copy of the
813ef270ab1SKenneth D. Merry  *		   argument
814ef270ab1SKenneth D. Merry  * @param size The size of the structure pointed to by arg.
815ef270ab1SKenneth D. Merry  *
816ef270ab1SKenneth D. Merry  * @return Returns 0.
817ef270ab1SKenneth D. Merry  */
818ef270ab1SKenneth D. Merry int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size)
819ef270ab1SKenneth D. Merry {
820ef270ab1SKenneth D. Merry 	return 0;
821ef270ab1SKenneth D. Merry }
822ef270ab1SKenneth D. Merry 
823ef270ab1SKenneth D. Merry /**
824ef270ab1SKenneth D. Merry  * @ingroup os
825ef270ab1SKenneth D. Merry  * @brief  Free memory allocated by ocs_ioctl_preprocess
826ef270ab1SKenneth D. Merry  * @par Description
827ef270ab1SKenneth D. Merry  * This function is called in the event of an error in ioctl
828ef270ab1SKenneth D. Merry  * processing.  For operating environments where ocs_ioctlpreprocess
829ef270ab1SKenneth D. Merry  * allocates memory, this call frees the memory without copying
830ef270ab1SKenneth D. Merry  * results back to user space.
831ef270ab1SKenneth D. Merry  *
832ef270ab1SKenneth D. Merry  * For BSD, because no memory was allocated in ocs_ioctl_preprocess,
833ef270ab1SKenneth D. Merry  * nothing needs to be done here.
834ef270ab1SKenneth D. Merry  *
835ef270ab1SKenneth D. Merry  * @param os OS handle
836ef270ab1SKenneth D. Merry  * @param kern_ptr A pointer to the kernel space copy of the
837ef270ab1SKenneth D. Merry  *		   argument
838ef270ab1SKenneth D. Merry  * @param size The size of the structure pointed to by arg.
839ef270ab1SKenneth D. Merry  *
840ef270ab1SKenneth D. Merry  * @return Returns nothing.
841ef270ab1SKenneth D. Merry  */
842ef270ab1SKenneth D. Merry void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size)
843ef270ab1SKenneth D. Merry {
844ef270ab1SKenneth D. Merry 	return;
845ef270ab1SKenneth D. Merry }
846ef270ab1SKenneth D. Merry 
847ef270ab1SKenneth D. Merry void ocs_intr_disable(ocs_os_handle_t os)
848ef270ab1SKenneth D. Merry {
849ef270ab1SKenneth D. Merry }
850ef270ab1SKenneth D. Merry 
851ef270ab1SKenneth D. Merry void ocs_intr_enable(ocs_os_handle_t os)
852ef270ab1SKenneth D. Merry {
853ef270ab1SKenneth D. Merry }
854ef270ab1SKenneth D. Merry 
855ef270ab1SKenneth D. Merry void ocs_print_stack(void)
856ef270ab1SKenneth D. Merry {
85780b5058dSRam Kishore Vegesna #if defined(STACK)
858ef270ab1SKenneth D. Merry 	struct stack st;
859ef270ab1SKenneth D. Merry 
860ef270ab1SKenneth D. Merry 	stack_zero(&st);
861ef270ab1SKenneth D. Merry 	stack_save(&st);
862ef270ab1SKenneth D. Merry 	stack_print(&st);
86380b5058dSRam Kishore Vegesna #endif
864ef270ab1SKenneth D. Merry }
865ef270ab1SKenneth D. Merry 
866ef270ab1SKenneth D. Merry void ocs_abort(void)
867ef270ab1SKenneth D. Merry {
868ef270ab1SKenneth D. Merry 	panic(">>> abort/panic\n");
869ef270ab1SKenneth D. Merry }
870ef270ab1SKenneth D. Merry 
871ef270ab1SKenneth D. Merry const char *
872ef270ab1SKenneth D. Merry ocs_pci_model(uint16_t vendor, uint16_t device)
873ef270ab1SKenneth D. Merry {
874ef270ab1SKenneth D. Merry 	switch (device) {
875ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_OCE16002:	return "OCE16002";
876ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_OCE1600_VF:	return "OCE1600_VF";
877ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_OCE50102:	return "OCE50102";
878ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_OCE50102_VF:	return "OCE50102_VR";
879ef270ab1SKenneth D. Merry 	default:
880ef270ab1SKenneth D. Merry 		break;
881ef270ab1SKenneth D. Merry 	}
882ef270ab1SKenneth D. Merry 
883ef270ab1SKenneth D. Merry 	return "unknown";
884ef270ab1SKenneth D. Merry }
885ef270ab1SKenneth D. Merry 
886ef270ab1SKenneth D. Merry int32_t
887ef270ab1SKenneth D. Merry ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func)
888ef270ab1SKenneth D. Merry {
889ef270ab1SKenneth D. Merry 	*bus = pci_get_bus(ocs->dev);
890ef270ab1SKenneth D. Merry 	*dev = pci_get_slot(ocs->dev);
891ef270ab1SKenneth D. Merry 	*func= pci_get_function(ocs->dev);
892ef270ab1SKenneth D. Merry 	return 0;
893ef270ab1SKenneth D. Merry }
894ef270ab1SKenneth D. Merry 
895ef270ab1SKenneth D. Merry /**
896ef270ab1SKenneth D. Merry  * @brief return CPU information
897ef270ab1SKenneth D. Merry  *
898ef270ab1SKenneth D. Merry  * This function populates the ocs_cpuinfo_t buffer with CPU information
899ef270ab1SKenneth D. Merry  *
900ef270ab1SKenneth D. Merry  * @param cpuinfo pointer to ocs_cpuinfo_t buffer
901ef270ab1SKenneth D. Merry  *
902ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
903ef270ab1SKenneth D. Merry  */
904ef270ab1SKenneth D. Merry extern int mp_ncpus;
905ef270ab1SKenneth D. Merry int32_t
906ef270ab1SKenneth D. Merry ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo)
907ef270ab1SKenneth D. Merry {
908ef270ab1SKenneth D. Merry 	cpuinfo->num_cpus = mp_ncpus;
909ef270ab1SKenneth D. Merry 	return 0;
910ef270ab1SKenneth D. Merry }
911ef270ab1SKenneth D. Merry 
912ef270ab1SKenneth D. Merry uint32_t
913ef270ab1SKenneth D. Merry ocs_get_num_cpus(void)
914ef270ab1SKenneth D. Merry {
915ef270ab1SKenneth D. Merry 	static ocs_cpuinfo_t cpuinfo;
916ef270ab1SKenneth D. Merry 
917ef270ab1SKenneth D. Merry 	if (cpuinfo.num_cpus == 0) {
918ef270ab1SKenneth D. Merry 		ocs_get_cpuinfo(&cpuinfo);
919ef270ab1SKenneth D. Merry 	}
920ef270ab1SKenneth D. Merry 	return cpuinfo.num_cpus;
921ef270ab1SKenneth D. Merry }
922ef270ab1SKenneth D. Merry 
923ef270ab1SKenneth D. Merry 
924ef270ab1SKenneth D. Merry void
925ef270ab1SKenneth D. Merry __ocs_callout(void *t)
926ef270ab1SKenneth D. Merry {
927ef270ab1SKenneth D. Merry 	ocs_timer_t *timer = t;
928ef270ab1SKenneth D. Merry 
929ef270ab1SKenneth D. Merry 	if (callout_pending(&timer->callout)) {
930ef270ab1SKenneth D. Merry 		/* Callout was reset */
931ef270ab1SKenneth D. Merry 		return;
932ef270ab1SKenneth D. Merry 	}
933ef270ab1SKenneth D. Merry 
934ef270ab1SKenneth D. Merry 	if (!callout_active(&timer->callout)) {
935ef270ab1SKenneth D. Merry 		/* Callout was stopped */
936ef270ab1SKenneth D. Merry 		return;
937ef270ab1SKenneth D. Merry 	}
938ef270ab1SKenneth D. Merry 
939ef270ab1SKenneth D. Merry 	callout_deactivate(&timer->callout);
940ef270ab1SKenneth D. Merry 
941ef270ab1SKenneth D. Merry 	if (timer->func) {
942ef270ab1SKenneth D. Merry 		timer->func(timer->data);
943ef270ab1SKenneth D. Merry 	}
944ef270ab1SKenneth D. Merry }
945ef270ab1SKenneth D. Merry 
946ef270ab1SKenneth D. Merry int32_t
947ef270ab1SKenneth D. Merry ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), void *data, uint32_t timeout_ms)
948ef270ab1SKenneth D. Merry {
949ef270ab1SKenneth D. Merry 	struct	timeval tv;
950ef270ab1SKenneth D. Merry 	int	hz;
951ef270ab1SKenneth D. Merry 
952ef270ab1SKenneth D. Merry 	if (timer == NULL) {
953ef270ab1SKenneth D. Merry 		ocs_log_err(NULL, "bad parameter\n");
954ef270ab1SKenneth D. Merry 		return -1;
955ef270ab1SKenneth D. Merry 	}
956ef270ab1SKenneth D. Merry 
957ef270ab1SKenneth D. Merry 	if (!mtx_initialized(&timer->lock)) {
958ef270ab1SKenneth D. Merry 		mtx_init(&timer->lock, "ocs_timer", NULL, MTX_DEF);
959ef270ab1SKenneth D. Merry 	}
960ef270ab1SKenneth D. Merry 
961ef270ab1SKenneth D. Merry 	callout_init_mtx(&timer->callout, &timer->lock, 0);
962ef270ab1SKenneth D. Merry 
963ef270ab1SKenneth D. Merry 	timer->func = func;
964ef270ab1SKenneth D. Merry 	timer->data = data;
965ef270ab1SKenneth D. Merry 
966ef270ab1SKenneth D. Merry 	tv.tv_sec  = timeout_ms / 1000;
967ef270ab1SKenneth D. Merry 	tv.tv_usec = (timeout_ms % 1000) * 1000;
968ef270ab1SKenneth D. Merry 
969ef270ab1SKenneth D. Merry 	hz = tvtohz(&tv);
970ef270ab1SKenneth D. Merry 	if (hz < 0)
971ef270ab1SKenneth D. Merry 		hz = INT32_MAX;
972ef270ab1SKenneth D. Merry 	if (hz == 0)
973ef270ab1SKenneth D. Merry 		hz = 1;
974ef270ab1SKenneth D. Merry 
975ef270ab1SKenneth D. Merry 	mtx_lock(&timer->lock);
976ef270ab1SKenneth D. Merry 		callout_reset(&timer->callout, hz, __ocs_callout, timer);
977ef270ab1SKenneth D. Merry 	mtx_unlock(&timer->lock);
978ef270ab1SKenneth D. Merry 
979ef270ab1SKenneth D. Merry 	return 0;
980ef270ab1SKenneth D. Merry }
981ef270ab1SKenneth D. Merry 
982ef270ab1SKenneth D. Merry int32_t
983ef270ab1SKenneth D. Merry ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms)
984ef270ab1SKenneth D. Merry {
985ef270ab1SKenneth D. Merry 	struct	timeval tv;
986ef270ab1SKenneth D. Merry 	int	hz;
987ef270ab1SKenneth D. Merry 
988ef270ab1SKenneth D. Merry 	if (timer == NULL) {
989ef270ab1SKenneth D. Merry 		ocs_log_err(NULL, "bad parameter\n");
990ef270ab1SKenneth D. Merry 		return -1;
991ef270ab1SKenneth D. Merry 	}
992ef270ab1SKenneth D. Merry 
993ef270ab1SKenneth D. Merry 	tv.tv_sec  = timeout_ms / 1000;
994ef270ab1SKenneth D. Merry 	tv.tv_usec = (timeout_ms % 1000) * 1000;
995ef270ab1SKenneth D. Merry 
996ef270ab1SKenneth D. Merry 	hz = tvtohz(&tv);
997ef270ab1SKenneth D. Merry 	if (hz < 0)
998ef270ab1SKenneth D. Merry 		hz = INT32_MAX;
999ef270ab1SKenneth D. Merry 	if (hz == 0)
1000ef270ab1SKenneth D. Merry 		hz = 1;
1001ef270ab1SKenneth D. Merry 
1002ef270ab1SKenneth D. Merry 	mtx_lock(&timer->lock);
1003ef270ab1SKenneth D. Merry 		callout_reset(&timer->callout, hz, __ocs_callout, timer);
1004ef270ab1SKenneth D. Merry 	mtx_unlock(&timer->lock);
1005ef270ab1SKenneth D. Merry 
1006ef270ab1SKenneth D. Merry 	return 0;
1007ef270ab1SKenneth D. Merry }
1008ef270ab1SKenneth D. Merry 
1009ef270ab1SKenneth D. Merry int32_t
1010ef270ab1SKenneth D. Merry ocs_timer_pending(ocs_timer_t *timer)
1011ef270ab1SKenneth D. Merry {
1012ef270ab1SKenneth D. Merry 	return callout_active(&timer->callout);
1013ef270ab1SKenneth D. Merry }
1014ef270ab1SKenneth D. Merry 
1015ef270ab1SKenneth D. Merry int32_t
1016ef270ab1SKenneth D. Merry ocs_del_timer(ocs_timer_t *timer)
1017ef270ab1SKenneth D. Merry {
1018ef270ab1SKenneth D. Merry 
1019ef270ab1SKenneth D. Merry 	mtx_lock(&timer->lock);
1020ef270ab1SKenneth D. Merry 		callout_stop(&timer->callout);
1021ef270ab1SKenneth D. Merry 	mtx_unlock(&timer->lock);
1022ef270ab1SKenneth D. Merry 
1023ef270ab1SKenneth D. Merry 	return 0;
1024ef270ab1SKenneth D. Merry }
1025ef270ab1SKenneth D. Merry 
1026ef270ab1SKenneth D. Merry char *
1027ef270ab1SKenneth D. Merry ocs_strdup(const char *s)
1028ef270ab1SKenneth D. Merry {
1029ef270ab1SKenneth D. Merry 	uint32_t l = strlen(s);
1030ef270ab1SKenneth D. Merry 	char *d;
1031ef270ab1SKenneth D. Merry 
1032ef270ab1SKenneth D. Merry 	d = ocs_malloc(NULL, l+1, OCS_M_NOWAIT);
1033ef270ab1SKenneth D. Merry 	if (d != NULL) {
1034ef270ab1SKenneth D. Merry 		ocs_strcpy(d, s);
1035ef270ab1SKenneth D. Merry 	}
1036ef270ab1SKenneth D. Merry 	return d;
1037ef270ab1SKenneth D. Merry }
1038ef270ab1SKenneth D. Merry 
1039ef270ab1SKenneth D. Merry void
1040ef270ab1SKenneth D. Merry _ocs_assert(const char *cond, const char *filename, int linenum)
1041ef270ab1SKenneth D. Merry {
1042ef270ab1SKenneth D. Merry 	const char *fn = strrchr(__FILE__, '/');
1043ef270ab1SKenneth D. Merry 
1044ef270ab1SKenneth D. Merry 	ocs_log_err(NULL, "%s(%d) assertion (%s) failed\n", (fn ? fn + 1 : filename), linenum, cond);
1045ef270ab1SKenneth D. Merry 	ocs_print_stack();
1046ef270ab1SKenneth D. Merry 	ocs_save_ddump_all(OCS_DDUMP_FLAGS_WQES|OCS_DDUMP_FLAGS_CQES|OCS_DDUMP_FLAGS_MQES, -1, TRUE);
1047ef270ab1SKenneth D. Merry }
1048