-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathcirc_buf_demo.c
140 lines (112 loc) · 3.33 KB
/
circ_buf_demo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "circ_buf.h"
/* ref ipc-msg drivers/rpmsg/qcom_glink_smem.c */
#define dsb(opt) asm volatile("dsb " #opt : : : "memory")
#define wmb() dsb(st)
static void circ_rx_peak(struct circ_buf *circ,
void *data, unsigned int offset, size_t count)
{
size_t len;
u32 tail;
tail = le32_to_cpu(circ->tail);
tail += offset;
if (tail >= circ->size)
tail -= circ->size;
len = min(count, circ->size - tail);
if (len)
memcpy(data, circ->buf + tail, len);
if (len != count)
memcpy(data + len, circ->buf, (count - len));
}
static void circ_rx_advance(struct circ_buf *circ,
size_t count)
{
u32 tail;
tail = le32_to_cpu(circ->tail);
tail += count;
if (tail >= circ->size)
tail -= circ->size;
circ->tail= cpu_to_le32(tail);
}
static unsigned int msg_tx_write_one(struct circ_buf *circ,
unsigned int head,
const void *data, size_t count)
{
size_t len;
len = min(count, circ->size - head);
if (len)
memcpy(circ->buf + head, data, len);
if (len != count)
memcpy(circ->buf, data + len, count - len);
head += count;
if (head >= circ->size)
head -= circ->size;
return head;
}
static void msg_tx_write(struct circ_buf *circ,
const void *hdr, size_t hlen,
const void *data, size_t dlen)
{
unsigned int head;
head = le32_to_cpu(circ->head);
head = msg_tx_write_one(circ, head, hdr, hlen);
head = msg_tx_write_one(circ, head, data, dlen);
/* Ensure head is always aligned to 8 bytes */
head = ALIGN(head, 8);
if (head >= circ->size)
head -= circ->size;
/* Ensure ordering of fifo and head update */
wmb();
circ->head = cpu_to_le32(head);
}
static size_t msg_tx_avail(struct circ_buf *circ)
{
int head;
int tail;
uint32_t avail = 0;
head = le32_to_cpu(circ->head);
tail = le32_to_cpu(circ->tail);
avail = CIRC_SPACE(head, tail, circ->size);
return avail;
}
static int test_circ_buf()
{
unsigned long flags = 0;
struct circ_buf *circ = &test_circ;
struct hdr hdr = {0};
int avail;
for (;;) {
spin_lock_irqsave(&rlock, flags);
avail = CIRC_CNT(circ->head, circ->tail, circ->size);
if (avail < sizeof(hdr)){
spin_unlock_irqrestore(&rlock, flags);
break;
}
circ_rx_peak(circ, &hdr, 0, sizeof(hdr));
if (hdr.msg_len > circ->size || hdr.msg_len < 0){
printf("hdr.msg_len overflow\n");
}
if (avail < sizeof(hdr) + hdr.msg_len){
spin_unlock_irqrestore(&rlock, flags);
printf("invalid msg len\n");
break;
}
circ_rx_peak(circ, message, sizeof(hdr), hdr.msg_len);
circ_rx_advance(circ, ALIGN(sizeof(hdr) + hdr.msg_len , 8));
spin_unlock_irqrestore(&rlock, flags);
}
spin_lock_irqsave(&wlock, flags);
while (msg_tx_avail(circ) < hdr.msg_len + sizeof(hdr)) {
if (!false) {
lost_msg++;
LogMsg_ISR(LOG_ERR, "logmsg lost_count[%d] msg[%s]\n", lost_msg, message);
goto out;
}
}
msg_tx_write(circ, &hdr, sizeof(hdr), message, hdr.msg_len);
out:
//unlock
spin_unlock_irqrestore(&wlock, flags);
}