root / firmware / microblaze / apps / app_passthru_v2.c @ aab51fa4
History | View | Annotate | Download (6.28 KB)
| 1 | d088a11b | Josh Blum | /* -*- c++ -*- */
|
|---|---|---|---|
| 2 | /*
|
||
| 3 | * Copyright 2007,2008 Free Software Foundation, Inc.
|
||
| 4 | *
|
||
| 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.
|
||
| 9 | *
|
||
| 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.
|
||
| 14 | *
|
||
| 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/>.
|
||
| 17 | */
|
||
| 18 | |||
| 19 | #ifdef HAVE_CONFIG_H
|
||
| 20 | #include "config.h" |
||
| 21 | #endif
|
||
| 22 | |||
| 23 | #include "app_passthru_v2.h" |
||
| 24 | #include "buffer_pool.h" |
||
| 25 | #include "memcpy_wa.h" |
||
| 26 | #include "ethernet.h" |
||
| 27 | #include "nonstdio.h" |
||
| 28 | #include "print_rmon_regs.h" |
||
| 29 | #include "db.h" |
||
| 30 | #include "clocks.h" |
||
| 31 | #include <string.h> |
||
| 32 | |||
| 33 | volatile bool link_is_up = false; // eth handler sets this |
||
| 34 | |||
| 35 | |||
| 36 | // If this is non-zero, this dbsm could be writing to the ethernet
|
||
| 37 | dbsm_t *ac_could_be_sending_to_eth; |
||
| 38 | |||
| 39 | //static unsigned char exp_seqno = 0;
|
||
| 40 | |||
| 41 | void
|
||
| 42 | set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt)
|
||
| 43 | {
|
||
| 44 | reply_pkt->ehdr.dst = cmd_pkt->ehdr.src; |
||
| 45 | reply_pkt->ehdr.src = *ethernet_mac_addr(); |
||
| 46 | reply_pkt->ehdr.ethertype = U2_ETHERTYPE; |
||
| 47 | reply_pkt->thdr.flags = 0;
|
||
| 48 | reply_pkt->thdr.fifo_status = 0; // written by protocol engine |
||
| 49 | reply_pkt->thdr.seqno = 0; // written by protocol engine |
||
| 50 | reply_pkt->thdr.ack = 0; // written by protocol engine |
||
| 51 | u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN);
|
||
| 52 | reply_pkt->fixed.timestamp = timer_regs->time; |
||
| 53 | } |
||
| 54 | |||
| 55 | static void |
||
| 56 | send_reply(unsigned char *reply, size_t reply_len) |
||
| 57 | {
|
||
| 58 | if (reply_len < 64) |
||
| 59 | reply_len = 64;
|
||
| 60 | |||
| 61 | // wait for buffer to become idle
|
||
| 62 | hal_set_leds(0x4, 0x4); |
||
| 63 | while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0) |
||
| 64 | ; |
||
| 65 | hal_set_leds(0x0, 0x4); |
||
| 66 | |||
| 67 | // copy reply into CPU_TX_BUF
|
||
| 68 | memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len); |
||
| 69 | |||
| 70 | // wait until nobody else is sending to the ethernet
|
||
| 71 | if (ac_could_be_sending_to_eth){
|
||
| 72 | hal_set_leds(0x8, 0x8); |
||
| 73 | dbsm_wait_for_opening(ac_could_be_sending_to_eth); |
||
| 74 | hal_set_leds(0x0, 0x8); |
||
| 75 | } |
||
| 76 | |||
| 77 | // fire it off
|
||
| 78 | bp_send_from_buf(CPU_TX_BUF, PORT_ETH, 1, 0, reply_len/4); |
||
| 79 | |||
| 80 | // wait for it to complete (not long, it's a small pkt)
|
||
| 81 | while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0) |
||
| 82 | ; |
||
| 83 | |||
| 84 | bp_clear_buf(CPU_TX_BUF); |
||
| 85 | } |
||
| 86 | |||
| 87 | |||
| 88 | static size_t
|
||
| 89 | op_id_cmd(const op_generic_t *p,
|
||
| 90 | void *reply_payload, size_t reply_payload_space)
|
||
| 91 | {
|
||
| 92 | op_id_reply_t *r = (op_id_reply_t *) reply_payload; |
||
| 93 | if (reply_payload_space < sizeof(*r)) // no room |
||
| 94 | return 0; |
||
| 95 | |||
| 96 | // Build reply subpacket
|
||
| 97 | |||
| 98 | r->opcode = OP_ID_REPLY; |
||
| 99 | r->len = sizeof(op_id_reply_t);
|
||
| 100 | r->rid = p->rid; |
||
| 101 | r->addr = *ethernet_mac_addr(); |
||
| 102 | r->hw_rev = 0x0000; // FIXME |
||
| 103 | // r->fpga_md5sum = ; // FIXME
|
||
| 104 | // r->sw_md5sum = ; // FIXME
|
||
| 105 | |||
| 106 | // FIXME Add d'board info, including dbid, min/max gain, min/max freq
|
||
| 107 | |||
| 108 | return r->len;
|
||
| 109 | } |
||
| 110 | |||
| 111 | static size_t
|
||
| 112 | add_eop(void *reply_payload, size_t reply_payload_space)
|
||
| 113 | {
|
||
| 114 | op_generic_t *r = (op_generic_t *) reply_payload; |
||
| 115 | if (reply_payload_space < sizeof(*r)) |
||
| 116 | return 0; // no room |
||
| 117 | |||
| 118 | r->opcode = OP_EOP; |
||
| 119 | r->len = sizeof(*r);
|
||
| 120 | r->rid = 0;
|
||
| 121 | r->ok = 0;
|
||
| 122 | |||
| 123 | return r->len;
|
||
| 124 | } |
||
| 125 | |||
| 126 | bool
|
||
| 127 | handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) |
||
| 128 | {
|
||
| 129 | unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4; |
||
| 130 | unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)]; |
||
| 131 | int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t); |
||
| 132 | |||
| 133 | bool handled_it = false; |
||
| 134 | |||
| 135 | // initialize reply
|
||
| 136 | memset(reply, 0, sizeof(reply)); |
||
| 137 | set_reply_hdr((u2_eth_packet_t *) reply, pkt); |
||
| 138 | |||
| 139 | // point to beginning of payload (subpackets)
|
||
| 140 | unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t); |
||
| 141 | int payload_len = len - sizeof(u2_eth_packet_t); |
||
| 142 | |||
| 143 | size_t subpktlen = 0;
|
||
| 144 | |||
| 145 | while (payload_len >= sizeof(op_generic_t)){ |
||
| 146 | const op_generic_t *gp = (const op_generic_t *) payload; |
||
| 147 | subpktlen = 0;
|
||
| 148 | |||
| 149 | switch(gp->opcode){
|
||
| 150 | case OP_EOP: // end of subpackets |
||
| 151 | goto end_of_subpackets;
|
||
| 152 | |||
| 153 | case OP_ID:
|
||
| 154 | subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space); |
||
| 155 | handled_it = true;
|
||
| 156 | break;
|
||
| 157 | |||
| 158 | default:
|
||
| 159 | if (0){ |
||
| 160 | printf("\npassing on %d\n", gp->opcode);
|
||
| 161 | } |
||
| 162 | break;
|
||
| 163 | } |
||
| 164 | |||
| 165 | int t = (gp->len + 3) & ~3; // bump to a multiple of 4 |
||
| 166 | payload += t; |
||
| 167 | payload_len -= t; |
||
| 168 | |||
| 169 | subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4 |
||
| 170 | reply_payload += subpktlen; |
||
| 171 | reply_payload_space -= subpktlen; |
||
| 172 | } |
||
| 173 | |||
| 174 | end_of_subpackets:
|
||
| 175 | |||
| 176 | if (handled_it){
|
||
| 177 | // add the EOP marker
|
||
| 178 | subpktlen = add_eop(reply_payload, reply_payload_space); |
||
| 179 | subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4 |
||
| 180 | reply_payload += subpktlen; |
||
| 181 | reply_payload_space -= subpktlen; |
||
| 182 | |||
| 183 | send_reply(reply, reply_payload - reply); |
||
| 184 | } |
||
| 185 | |||
| 186 | return handled_it;
|
||
| 187 | } |
||
| 188 | |||
| 189 | |||
| 190 | /*
|
||
| 191 | * Called when an ethernet packet is received.
|
||
| 192 | * Return true if we handled it here, otherwise
|
||
| 193 | * it'll be passed on to the DSP Tx pipe
|
||
| 194 | */
|
||
| 195 | bool
|
||
| 196 | eth_pkt_inspector(dbsm_t *sm, int bufno)
|
||
| 197 | {
|
||
| 198 | u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); |
||
| 199 | size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4; |
||
| 200 | |||
| 201 | //static size_t last_len = 0;
|
||
| 202 | |||
| 203 | // hal_toggle_leds(0x1);
|
||
| 204 | |||
| 205 | // inspect rcvd frame and figure out what do do.
|
||
| 206 | |||
| 207 | if (pkt->ehdr.ethertype != U2_ETHERTYPE)
|
||
| 208 | return true; // ignore, probably bogus PAUSE frame from MAC |
||
| 209 | |||
| 210 | int chan = u2p_chan(&pkt->fixed);
|
||
| 211 | |||
| 212 | switch (chan){
|
||
| 213 | case CONTROL_CHAN:
|
||
| 214 | return handle_control_chan_frame(pkt, byte_len);
|
||
| 215 | break;
|
||
| 216 | |||
| 217 | case 0: |
||
| 218 | default:
|
||
| 219 | #if 0
|
||
| 220 | if (last_len != 0){
|
||
| 221 | if (byte_len != last_len){
|
||
| 222 | printf("Len: %d last: %d\n", byte_len, last_len);
|
||
| 223 | }
|
||
| 224 | }
|
||
| 225 | last_len = byte_len;
|
||
| 226 | |||
| 227 | if((pkt->thdr.seqno) == exp_seqno){
|
||
| 228 | exp_seqno++;
|
||
| 229 | //putchar('.');
|
||
| 230 | }
|
||
| 231 | else {
|
||
| 232 | // putchar('S');
|
||
| 233 | //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
|
||
| 234 | exp_seqno = pkt->thdr.seqno + 1;
|
||
| 235 | }
|
||
| 236 | #endif
|
||
| 237 | return false; // pass it on to Tx DSP |
||
| 238 | break;
|
||
| 239 | } |
||
| 240 | } |
||
| 241 | |||
| 242 | /*
|
||
| 243 | * Called when eth phy state changes (w/ interrupts disabled)
|
||
| 244 | */
|
||
| 245 | void
|
||
| 246 | link_changed_callback(int speed)
|
||
| 247 | {
|
||
| 248 | link_is_up = speed != 0;
|
||
| 249 | hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45);
|
||
| 250 | printf("\neth link changed: speed = %d\n", speed);
|
||
| 251 | } |