3
* Copyright 2007,2008 Free Software Foundation, Inc.
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
* Double Buffering State Machine
24
#include "memory_map.h"
25
#include "buffer_pool.h"
37
static buffer_state_t buffer_state[NBUFFERS];
40
dbsm_nop_inspector(dbsm_t *sm, int buf_this)
46
dbsm_init(dbsm_t *sm, int buf0,
47
const buf_cmd_args_t *recv, const buf_cmd_args_t *send,
50
if (buf0 & 0x1) // must be even
55
sm->recv_args = *recv;
56
sm->send_args = *send;
61
sm->inspect = inspect;
63
// How much to adjust the last_line register.
64
// It's 1 for everything but the ethernet.
65
sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1;
67
buffer_state[sm->buf0] = BS_EMPTY;
68
buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
70
sm->precomputed_receive_to_buf_ctrl_word[0] =
72
| BPC_BUFFER(sm->buf0)
73
| BPC_PORT(sm->recv_args.port)
75
| BPC_FIRST_LINE(sm->recv_args.first_line)
76
| BPC_LAST_LINE(sm->recv_args.last_line));
78
sm->precomputed_receive_to_buf_ctrl_word[1] =
80
| BPC_BUFFER(sm->buf0 ^ 1)
81
| BPC_PORT(sm->recv_args.port)
83
| BPC_FIRST_LINE(sm->recv_args.first_line)
84
| BPC_LAST_LINE(sm->recv_args.last_line));
86
sm->precomputed_send_from_buf_ctrl_word[0] =
88
| BPC_BUFFER(sm->buf0)
89
| BPC_PORT(sm->send_args.port)
91
| BPC_FIRST_LINE(sm->send_args.first_line)
92
| BPC_LAST_LINE(0)); // last line filled in at runtime
94
sm->precomputed_send_from_buf_ctrl_word[1] =
96
| BPC_BUFFER(sm->buf0 ^ 1)
97
| BPC_PORT(sm->send_args.port)
99
| BPC_FIRST_LINE(sm->send_args.first_line)
100
| BPC_LAST_LINE(0)); // last line filled in at runtime
105
dbsm_receive_to_buf(dbsm_t *sm, int bufno)
107
buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 1];
111
dbsm_send_from_buf(dbsm_t *sm, int bufno)
113
buffer_pool_ctrl->ctrl =
114
(sm->precomputed_send_from_buf_ctrl_word[bufno & 1]
115
| BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj));
119
dbsm_start(dbsm_t *sm)
121
// printf("dbsm_start: buf0 = %d, recv_port = %d\n", sm->buf0, sm->recv_args.port);
125
buffer_state[sm->buf0] = BS_EMPTY;
126
buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
128
bp_clear_buf(sm->buf0);
129
bp_clear_buf(sm->buf0 ^ 1);
133
dbsm_receive_to_buf(sm, sm->buf0);
134
buffer_state[sm->buf0] = BS_FILLING;
140
dbsm_stop(dbsm_t *sm)
143
bp_clear_buf(sm->buf0);
144
bp_clear_buf(sm->buf0 ^ 1);
145
buffer_state[sm->buf0] = BS_EMPTY;
146
buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
149
static void dbsm_process_helper(dbsm_t *sm, int buf_this);
150
static void dbsm_error_helper(dbsm_t *sm, int buf_this);
153
dbsm_process_status(dbsm_t *sm, uint32_t status)
158
if (status & (BPS_ERROR(sm->buf0) | BPS_ERROR(sm->buf0 ^ 1))){
160
// Most likely an ethernet Rx error. We just restart the transfer.
161
if (status & (BPS_ERROR(sm->buf0)))
162
dbsm_error_helper(sm, sm->buf0);
164
if (status & (BPS_ERROR(sm->buf0 ^ 1)))
165
dbsm_error_helper(sm, sm->buf0 ^ 1);
168
if (status & BPS_DONE(sm->buf0))
169
dbsm_process_helper(sm, sm->buf0);
171
if (status & BPS_DONE(sm->buf0 ^ 1))
172
dbsm_process_helper(sm, sm->buf0 ^ 1);
176
dbsm_process_helper(dbsm_t *sm, int buf_this)
178
int buf_other = buf_this ^ 1;
180
bp_clear_buf(buf_this);
182
if (buffer_state[buf_this] == BS_FILLING){
183
buffer_state[buf_this] = BS_FULL;
185
// does s/w handle this packet?
187
if (sm->inspect(sm, buf_this)){
188
// s/w handled the packet; refill the buffer
189
dbsm_receive_to_buf(sm, buf_this);
190
buffer_state[buf_this] = BS_FILLING;
193
else { // s/w didn't handle this; pass it on
195
if(buffer_state[buf_other] == BS_EMPTY){
196
dbsm_receive_to_buf(sm, buf_other);
197
buffer_state[buf_other] = BS_FILLING;
204
dbsm_send_from_buf(sm, buf_this);
205
buffer_state[buf_this] = BS_EMPTYING;
209
else { // buffer was emptying
210
buffer_state[buf_this] = BS_EMPTY;
213
dbsm_receive_to_buf(sm, buf_this);
214
buffer_state[buf_this] = BS_FILLING;
216
if (buffer_state[buf_other] == BS_FULL){
217
dbsm_send_from_buf(sm, buf_other);
218
buffer_state[buf_other] = BS_EMPTYING;
226
dbsm_error_helper(dbsm_t *sm, int buf_this)
228
bp_clear_buf(buf_this); // clears ERROR flag
230
if (buffer_state[buf_this] == BS_FILLING){
231
dbsm_receive_to_buf(sm, buf_this); // restart the xfer
233
else { // buffer was emptying
234
dbsm_send_from_buf(sm, buf_this); // restart the xfer
239
* Handle DSP Tx underrun
242
dbsm_handle_tx_underrun(dbsm_t *sm)
244
// clear the DSP Tx state machine
245
dsp_tx_regs->clear_state = 1;
247
// If there's a buffer that's empyting, clear it & flush xfer
249
if (buffer_state[sm->buf0] == BS_EMPTYING){
250
bp_clear_buf(sm->buf0);
251
dsp_tx_regs->clear_state = 1; // flush partial packet
252
// drop frame in progress on ground. Pretend it finished
253
dbsm_process_helper(sm, sm->buf0);
255
else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
256
bp_clear_buf(sm->buf0 ^ 1);
257
dsp_tx_regs->clear_state = 1; // flush partial packet
258
// drop frame in progress on ground. Pretend it finished
259
dbsm_process_helper(sm, sm->buf0 ^ 1);
264
* Handle DSP Rx overrun
267
dbsm_handle_rx_overrun(dbsm_t *sm)
269
dsp_rx_regs->clear_state = 1;
271
// If there's a buffer that's filling, clear it.
272
// Any restart will be the job of the caller.
274
if (buffer_state[sm->buf0] == BS_FILLING)
275
bp_clear_buf(sm->buf0);
277
if (buffer_state[sm->buf0 ^1] == BS_FILLING)
278
bp_clear_buf(sm->buf0 ^ 1);
282
dbsm_wait_for_opening(dbsm_t *sm)
284
if (buffer_state[sm->buf0] == BS_EMPTYING){
285
// wait for xfer to complete
286
int mask = BPS_DONE(sm->buf0) | BPS_ERROR(sm->buf0) | BPS_IDLE(sm->buf0);
287
while ((buffer_pool_status->status & mask) == 0)
290
else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
291
// wait for xfer to complete
292
int mask = BPS_DONE(sm->buf0 ^ 1) | BPS_ERROR(sm->buf0 ^ 1) | BPS_IDLE(sm->buf0 ^ 1);
293
while ((buffer_pool_status->status & mask) == 0)