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;
66 sm->last_line_adj = 1;
68 buffer_state[sm->buf0] = BS_EMPTY;
69 buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
71 sm->precomputed_receive_to_buf_ctrl_word[0] =
73 | BPC_BUFFER(sm->buf0)
74 | BPC_PORT(sm->recv_args.port)
76 | BPC_FIRST_LINE(sm->recv_args.first_line)
77 | BPC_LAST_LINE(sm->recv_args.last_line));
79 sm->precomputed_receive_to_buf_ctrl_word[1] =
81 | BPC_BUFFER(sm->buf0 ^ 1)
82 | BPC_PORT(sm->recv_args.port)
84 | BPC_FIRST_LINE(sm->recv_args.first_line)
85 | BPC_LAST_LINE(sm->recv_args.last_line));
87 sm->precomputed_send_from_buf_ctrl_word[0] =
89 | BPC_BUFFER(sm->buf0)
90 | BPC_PORT(sm->send_args.port)
92 | BPC_FIRST_LINE(sm->send_args.first_line)
93 | BPC_LAST_LINE(0)); // last line filled in at runtime
95 sm->precomputed_send_from_buf_ctrl_word[1] =
97 | BPC_BUFFER(sm->buf0 ^ 1)
98 | BPC_PORT(sm->send_args.port)
100 | BPC_FIRST_LINE(sm->send_args.first_line)
101 | BPC_LAST_LINE(0)); // last line filled in at runtime
106 dbsm_receive_to_buf(dbsm_t *sm, int bufno)
108 buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 1];
112 dbsm_send_from_buf(dbsm_t *sm, int bufno)
114 buffer_pool_ctrl->ctrl =
115 (sm->precomputed_send_from_buf_ctrl_word[bufno & 1]
116 | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj));
120 dbsm_start(dbsm_t *sm)
122 // printf("dbsm_start: buf0 = %d, recv_port = %d\n", sm->buf0, sm->recv_args.port);
126 buffer_state[sm->buf0] = BS_EMPTY;
127 buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
129 bp_clear_buf(sm->buf0);
130 bp_clear_buf(sm->buf0 ^ 1);
134 dbsm_receive_to_buf(sm, sm->buf0);
135 buffer_state[sm->buf0] = BS_FILLING;
141 dbsm_stop(dbsm_t *sm)
144 bp_clear_buf(sm->buf0);
145 bp_clear_buf(sm->buf0 ^ 1);
146 buffer_state[sm->buf0] = BS_EMPTY;
147 buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
150 static void dbsm_process_helper(dbsm_t *sm, int buf_this);
151 static void dbsm_error_helper(dbsm_t *sm, int buf_this);
154 dbsm_process_status(dbsm_t *sm, uint32_t status)
159 if (status & (BPS_ERROR(sm->buf0) | BPS_ERROR(sm->buf0 ^ 1))){
161 // Most likely an ethernet Rx error. We just restart the transfer.
162 if (status & (BPS_ERROR(sm->buf0)))
163 dbsm_error_helper(sm, sm->buf0);
165 if (status & (BPS_ERROR(sm->buf0 ^ 1)))
166 dbsm_error_helper(sm, sm->buf0 ^ 1);
169 if (status & BPS_DONE(sm->buf0))
170 dbsm_process_helper(sm, sm->buf0);
172 if (status & BPS_DONE(sm->buf0 ^ 1))
173 dbsm_process_helper(sm, sm->buf0 ^ 1);
177 dbsm_process_helper(dbsm_t *sm, int buf_this)
179 int buf_other = buf_this ^ 1;
181 bp_clear_buf(buf_this);
183 if (buffer_state[buf_this] == BS_FILLING){
184 buffer_state[buf_this] = BS_FULL;
186 // does s/w handle this packet?
188 if (sm->inspect(sm, buf_this)){
189 // s/w handled the packet; refill the buffer
190 dbsm_receive_to_buf(sm, buf_this);
191 buffer_state[buf_this] = BS_FILLING;
194 else { // s/w didn't handle this; pass it on
196 if(buffer_state[buf_other] == BS_EMPTY){
197 dbsm_receive_to_buf(sm, buf_other);
198 buffer_state[buf_other] = BS_FILLING;
205 dbsm_send_from_buf(sm, buf_this);
206 buffer_state[buf_this] = BS_EMPTYING;
210 else { // buffer was emptying
211 buffer_state[buf_this] = BS_EMPTY;
214 dbsm_receive_to_buf(sm, buf_this);
215 buffer_state[buf_this] = BS_FILLING;
217 if (buffer_state[buf_other] == BS_FULL){
218 dbsm_send_from_buf(sm, buf_other);
219 buffer_state[buf_other] = BS_EMPTYING;
227 dbsm_error_helper(dbsm_t *sm, int buf_this)
229 bp_clear_buf(buf_this); // clears ERROR flag
231 if (buffer_state[buf_this] == BS_FILLING){
232 dbsm_receive_to_buf(sm, buf_this); // restart the xfer
234 else { // buffer was emptying
235 dbsm_send_from_buf(sm, buf_this); // restart the xfer
240 * Handle DSP Tx underrun
243 dbsm_handle_tx_underrun(dbsm_t *sm)
245 // clear the DSP Tx state machine
246 dsp_tx_regs->clear_state = 1;
248 // If there's a buffer that's empyting, clear it & flush xfer
250 if (buffer_state[sm->buf0] == BS_EMPTYING){
251 bp_clear_buf(sm->buf0);
252 dsp_tx_regs->clear_state = 1; // flush partial packet
253 // drop frame in progress on ground. Pretend it finished
254 dbsm_process_helper(sm, sm->buf0);
256 else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
257 bp_clear_buf(sm->buf0 ^ 1);
258 dsp_tx_regs->clear_state = 1; // flush partial packet
259 // drop frame in progress on ground. Pretend it finished
260 dbsm_process_helper(sm, sm->buf0 ^ 1);
265 * Handle DSP Rx overrun
268 dbsm_handle_rx_overrun(dbsm_t *sm)
270 dsp_rx_regs->clear_state = 1;
272 // If there's a buffer that's filling, clear it.
273 // Any restart will be the job of the caller.
275 if (buffer_state[sm->buf0] == BS_FILLING)
276 bp_clear_buf(sm->buf0);
278 if (buffer_state[sm->buf0 ^1] == BS_FILLING)
279 bp_clear_buf(sm->buf0 ^ 1);
283 dbsm_wait_for_opening(dbsm_t *sm)
285 if (buffer_state[sm->buf0] == BS_EMPTYING){
286 // wait for xfer to complete
287 int mask = BPS_DONE(sm->buf0) | BPS_ERROR(sm->buf0) | BPS_IDLE(sm->buf0);
288 while ((buffer_pool_status->status & mask) == 0)
291 else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
292 // wait for xfer to complete
293 int mask = BPS_DONE(sm->buf0 ^ 1) | BPS_ERROR(sm->buf0 ^ 1) | BPS_IDLE(sm->buf0 ^ 1);
294 while ((buffer_pool_status->status & mask) == 0)