1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @brief File containing work specific definitions for the
9  * Zephyr OS layer of the Wi-Fi driver.
10  */
11 
12 #include <zephyr/kernel.h>
13 #include <zephyr/init.h>
14 #include <zephyr/sys/printk.h>
15 #include <zephyr/logging/log.h>
16 
17 #include "work.h"
18 
19 LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
20 
21 K_THREAD_STACK_DEFINE(bh_wq_stack_area, CONFIG_NRF70_BH_WQ_STACK_SIZE);
22 struct k_work_q zep_wifi_bh_q;
23 
24 K_THREAD_STACK_DEFINE(irq_wq_stack_area, CONFIG_NRF70_IRQ_WQ_STACK_SIZE);
25 struct k_work_q zep_wifi_intr_q;
26 
27 #ifdef CONFIG_NRF70_TX_DONE_WQ_ENABLED
28 K_THREAD_STACK_DEFINE(tx_done_wq_stack_area, CONFIG_NRF70_TX_DONE_WQ_STACK_SIZE);
29 struct k_work_q zep_wifi_tx_done_q;
30 #endif /* CONFIG_NRF70_TX_DONE_WQ_ENABLED */
31 
32 #ifdef CONFIG_NRF70_RX_WQ_ENABLED
33 K_THREAD_STACK_DEFINE(rx_wq_stack_area, CONFIG_NRF70_RX_WQ_STACK_SIZE);
34 struct k_work_q zep_wifi_rx_q;
35 #endif /* CONFIG_NRF70_RX_WQ_ENABLED */
36 
37 struct zep_work_item zep_work_item[CONFIG_NRF70_WORKQ_MAX_ITEMS];
38 
get_free_work_item_index(void)39 int get_free_work_item_index(void)
40 {
41 	int i;
42 
43 	for (i = 0; i < CONFIG_NRF70_WORKQ_MAX_ITEMS; i++) {
44 		if (zep_work_item[i].in_use) {
45 			continue;
46 		}
47 		return i;
48 	}
49 
50 	return -1;
51 }
52 
workqueue_callback(struct k_work * work)53 void workqueue_callback(struct k_work *work)
54 {
55 	struct zep_work_item *item = CONTAINER_OF(work, struct zep_work_item, work);
56 
57 	item->callback(item->data);
58 }
59 
work_alloc(enum zep_work_type type)60 struct zep_work_item *work_alloc(enum zep_work_type type)
61 {
62 	int free_work_index = get_free_work_item_index();
63 
64 	if (free_work_index < 0) {
65 		LOG_ERR("%s: Reached maximum work items", __func__);
66 		return NULL;
67 	}
68 
69 	zep_work_item[free_work_index].in_use = true;
70 	zep_work_item[free_work_index].type = type;
71 
72 	return &zep_work_item[free_work_index];
73 }
74 
workqueue_init(void)75 static int workqueue_init(void)
76 {
77 	k_work_queue_init(&zep_wifi_bh_q);
78 
79 	k_work_queue_start(&zep_wifi_bh_q,
80 			   bh_wq_stack_area,
81 			   K_THREAD_STACK_SIZEOF(bh_wq_stack_area),
82 			   CONFIG_NRF70_BH_WQ_PRIORITY,
83 			   NULL);
84 
85 	k_thread_name_set(&zep_wifi_bh_q.thread, "nrf70_bh_wq");
86 
87 	k_work_queue_init(&zep_wifi_intr_q);
88 
89 	k_work_queue_start(&zep_wifi_intr_q,
90 			   irq_wq_stack_area,
91 			   K_THREAD_STACK_SIZEOF(irq_wq_stack_area),
92 			   CONFIG_NRF70_IRQ_WQ_PRIORITY,
93 			   NULL);
94 
95 	k_thread_name_set(&zep_wifi_intr_q.thread, "nrf70_intr_wq");
96 #ifdef CONFIG_NRF70_TX_DONE_WQ_ENABLED
97 	k_work_queue_init(&zep_wifi_tx_done_q);
98 
99 	k_work_queue_start(&zep_wifi_tx_done_q,
100 			   tx_done_wq_stack_area,
101 			   K_THREAD_STACK_SIZEOF(tx_done_wq_stack_area),
102 			   CONFIG_NRF70_TX_DONE_WQ_PRIORITY,
103 			   NULL);
104 
105 	k_thread_name_set(&zep_wifi_tx_done_q.thread, "nrf70_tx_done_wq");
106 #endif /* CONFIG_NRF70_TX_DONE_WQ_ENABLED */
107 
108 #ifdef CONFIG_NRF70_RX_WQ_ENABLED
109 	k_work_queue_init(&zep_wifi_rx_q);
110 
111 	k_work_queue_start(&zep_wifi_rx_q,
112 			   rx_wq_stack_area,
113 			   K_THREAD_STACK_SIZEOF(rx_wq_stack_area),
114 			   CONFIG_NRF70_RX_WQ_PRIORITY,
115 			   NULL);
116 
117 	k_thread_name_set(&zep_wifi_rx_q.thread, "nrf70_rx_wq");
118 #endif /* CONFIG_NRF70_RX_WQ_ENABLED */
119 
120 	return 0;
121 }
122 
work_init(struct zep_work_item * item,void (* callback)(unsigned long),unsigned long data)123 void work_init(struct zep_work_item *item, void (*callback)(unsigned long),
124 		  unsigned long data)
125 {
126 	item->callback = callback;
127 	item->data = data;
128 
129 	k_work_init(&item->work, workqueue_callback);
130 }
131 
work_schedule(struct zep_work_item * item)132 void work_schedule(struct zep_work_item *item)
133 {
134 	if (item->type == ZEP_WORK_TYPE_IRQ) {
135 		k_work_submit_to_queue(&zep_wifi_intr_q, &item->work);
136 	} else if (item->type == ZEP_WORK_TYPE_BH) {
137 		k_work_submit_to_queue(&zep_wifi_bh_q, &item->work);
138 	}
139 #ifdef CONFIG_NRF70_TX_DONE_WQ_ENABLED
140 	else if (item->type == ZEP_WORK_TYPE_TX_DONE) {
141 		k_work_submit_to_queue(&zep_wifi_tx_done_q, &item->work);
142 	}
143 #endif /* CONFIG_NRF70_TX_DONE_WQ_ENABLED */
144 #ifdef CONFIG_NRF70_RX_WQ_ENABLED
145 	else if (item->type == ZEP_WORK_TYPE_RX) {
146 		k_work_submit_to_queue(&zep_wifi_rx_q, &item->work);
147 	}
148 #endif /* CONFIG_NRF70_RX_WQ_ENABLED */
149 }
150 
work_kill(struct zep_work_item * item)151 void work_kill(struct zep_work_item *item)
152 {
153 	/* TODO: Based on context, use _sync version */
154 	k_work_cancel(&item->work);
155 }
156 
work_free(struct zep_work_item * item)157 void work_free(struct zep_work_item *item)
158 {
159 	item->in_use = 0;
160 }
161 
162 SYS_INIT(workqueue_init, POST_KERNEL, 0);
163