Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2016-2020 Intel Corporation
3 : : */
4 : :
5 : : #ifndef __DLB2_OSDEP_H
6 : : #define __DLB2_OSDEP_H
7 : :
8 : : #include <string.h>
9 : : #include <time.h>
10 : : #include <unistd.h>
11 : :
12 : : #include <rte_string_fns.h>
13 : : #include <rte_cycles.h>
14 : : #include <rte_io.h>
15 : : #include <rte_log.h>
16 : : #include <rte_spinlock.h>
17 : : #include "../dlb2_main.h"
18 : :
19 : : #include "dlb2_resource.h"
20 : :
21 : : #include "../../dlb2_log.h"
22 : : #include "../../dlb2_user.h"
23 : :
24 : :
25 : : #define DLB2_PCI_REG_READ(addr) rte_read32((void *)addr)
26 : : #define DLB2_PCI_REG_WRITE(reg, value) rte_write32(value, (void *)reg)
27 : :
28 : : /* Read/write register 'reg' in the CSR BAR space */
29 : : #define DLB2_CSR_REG_ADDR(a, reg) ((void *)((uintptr_t)(a)->csr_kva + (reg)))
30 : : #define DLB2_CSR_RD(hw, reg) \
31 : : DLB2_PCI_REG_READ(DLB2_CSR_REG_ADDR((hw), (reg)))
32 : : #define DLB2_CSR_WR(hw, reg, value) \
33 : : DLB2_PCI_REG_WRITE(DLB2_CSR_REG_ADDR((hw), (reg)), (value))
34 : :
35 : : /* Read/write register 'reg' in the func BAR space */
36 : : #define DLB2_FUNC_REG_ADDR(a, reg) ((void *)((uintptr_t)(a)->func_kva + (reg)))
37 : : #define DLB2_FUNC_RD(hw, reg) \
38 : : DLB2_PCI_REG_READ(DLB2_FUNC_REG_ADDR((hw), (reg)))
39 : : #define DLB2_FUNC_WR(hw, reg, value) \
40 : : DLB2_PCI_REG_WRITE(DLB2_FUNC_REG_ADDR((hw), (reg)), (value))
41 : :
42 : : /* Map to PMDs logging interface */
43 : : #define DLB2_ERR(dev, fmt, args...) \
44 : : DLB2_LOG_ERR(fmt, ## args)
45 : :
46 : : #define DLB2_INFO(dev, fmt, args...) \
47 : : DLB2_LOG_INFO(fmt, ## args)
48 : :
49 : : #define DLB2_DEBUG(dev, fmt, args...) \
50 : : DLB2_LOG_DBG(fmt, ## args)
51 : :
52 : : /**
53 : : * os_udelay() - busy-wait for a number of microseconds
54 : : * @usecs: delay duration.
55 : : */
56 : : static inline void os_udelay(int usecs)
57 : : {
58 : : rte_delay_us(usecs);
59 : : }
60 : :
61 : : /**
62 : : * os_msleep() - sleep for a number of milliseconds
63 : : * @usecs: delay duration.
64 : : */
65 : : static inline void os_msleep(int msecs)
66 : : {
67 : : rte_delay_ms(msecs);
68 : : }
69 : :
70 : : #define DLB2_PP_BASE(__is_ldb) \
71 : : ((__is_ldb) ? DLB2_LDB_PP_BASE : DLB2_DIR_PP_BASE)
72 : :
73 : : /**
74 : : * os_map_producer_port() - map a producer port into the caller's address space
75 : : * @hw: dlb2_hw handle for a particular device.
76 : : * @port_id: port ID
77 : : * @is_ldb: true for load-balanced port, false for a directed port
78 : : *
79 : : * This function maps the requested producer port memory into the caller's
80 : : * address space.
81 : : *
82 : : * Return:
83 : : * Returns the base address at which the PP memory was mapped, else NULL.
84 : : */
85 : : static inline void *os_map_producer_port(struct dlb2_hw *hw,
86 : : u8 port_id,
87 : : bool is_ldb)
88 : : {
89 : : uint64_t addr;
90 : : uint64_t pp_dma_base;
91 : :
92 [ # # ]: 0 : pp_dma_base = (uintptr_t)hw->func_kva + DLB2_PP_BASE(is_ldb);
93 : 0 : addr = (pp_dma_base + (rte_mem_page_size() * port_id));
94 : :
95 : 0 : return (void *)(uintptr_t)addr;
96 : : }
97 : :
98 : : /**
99 : : * os_unmap_producer_port() - unmap a producer port
100 : : * @addr: mapped producer port address
101 : : *
102 : : * This function undoes os_map_producer_port() by unmapping the producer port
103 : : * memory from the caller's address space.
104 : : *
105 : : * Return:
106 : : * Returns the base address at which the PP memory was mapped, else NULL.
107 : : */
108 : : static inline void os_unmap_producer_port(struct dlb2_hw *hw, void *addr)
109 : : {
110 : : RTE_SET_USED(hw);
111 : : RTE_SET_USED(addr);
112 : : }
113 : :
114 : : /**
115 : : * os_fence_hcw() - fence an HCW to ensure it arrives at the device
116 : : * @hw: dlb2_hw handle for a particular device.
117 : : * @pp_addr: producer port address
118 : : */
119 : : static inline void os_fence_hcw(struct dlb2_hw *hw, u64 *pp_addr)
120 : : {
121 : : RTE_SET_USED(hw);
122 : :
123 : : /* To ensure outstanding HCWs reach the device, read the PP address. IA
124 : : * memory ordering prevents reads from passing older writes, and the
125 : : * mfence also ensures this.
126 : : */
127 : : rte_mb();
128 : :
129 : 0 : *(volatile u64 *)pp_addr;
130 : : }
131 : :
132 : : /**
133 : : * DLB2_HW_ERR() - log an error message
134 : : * @dlb2: dlb2_hw handle for a particular device.
135 : : * @...: variable string args.
136 : : */
137 : : #define DLB2_HW_ERR(dlb2, ...) do { \
138 : : RTE_SET_USED(dlb2); \
139 : : DLB2_ERR(dlb2, __VA_ARGS__); \
140 : : } while (0)
141 : :
142 : : /**
143 : : * DLB2_HW_DBG() - log an info message
144 : : * @dlb2: dlb2_hw handle for a particular device.
145 : : * @...: variable string args.
146 : : */
147 : : #define DLB2_HW_DBG(dlb2, ...) do { \
148 : : RTE_SET_USED(dlb2); \
149 : : DLB2_DEBUG(dlb2, __VA_ARGS__); \
150 : : } while (0)
151 : :
152 : : /* The callback runs until it completes all outstanding QID->CQ
153 : : * map and unmap requests. To prevent deadlock, this function gives other
154 : : * threads a chance to grab the resource mutex and configure hardware.
155 : : */
156 : 0 : static uint32_t dlb2_complete_queue_map_unmap(void *__args)
157 : : {
158 : : struct dlb2_dev *dlb2_dev = (struct dlb2_dev *)__args;
159 : : int ret;
160 : :
161 : : while (1) {
162 : 0 : rte_spinlock_lock(&dlb2_dev->resource_mutex);
163 : :
164 : 0 : ret = dlb2_finish_unmap_qid_procedures(&dlb2_dev->hw);
165 : 0 : ret += dlb2_finish_map_qid_procedures(&dlb2_dev->hw);
166 : :
167 [ # # ]: 0 : if (ret != 0) {
168 : : rte_spinlock_unlock(&dlb2_dev->resource_mutex);
169 : : /* Relinquish the CPU so the application can process
170 : : * its CQs, so this function doesn't deadlock.
171 : : */
172 : 0 : sched_yield();
173 : : } else {
174 : : break;
175 : : }
176 : : }
177 : :
178 : 0 : dlb2_dev->worker_launched = false;
179 : :
180 : : rte_spinlock_unlock(&dlb2_dev->resource_mutex);
181 : :
182 : 0 : return 0;
183 : : }
184 : :
185 : :
186 : : /**
187 : : * os_schedule_work() - launch a thread to process pending map and unmap work
188 : : * @hw: dlb2_hw handle for a particular device.
189 : : *
190 : : * This function launches a kernel thread that will run until all pending
191 : : * map and unmap procedures are complete.
192 : : */
193 : 0 : static inline void os_schedule_work(struct dlb2_hw *hw)
194 : : {
195 : : struct dlb2_dev *dlb2_dev;
196 : : rte_thread_t complete_queue_map_unmap_thread;
197 : : int ret;
198 : :
199 : 0 : dlb2_dev = container_of(hw, struct dlb2_dev, hw);
200 : :
201 : 0 : ret = rte_thread_create_internal_control(&complete_queue_map_unmap_thread,
202 : : "dlb-qunmap", dlb2_complete_queue_map_unmap, dlb2_dev);
203 [ # # ]: 0 : if (ret)
204 : 0 : DLB2_ERR(dlb2_dev,
205 : : "Could not create queue complete map/unmap thread, err=%d\n",
206 : : ret);
207 : : else
208 : 0 : dlb2_dev->worker_launched = true;
209 : 0 : }
210 : :
211 : : /**
212 : : * os_worker_active() - query whether the map/unmap worker thread is active
213 : : * @hw: dlb2_hw handle for a particular device.
214 : : *
215 : : * This function returns a boolean indicating whether a thread (launched by
216 : : * os_schedule_work()) is active. This function is used to determine
217 : : * whether or not to launch a worker thread.
218 : : */
219 : : static inline bool os_worker_active(struct dlb2_hw *hw)
220 : : {
221 : : struct dlb2_dev *dlb2_dev;
222 : :
223 : 0 : dlb2_dev = container_of(hw, struct dlb2_dev, hw);
224 : :
225 [ # # # # : 0 : return dlb2_dev->worker_launched;
# # ]
226 : : }
227 : :
228 : : #endif /* __DLB2_OSDEP_H */
|