/*
* Multi-processor Packet Counting
* Single-threaded receive
* Chapter 5 Example code, with modified main()
* Run this code on microprocessor 0
*/
#include "ixp.h"
#include "CSR.h"
#include "buffer.h"
#define QWS_IN_RFIFO 8
/*
* get_mpacket: waits for an mpacket to be available on the given port
* then transfers it into the given RFIFO
*/
rcv_cntl_reg_t get_mpacket(unsigned int port_num,
unsigned int rfifo_num) {
unsigned int rcv_ready_bits;
rcv_req_reg_t rcv_request;
rcv_cntl_reg_t rcv_control;
/* Wait for data on the requested port */
do {
csr_read((void *)&rcv_ready_bits, rcv_rdy_lo, 1, ctx_swap);
} while ( !(rcv_ready_bits & (1 << port_num)) );
/* Build and issue the receive request */
rcv_request.reg_val = 0;
rcv_request.fields.rp = port_num;
rcv_request.fields.tid = ctx();
rcv_request.fields.e1 = rfifo_num;
csr_write(rcv_request.reg_val, rcv_req, no_signal);
/* Wait for the data to get pulled into the RFIFO */
ctx_wait(start_receive);
/* Get information about the mpacket */
csr_read((void *)&rcv_control.reg_val, rcv_cntl, 1, ctx_swap);
return rcv_control;
}
/* Reassembly state */
typedef struct _rcv_state_t {
unsigned int discard : 1; /* Entire packet is bad */
unsigned int mpkt_count : 6; /* # mpackets received */
buffer_handle_t handle;
} rcv_state_t;
/*
* transfer_mpacket_to_buffer: wrapper around sdram_r_fifo_read
* moves the given RFIFO data into
* SDRAM at the given address
*/
void transfer_mpacket_to_buffer(__declspec(sdram) void *buf_ptr,
unsigned int rfifo_num) {
fifo_read_write_ind_t rfifo_read_params = { 0 };
rfifo_read_params.qword_addr = rfifo_num * QWS_IN_RFIFO;
rfifo_read_params.ov_ref_count = 1;
rfifo_read_params.ref_count = QWS_IN_RFIFO - 1;
sdram_r_fifo_read_ind(
buf_ptr,
4, /* Overridden */
rfifo_read_params,
optimize_mem,
ctx_swap);
}
/*
* receive_packet: Properly reassembles an entire packet for
* the given port using the given RIFO
*/
buffer_handle_t receive_packet(unsigned int port_num,
unsigned int rfifo_num,
unsigned int *pkt_length) {
rcv_state_t rcv_state = { 0 };
rcv_cntl_reg_t rcv_control;
__declspec(sdram) void *buf_data_ptr;
do {
rcv_control = get_mpacket(port_num, rfifo_num);
/* Check that the packet was properly received */
if ( rcv_control.fields.rf || rcv_control.fields.rerr ) {
rcv_state.discard = 1;
if ( rcv_state.handle != BUFFER_NULL ) {
buffer_free(rcv_state.handle);
rcv_state.handle = BUFFER_NULL;
}
continue;
}
if ( rcv_control.fields.sop ) {
/* Allocate the buffer handle */
if ((rcv_state.handle = buffer_allocate()) == BUFFER_NULL) {
/* No room for packet */
rcv_state.discard = 1;
continue;
}
/* Transfer the mpacket into the buffer */
buf_data_ptr = buffer_get_data_ptr(rcv_state.handle);
transfer_mpacket_to_buffer(buf_data_ptr, rfifo_num);
/* Update the state */
rcv_state.discard = 0;
rcv_state.mpkt_count = 1;
} else {
/* Non-SOP */
if ( rcv_state.discard ) {
continue;
}
/* Transfer the mpacket into the buffer */
buf_data_ptr = (__declspec(sdram) void *)
(((unsigned int)buffer_get_data_ptr(rcv_state.handle)) +
(rcv_state.mpkt_count * 64 / sizeof(long long)));
transfer_mpacket_to_buffer(buf_data_ptr, rfifo_num);
/* Update the state */
rcv_state.mpkt_count++;
}
if ( rcv_control.fields.eop ) {
*pkt_length = ((rcv_state.mpkt_count - 1) * 64) +
rcv_control.fields.valid_bytes + 1;
return rcv_state.handle;
}
} while ( 1 );
}
/*
* Receive and count packets on a given port
*/
void main(void) {
int i;
buffer_handle_t buf_handle;
unsigned int cur_pkt_len;
__declspec(sram_write_reg) unsigned int mask;
__declspec(sram_read_reg) unsigned int temp;
volatile __declspec(sram) unsigned int * pktadr;
volatile __declspec(scratch) unsigned int * ready;
__declspec(sram_read_reg) unsigned int data;
__declspec(sram_write_reg) unsigned int newdata;
ready = (__declspec(scratch) unsigned int *) 0x0;
pktadr = (__declspec(sram) unsigned int *) 0x50;
*pktadr = BUFFER_NULL; // intializing
mask = 1;
/* Initialize our freelist */
buffer_free(BUFFER_NULL);
buffer_free(BUFFER_NULL);
for (i=0; i < 10; ++i) {
buffer_free(SRAM_BASE + i*SRAM_ENTRY_SIZE);
}
*ready = 1;
while (1) {
buf_handle = receive_packet(0, 5, &cur_pkt_len);
do
{
scratch_test_and_clear_bits(&temp, &mask, ready, ctx_swap);
}
while (!temp);
sram_read_lock(&data, pktadr, 1, queue_default, ctx_swap);
newdata = buf_handle;
sram_write_unlock(&newdata, pktadr, 1, queue_default, ctx_swap);
csr_fast_write(inter_thd_sig, 4); // send signal to thread on microprocessor 1
}
}
void exit(unsigned int code) {
/* empty */
}