Skip to content

Commit b1a0e87

Browse files
committed
Redesign message handling - Prevent handling in ISR
1 parent 4236cd5 commit b1a0e87

File tree

6 files changed

+133
-49
lines changed

6 files changed

+133
-49
lines changed

cores/arduino/VirtIOSerial.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#if defined (VIRTIOCON)
2525

2626
#include "VirtIOSerial.h"
27+
#include "core_debug.h"
28+
2729
#if !defined(VIRTIOSERIAL_NUM)
2830
#define VIRTIOSERIAL_NUM 1
2931
#endif
@@ -62,6 +64,9 @@ void VirtIOSerial::begin(void)
6264
VirtIOSerial_Handle[VirtIOSerial_index] = &_VirtIOSerialObj;
6365
_VirtIOSerialObj.initialized = true;
6466
_VirtIOSerialObj.first_message_discarded = false;
67+
68+
// This will wait for the first message "DUMMY", see rxCallback().
69+
OPENAMP_Wait_EndPointready(&_VirtIOSerialObj.handle.ept);
6570
}
6671

6772
void VirtIOSerial::begin(uint32_t /* baud_count */)
@@ -85,18 +90,21 @@ void VirtIOSerial::end()
8590

8691
int VirtIOSerial::available(void)
8792
{
93+
checkMessageFromISR();
8894
return virtio_buffer_read_available(&_VirtIOSerialObj.ring);
8995
}
9096

9197
int VirtIOSerial::availableForWrite()
9298
{
99+
checkMessageFromISR();
93100
// Just return max length of VIRT_UART_Transmit() can transmit.
94101
// See VIRT_UART_Transmit().
95-
return RPMSG_BUFFER_SIZE - RPMSG_VRING_HEADER_SIZE;
102+
return RPMSG_VRING_PAYLOAD_SIZE;
96103
}
97104

98105
int VirtIOSerial::peek(void)
99106
{
107+
checkMessageFromISR();
100108
if (virtio_buffer_read_available(&_VirtIOSerialObj.ring) > 0) {
101109
uint8_t tmp;
102110
virtio_buffer_peek(&_VirtIOSerialObj.ring, &tmp, 1);
@@ -119,14 +127,11 @@ int VirtIOSerial::read(void)
119127

120128
size_t VirtIOSerial::readBytes(char *buffer, size_t length)
121129
{
130+
checkMessageFromISR();
122131
uint16_t prev_write_available = virtio_buffer_write_available(&_VirtIOSerialObj.ring);
123132
const size_t size = virtio_buffer_read(&_VirtIOSerialObj.ring, reinterpret_cast<uint8_t *>(buffer), length);
124-
125-
if (prev_write_available < RPMSG_VRING_TOTAL_PAYLOAD_SIZE
126-
&& virtio_buffer_write_available(&_VirtIOSerialObj.ring) >= RPMSG_VRING_TOTAL_PAYLOAD_SIZE) {
127-
MAILBOX_Notify_Rx_Buf_Free();
128-
}
129-
133+
// The ring buffer might be available enough to write after reading
134+
checkMessageFromISR();
130135
return size;
131136
}
132137

@@ -137,23 +142,43 @@ size_t VirtIOSerial::write(uint8_t ch)
137142
}
138143

139144
// Warning: Currently VirtIOSerial implementation is synchronous, blocking
140-
// until all bytes are sent.
145+
// until all bytes are sent. But it will be fast enough.
141146
size_t VirtIOSerial::write(const uint8_t *buffer, size_t size)
142147
{
143-
if (VIRT_UART_Transmit(&_VirtIOSerialObj.handle, const_cast<uint8_t *>(buffer), size) == VIRT_UART_ERROR) {
144-
// This error usually happens when rpmsg is not ready for
148+
checkMessageFromISR();
149+
if (VIRT_UART_Transmit(&_VirtIOSerialObj.handle, const_cast<uint8_t *>(buffer), size) != VIRT_UART_OK) {
150+
// This error usually happens when size > 496. See VirtIOSerial::availableForWrite()
151+
core_debug("ERROR: VirtIOSerial::write() failed. Check availableForWrite().\n");
145152
return 0;
146153
}
154+
// It is likely receive "buf free" from the Linux host right after
155+
// VIRT_UART_Transmit(). So check it here too.
156+
checkMessageFromISR();
147157
return size;
148158
}
149159

150160
void VirtIOSerial::flush(void)
151161
{
162+
checkMessageFromISR();
152163
// write() is blocked until all bytes are sent. So flush() doesn't need to do
153164
// anything. See rpmsg_send().
154165
return;
155166
}
156167

168+
/**
169+
* @brief Check if RPMsg message arrived from IPCC ISR
170+
* @note This should called as mush as possible to consume RPMsg ring buffers,
171+
* so that the host processor can send more messages quickly.
172+
*/
173+
void VirtIOSerial::checkMessageFromISR(void)
174+
{
175+
OPENAMP_check_for_tx_message();
176+
if (virtio_buffer_write_available(&_VirtIOSerialObj.ring) >= RPMSG_VRING_TOTAL_PAYLOAD_SIZE) {
177+
// This calls rxCallback() VRING_NUM_BUFFS times at maximum
178+
OPENAMP_check_for_rx_message();
179+
}
180+
}
181+
157182
void VirtIOSerial::rxGenericCallback(VIRT_UART_HandleTypeDef *huart)
158183
{
159184
VirtIOSerialObj_t *obj = get_VirtIOSerial_obj(huart);
@@ -180,9 +205,6 @@ void VirtIOSerial::rxCallback(VIRT_UART_HandleTypeDef *huart)
180205
while (size > 0) {
181206
size -= virtio_buffer_write(&_VirtIOSerialObj.ring, huart->pRxBuffPtr, size);
182207
}
183-
if (virtio_buffer_write_available(&_VirtIOSerialObj.ring) >= RPMSG_VRING_TOTAL_PAYLOAD_SIZE) {
184-
MAILBOX_Notify_Rx_Buf_Free();
185-
}
186208
}
187209

188210
/* Aim of the function is to get _VirtIOSerialObj pointer using huart pointer */

cores/arduino/VirtIOSerial.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class VirtIOSerial : public Stream {
7373
private:
7474
static uint32_t VirtIOSerial_index;
7575
VirtIOSerialObj_t _VirtIOSerialObj;
76+
void checkMessageFromISR(void);
7677
};
7778

7879
extern VirtIOSerial SerialVirtIO;

cores/arduino/stm32/OpenAMP/mbox_ipcc.c

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,24 @@
3636
#include "openamp/open_amp.h"
3737
#include "stm32_def.h"
3838
#include "openamp_conf.h"
39+
#include "core_debug.h"
3940

4041
/* Private define ------------------------------------------------------------*/
4142
#define MASTER_CPU_ID 0
4243
#define REMOTE_CPU_ID 1
4344
#define IPCC_CPU_A7 MASTER_CPU_ID
4445
#define IPCC_CPU_M4 REMOTE_CPU_ID
4546

46-
#define RX_NO_MSG 0
47-
#define RX_NEW_MSG 1
48-
#define RX_BUF_FREE 2
47+
typedef enum {
48+
RX_NO_MSG = 0,
49+
RX_NEW_MSG = 1,
50+
RX_BUF_FREE = 2
51+
} rx_status_t;
4952

5053
/* Private variables ---------------------------------------------------------*/
5154
IPCC_HandleTypeDef hipcc;
52-
extern struct rpmsg_virtio_device rvdev;
53-
54-
55-
55+
rx_status_t msg_received_ch1 = RX_NO_MSG;
56+
rx_status_t msg_received_ch2 = RX_NO_MSG;
5657

5758
/* Private function prototypes -----------------------------------------------*/
5859
void IPCC_channel1_callback(IPCC_HandleTypeDef *hipcc, uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir);
@@ -68,6 +69,7 @@ int MAILBOX_Init(void)
6869
__HAL_RCC_IPCC_CLK_ENABLE();
6970
HAL_NVIC_SetPriority(IPCC_RX1_IRQn, IPCC_IRQ_PRIO, IPCC_IRQ_SUBPRIO);
7071
HAL_NVIC_EnableIRQ(IPCC_RX1_IRQn);
72+
7173
hipcc.Instance = IPCC;
7274
if (HAL_IPCC_Init(&hipcc) != HAL_OK) {
7375
Error_Handler();
@@ -89,19 +91,61 @@ int MAILBOX_Init(void)
8991
}
9092

9193
/**
92-
* @brief Callback function called by OpenAMP MW to notify message processing
93-
* @param VRING id
94+
* @brief Process vring messages received from IPCC ISR
95+
* @param vdev: virtio device
96+
* @param vring_id: Vring ID
97+
* @retval : Operation result
98+
*/
99+
int MAILBOX_Poll(struct virtio_device *vdev, uint32_t vring_id)
100+
{
101+
int ret = -1;
102+
103+
switch (vring_id) {
104+
case VRING0_ID:
105+
if (msg_received_ch1 == RX_BUF_FREE) {
106+
/* This calls rpmsg_virtio_tx_callback(), which actually does nothing. */
107+
rproc_virtio_notified(vdev, VRING0_ID);
108+
msg_received_ch1 = RX_NO_MSG;
109+
ret = 0;
110+
}
111+
break;
112+
case VRING1_ID:
113+
if (msg_received_ch2 == RX_NEW_MSG) {
114+
/**
115+
* This calls rpmsg_virtio_rx_callback(), which calls virt_uart rx callback
116+
* RING_NUM_BUFFS times at maximum.
117+
*/
118+
rproc_virtio_notified(vdev, VRING1_ID);
119+
msg_received_ch2 = RX_NO_MSG;
120+
121+
/* The OpenAMP framework does not notify for free buf: do it here */
122+
rproc_virtio_notified(NULL, VRING1_ID);
123+
ret = 0;
124+
}
125+
break;
126+
default:
127+
break;
128+
}
129+
130+
return ret;
131+
}
132+
133+
/**
134+
* @brief Callback function called by OpenAMP MW to notify message processing (aka. kick)
135+
* @note This callback is called by virtqueue_kick() in rpmsg_virtio_send_offchannel_raw().
136+
* Therefore, it is only called while tx, but not rx.
137+
* @param Vring id
94138
* @retval Operation result
95139
*/
96-
int MAILBOX_Notify(void *priv, uint32_t id)
140+
int MAILBOX_Notify(void *priv, uint32_t vring_id)
97141
{
98142
uint32_t channel;
99143
(void)priv;
100144

101145
/* Called after virtqueue processing: time to inform the remote */
102-
if (id == VRING0_ID) {
146+
if (vring_id == VRING0_ID) {
103147
channel = IPCC_CHANNEL_1;
104-
} else if (id == VRING1_ID) {
148+
} else if (vring_id == VRING1_ID) {
105149
/* Note: the OpenAMP framework never notifies this */
106150
channel = IPCC_CHANNEL_2;
107151
return -1;
@@ -121,37 +165,25 @@ int MAILBOX_Notify(void *priv, uint32_t id)
121165
return 0;
122166
}
123167

124-
/**
125-
* @brief Notify Rx buffer is free to Master
126-
*/
127-
void MAILBOX_Notify_Rx_Buf_Free()
128-
{
129-
HAL_IPCC_NotifyCPU(&hipcc, IPCC_CHANNEL_2, IPCC_CHANNEL_DIR_RX);
130-
}
131-
132168
/* Private function ---------------------------------------------------------*/
133169
/* Callback from IPCC Interrupt Handler: Master Processor informs that there are some free buffers */
134170
void IPCC_channel1_callback(IPCC_HandleTypeDef *hipcc,
135171
uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir)
136172
{
173+
msg_received_ch1 = RX_BUF_FREE;
174+
137175
/* Inform A7 that we have received the 'buff free' msg */
138176
HAL_IPCC_NotifyCPU(hipcc, ChannelIndex, IPCC_CHANNEL_DIR_RX);
139-
rproc_virtio_notified(rvdev.vdev, VRING0_ID);
140177
}
141178

142179
/* Callback from IPCC Interrupt Handler: new message received from Master Processor */
143180
void IPCC_channel2_callback(IPCC_HandleTypeDef *hipcc,
144181
uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir)
145182
{
146-
(void) hipcc;
147-
(void) ChannelIndex;
148-
(void) ChannelDir;
149-
/* Don't inform A7 here, do it when the buffer has more than RPMSG_BUFFER_SIZE.
150-
* See MAILBOX_Notify_Rx_Buf_Free() and VirIOSerial.cpp.
151-
*/
152-
rproc_virtio_notified(rvdev.vdev, VRING1_ID);
153-
/* The OpenAMP framework does not notify for free buf: do it here */
154-
rproc_virtio_notified(NULL, VRING1_ID);
183+
msg_received_ch2 = RX_NEW_MSG;
184+
185+
/* Don't inform A7 here */
186+
HAL_IPCC_NotifyCPU(hipcc, ChannelIndex, IPCC_CHANNEL_DIR_RX);
155187
}
156188

157189
/**

cores/arduino/stm32/OpenAMP/mbox_ipcc.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,9 @@
3030
#define IPCC_IRQ_SUBPRIO 0
3131
#endif
3232

33-
/* Includes ------------------------------------------------------------------*/
34-
/* Exported types ------------------------------------------------------------*/
35-
/* Exported constants --------------------------------------------------------*/
36-
/* Exported functions ------------------------------------------------------- */
3733
int MAILBOX_Init(void);
34+
int MAILBOX_Poll(struct virtio_device *vdev, uint32_t vring_id);
3835
int MAILBOX_Notify(void *priv, uint32_t id);
39-
void MAILBOX_Notify_Rx_Buf_Free(void);
4036

4137
#endif /* VIRTIOCON */
4238
#endif /* MBOX_IPCC_H_ */

cores/arduino/stm32/OpenAMP/openamp.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,39 @@ int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name,
161161
unbind_cb);
162162
}
163163

164+
/**
165+
* @brief Check and process any received messages from tx channel
166+
* @note Don't call this in an ISR.
167+
*/
168+
void OPENAMP_check_for_tx_message(void)
169+
{
170+
MAILBOX_Poll(rvdev.vdev, VRING0_ID);
171+
}
172+
173+
/**
174+
* @brief Check and process any received messages from rx channel
175+
* @note Don't call this in an ISR.
176+
*/
177+
void OPENAMP_check_for_rx_message(void)
178+
{
179+
MAILBOX_Poll(rvdev.vdev, VRING1_ID);
180+
}
181+
182+
/**
183+
* @brief Wait loop on rpmsg endpoint (VirtIOSerial) ready to send a message.
184+
* (until message dest address is known)
185+
* @note This will wait until the first message arrives from the Linux host.
186+
* If we send a rpmsg message before this it will fail.
187+
* @note Don't call this in an ISR.
188+
* @see VirtIOSerial::rxCallback
189+
* @param rp_ept: virtio rpmsg endpoint
190+
*/
164191
void OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept)
165192
{
166-
while (!is_rpmsg_ept_ready(rp_ept));
193+
while (!is_rpmsg_ept_ready(rp_ept)) {
194+
MAILBOX_Poll(rvdev.vdev, VRING0_ID);
195+
MAILBOX_Poll(rvdev.vdev, VRING1_ID);
196+
}
167197
}
168198

169199
#endif /* VIRTIOCON */

cores/arduino/stm32/OpenAMP/openamp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name,
4848
uint32_t dest, rpmsg_ept_cb cb,
4949
rpmsg_ns_unbind_cb unbind_cb);
5050

51+
/* Check for new rpmsg reception */
52+
void OPENAMP_check_for_message(void);
53+
5154
/* Wait loop on endpoint ready ( message dest address is know)*/
5255
void OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept);
5356

0 commit comments

Comments
 (0)