1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ipc/ipc_service.h>
9 #include <zephyr/logging/log_link.h>
10 #include <zephyr/logging/log_multidomain_helper.h>
11 #include <zephyr/logging/log_core.h>
12 #include <zephyr/logging/log.h>
13 
14 LOG_MODULE_DECLARE(link_ipc);
15 
log_multidomain_link_on_error(struct log_multidomain_link * link_remote,int err)16 void log_multidomain_link_on_error(struct log_multidomain_link *link_remote, int err)
17 {
18 	link_remote->status = err;
19 }
20 
log_multidomain_link_on_started(struct log_multidomain_link * link_remote,int err)21 void log_multidomain_link_on_started(struct log_multidomain_link *link_remote, int err)
22 {
23 	link_remote->status = err;
24 
25 	if (err == 0) {
26 		link_remote->ready = true;
27 	}
28 }
29 
log_multidomain_link_on_recv_cb(struct log_multidomain_link * link_remote,const void * data,size_t len)30 void log_multidomain_link_on_recv_cb(struct log_multidomain_link *link_remote,
31 				const void *data, size_t len)
32 {
33 	struct log_multidomain_msg *msg = (struct log_multidomain_msg *)data;
34 
35 	if (msg->status != Z_LOG_MULTIDOMAIN_STATUS_OK) {
36 		link_remote->status = -EIO;
37 		goto exit;
38 	} else {
39 		link_remote->status = 0;
40 	}
41 
42 	switch (msg->id) {
43 	case Z_LOG_MULTIDOMAIN_ID_MSG:
44 		z_log_msg_enqueue(link_remote->link,
45 				  msg->data.log_msg.data,
46 				  len - offsetof(struct log_multidomain_msg, data));
47 		return;
48 	case Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_CNT:
49 		link_remote->dst.count = msg->data.domain_cnt.count;
50 		break;
51 	case Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_CNT:
52 		link_remote->dst.count = msg->data.source_cnt.count;
53 		break;
54 	case Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_NAME:
55 	{
56 		size_t slen = MIN(len - 1, *link_remote->dst.name.len - 1);
57 
58 		*link_remote->dst.name.len = len - 1;
59 		memcpy(link_remote->dst.name.dst, msg->data.domain_name.name, slen);
60 		link_remote->dst.name.dst[slen] = '\0';
61 		break;
62 	}
63 	case Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_NAME:
64 	{
65 		size_t slen = MIN(len - 1, *link_remote->dst.name.len - 1);
66 
67 		*link_remote->dst.name.len = len - 1;
68 		memcpy(link_remote->dst.name.dst, msg->data.source_name.name, slen);
69 		link_remote->dst.name.dst[slen] = '\0';
70 		break;
71 	}
72 	case Z_LOG_MULTIDOMAIN_ID_GET_LEVELS:
73 		link_remote->dst.levels.level = msg->data.levels.level;
74 		link_remote->dst.levels.runtime_level = msg->data.levels.runtime_level;
75 		break;
76 	case Z_LOG_MULTIDOMAIN_ID_SET_RUNTIME_LEVEL:
77 		link_remote->dst.set_runtime_level.level = msg->data.set_rt_level.runtime_level;
78 		break;
79 	case Z_LOG_MULTIDOMAIN_ID_DROPPED:
80 		return;
81 	case Z_LOG_MULTIDOMAIN_ID_READY:
82 		break;
83 	default:
84 		__ASSERT(0, "Unexpected message");
85 		return;
86 	}
87 
88 exit:
89 	k_sem_give(&link_remote->rdy_sem);
90 }
91 
getter_msg_process(struct log_multidomain_link * link_remote,struct log_multidomain_msg * msg,size_t msg_size)92 static int getter_msg_process(struct log_multidomain_link *link_remote,
93 			      struct log_multidomain_msg *msg, size_t msg_size)
94 {
95 	int err;
96 
97 	err = link_remote->transport_api->send(link_remote, msg, msg_size);
98 	if (err < 0) {
99 		return err;
100 	}
101 
102 	err = k_sem_take(&link_remote->rdy_sem, K_MSEC(1000));
103 	if (err < 0) {
104 		return err;
105 	}
106 
107 	return (link_remote->status == Z_LOG_MULTIDOMAIN_STATUS_OK) ? 0 : -EIO;
108 }
109 
link_remote_get_domain_count(struct log_multidomain_link * link_remote,uint16_t * cnt)110 static int link_remote_get_domain_count(struct log_multidomain_link *link_remote,
111 					uint16_t *cnt)
112 {
113 	int err;
114 	struct log_multidomain_msg msg = {
115 		.id = Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_CNT,
116 	};
117 
118 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
119 	if (err < 0) {
120 		return err;
121 	}
122 
123 	*cnt = link_remote->dst.count;
124 
125 	return 0;
126 }
127 
link_remote_get_source_count(struct log_multidomain_link * link_remote,uint32_t domain_id,uint16_t * cnt)128 static int link_remote_get_source_count(struct log_multidomain_link *link_remote,
129 					      uint32_t domain_id,
130 					      uint16_t *cnt)
131 {
132 	int err;
133 	struct log_multidomain_msg msg = {
134 		.id = Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_CNT,
135 		.data = { .source_cnt = { .domain_id = domain_id } }
136 	};
137 
138 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
139 	if (err < 0) {
140 		return err;
141 	}
142 
143 	*cnt = link_remote->dst.count;
144 
145 	return 0;
146 }
147 
link_remote_ready(struct log_multidomain_link * link_remote)148 static int link_remote_ready(struct log_multidomain_link *link_remote)
149 {
150 	int err;
151 	struct log_multidomain_msg msg = {
152 		.id = Z_LOG_MULTIDOMAIN_ID_READY
153 	};
154 
155 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
156 	if (err < 0) {
157 		return err;
158 	}
159 
160 	return 0;
161 }
162 
link_remote_initiate(const struct log_link * link,struct log_link_config * config)163 static int link_remote_initiate(const struct log_link *link,
164 				struct log_link_config *config)
165 {
166 	struct log_multidomain_link *link_remote = link->ctx;
167 
168 	link_remote->link = link;
169 	k_sem_init(&link_remote->rdy_sem, 0, 1);
170 
171 	return link_remote->transport_api->init(link_remote);
172 }
173 
link_remote_activate(const struct log_link * link)174 static int link_remote_activate(const struct log_link *link)
175 {
176 	struct log_multidomain_link *link_remote = link->ctx;
177 	int err;
178 
179 	if (!link_remote->ready) {
180 		return -EINPROGRESS;
181 	}
182 
183 	if (link_remote->status != 0) {
184 		return link_remote->status;
185 	}
186 
187 	uint16_t cnt;
188 
189 	err = link_remote_get_domain_count(link_remote, &cnt);
190 	if (err < 0) {
191 		return err;
192 	}
193 
194 	if (cnt > ARRAY_SIZE(link->ctrl_blk->source_cnt)) {
195 		__ASSERT(0, "Number of domains not supported.");
196 		return -ENOMEM;
197 	}
198 
199 	link->ctrl_blk->domain_cnt = cnt;
200 	for (int i = 0; i < link->ctrl_blk->domain_cnt; i++) {
201 		err = link_remote_get_source_count(link_remote, i, &cnt);
202 		if (err < 0) {
203 			return err;
204 		}
205 
206 		link->ctrl_blk->source_cnt[i] = cnt;
207 	}
208 
209 	err = link_remote_ready(link_remote);
210 
211 	return err;
212 }
213 
link_remote_get_domain_name(const struct log_link * link,uint32_t domain_id,char * name,uint32_t * length)214 static int link_remote_get_domain_name(const struct log_link *link,
215 					uint32_t domain_id,
216 					char *name, uint32_t *length)
217 {
218 	struct log_multidomain_link *link_remote = link->ctx;
219 	struct log_multidomain_msg msg = {
220 		.id = Z_LOG_MULTIDOMAIN_ID_GET_DOMAIN_NAME,
221 		.data = { .domain_name = { .domain_id = domain_id } }
222 	};
223 	int err;
224 
225 
226 	link_remote->dst.name.dst = name;
227 	link_remote->dst.name.len = length;
228 
229 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
230 	if (err < 0) {
231 		return err;
232 	}
233 
234 	return 0;
235 }
236 
link_remote_get_source_name(const struct log_link * link,uint32_t domain_id,uint16_t source_id,char * name,size_t * length)237 static int link_remote_get_source_name(const struct log_link *link,
238 					uint32_t domain_id, uint16_t source_id,
239 					char *name, size_t *length)
240 {
241 	struct log_multidomain_link *link_remote = link->ctx;
242 	struct log_multidomain_msg msg = {
243 		.id = Z_LOG_MULTIDOMAIN_ID_GET_SOURCE_NAME,
244 		.data = {
245 			.source_name = {
246 				.domain_id = domain_id,
247 				.source_id = source_id
248 			}
249 		}
250 	};
251 	int err;
252 
253 	link_remote->dst.name.dst = name;
254 	link_remote->dst.name.len = length;
255 
256 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
257 	if (err < 0) {
258 		return err;
259 	}
260 
261 	return 0;
262 }
263 
link_remote_get_levels(const struct log_link * link,uint32_t domain_id,uint16_t source_id,uint8_t * level,uint8_t * runtime_level)264 static int link_remote_get_levels(const struct log_link *link,
265 				   uint32_t domain_id, uint16_t source_id,
266 				   uint8_t *level, uint8_t *runtime_level)
267 {
268 	struct log_multidomain_link *link_remote = link->ctx;
269 	struct log_multidomain_msg msg = {
270 		.id = Z_LOG_MULTIDOMAIN_ID_GET_LEVELS,
271 		.data = {
272 			.levels = {
273 				.domain_id = domain_id,
274 				.source_id = source_id
275 			}
276 		}
277 	};
278 	int err;
279 
280 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
281 	if (err < 0) {
282 		return err;
283 	}
284 
285 	if (level) {
286 		*level = link_remote->dst.levels.level;
287 	}
288 	if (runtime_level) {
289 		*runtime_level = link_remote->dst.levels.runtime_level;
290 	}
291 
292 	return 0;
293 }
294 
link_remote_set_runtime_level(const struct log_link * link,uint32_t domain_id,uint16_t source_id,uint8_t level)295 static int link_remote_set_runtime_level(const struct log_link *link,
296 					 uint32_t domain_id, uint16_t source_id,
297 					 uint8_t level)
298 {
299 	struct log_multidomain_link *link_remote = link->ctx;
300 	struct log_multidomain_msg msg = {
301 		.id = Z_LOG_MULTIDOMAIN_ID_SET_RUNTIME_LEVEL,
302 		.data = {
303 			.set_rt_level = {
304 				.domain_id = domain_id,
305 				.source_id = source_id,
306 				.runtime_level = level
307 			}
308 		}
309 	};
310 	int err;
311 
312 	err = getter_msg_process(link_remote, &msg, sizeof(msg));
313 	if (err < 0) {
314 		return err;
315 	}
316 
317 	return 0;
318 }
319 
320 struct log_link_api log_multidomain_link_api = {
321 	.initiate = link_remote_initiate,
322 	.activate = link_remote_activate,
323 	.get_domain_name = link_remote_get_domain_name,
324 	.get_source_name = link_remote_get_source_name,
325 	.get_levels = link_remote_get_levels,
326 	.set_runtime_level = link_remote_set_runtime_level
327 };
328