1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <stdint.h>
21 #include <string.h>
22 #include <DA1469xAB.h>
23 #include <shm.h>
24 #include <mbox.h>
25 
26 #define min(a, b) (((a) < (b)) ? (a) : (b))
27 
28 static struct cmac_shm_mbox *
mbox_src_get(uint16_t * size)29 mbox_src_get(uint16_t *size)
30 {
31     *size = g_cmac_shm.config->mbox_c2s_size;
32 
33     return g_cmac_shm.mbox_c2s;
34 }
35 
36 static struct cmac_shm_mbox *
mbox_dst_get(uint16_t * size)37 mbox_dst_get(uint16_t *size)
38 {
39     *size = g_cmac_shm.config->mbox_s2c_size;
40 
41     return g_cmac_shm.mbox_s2c;
42 }
43 
44 int
cmac_mbox_has_data(void)45 cmac_mbox_has_data(void)
46 {
47     volatile struct cmac_shm_mbox *mbox;
48     uint16_t mbox_size;
49 
50     mbox = mbox_src_get(&mbox_size);
51 
52     return mbox->rd_off != mbox->wr_off;
53 }
54 
55 int
cmac_mbox_read(void * data,uint16_t len)56 cmac_mbox_read(void *data, uint16_t len)
57 {
58 	volatile struct cmac_shm_mbox *mbox;
59 	uint16_t mbox_size;
60 	uint8_t *mbox_buf;
61 	uint16_t rd_off;
62 	uint16_t wr_off;
63 	uint16_t chunk_len;
64 	uint16_t rem_len;
65 
66 	mbox = mbox_src_get(&mbox_size);
67 	/* no need for volatile on data buffer */
68 	mbox_buf = (void *)mbox->data;
69 
70 	rem_len = len;
71 
72 	do {
73 		rd_off = mbox->rd_off;
74 		wr_off = mbox->wr_off;
75 
76 		if (rd_off <= wr_off) {
77 			chunk_len = wr_off - rd_off;
78 		} else {
79 			chunk_len = mbox_size - rd_off;
80 		}
81 
82 		chunk_len = min(chunk_len, rem_len);
83 
84 		memcpy(data, &mbox_buf[rd_off], chunk_len);
85 
86 		data = (uint8_t *)data + chunk_len;
87 		rem_len -= chunk_len;
88 		rd_off += chunk_len;
89 
90 		mbox->rd_off = rd_off == mbox_size ? 0 : rd_off;
91 	} while ((mbox->rd_off != mbox->wr_off) && (rem_len > 0));
92 
93 	return len - rem_len;
94 }
95 
96 int
cmac_mbox_write(const void * data,uint16_t len)97 cmac_mbox_write(const void *data, uint16_t len)
98 {
99     volatile struct cmac_shm_mbox *mbox;
100     uint16_t mbox_size;
101     uint8_t *mbox_buf;
102     uint16_t rd_off;
103     uint16_t wr_off;
104     uint16_t max_wr;
105     uint16_t chunk;
106 
107     mbox = mbox_dst_get(&mbox_size);
108     /* no need for volatile on data buffer */
109     mbox_buf = (void *)mbox->data;
110 
111     while (len) {
112         rd_off = mbox->rd_off;
113         wr_off = mbox->wr_off;
114 
115         /*
116          * Calculate maximum length to write, i.e. up to end of buffer or stop
117          * before rd_off to be able to detect full queue.
118          */
119         if (rd_off > wr_off) {
120             /*
121              * |0|1|2|3|4|5|6|7|
122              * | | | |W| | |R| |
123              *        `---^
124              */
125             max_wr = rd_off - wr_off - 1;
126         } else if (rd_off == 0) {
127             /*
128              * |0|1|2|3|4|5|6|7|
129              * |R| | |W| | | | |
130              *        `-------^
131              */
132             max_wr = mbox_size - wr_off - 1;
133         } else {
134             /*
135              * |0|1|2|3|4|5|6|7|
136              * | |R| |W| | | | |
137              *        `---------^
138              */
139             max_wr = mbox_size - wr_off;
140         }
141 
142         chunk = min(len, max_wr);
143 
144         if (chunk == 0) {
145             continue;
146         }
147 
148         memcpy(&mbox_buf[wr_off], data, chunk);
149 
150         wr_off += chunk;
151         mbox->wr_off = wr_off == mbox_size ? 0 : wr_off;
152 
153 	    cmac_signal();
154 
155         len -= chunk;
156         data = (uint8_t *)data + chunk;
157     }
158 
159     return 0;
160 }
161