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