/* Cesar project {{{ * * Copyright (C) 2008 Spidcom * * <<>> * * }}} */ /** * \file bridgedma-init-test.c * \brief « brief description » * \ingroup « module » * * « long description » */ #include #include #include "common/std.h" #include "common/defs/ethernet.h" #include "lib/test.h" #include "lib/list.h" #include "lib/read_word.h" #include "lib/bitstream.h" #include "hal/phy/inc/bridgedma.h" #include "hal/phy/inc/bridgedma_proto.h" #include "mac/common/pb.h" #include #include #include #define START_OFFSET 128 cyg_thread my_test_thread; cyg_handle_t my_test_thread_handle; u8 my_test_thread_stack [CYGNUM_HAL_STACK_SIZE_TYPICAL]; pb_t *my_pb_first; pb_t *my_pb_last; phy_bridgedma_job_t *job_current; phy_bridgedma_job_t job1, job2, job3; phy_bridgedma_t *bridgedma_ctx; u8 frame_buffer [2048] __attribute__((aligned(2048))); crc_t crc_ctx; blk_t *pb_first, *pb_last, *pb_current; u32 mf_header; u32 enc_tab[256]; uint ats; /* WARNING: callback are not possible to test inside UNIT TEST */ bool _bridgedma_segmentation_cb(void *data, u32 status) { // If no more jobs to process by the bridgedma wake up the test thread to // continue if (!job_current) { cyg_thread_resume (my_test_thread_handle); } if (job_current) { diag_printf ("----- Bridge Cb ----\n"); diag_printf ("SSN : %d\n", ((pb_t*)job_current->first_pb_desc)->header.ssn); diag_printf ("offset : %d\n", job_current->first_pb_offset); diag_printf ("length : %d\n", read_u16_from_word (((pb_t *)job_current->first_pb_desc)->data + job_current->first_pb_offset) >> 2); diag_printf ("---- END Bridge Cb ----\n"); } job_current = job_current->next; return true; } /* WARNING: callback are not possible to test inside UNIT TEST */ void _bridgedma_deffered_cb(void *data) { } void bridgedma_init_test_case(test_t t) { int user_data; test_case_begin(t, "init"); test_begin(t, "init") { bridgedma_ctx = NULL; bridgedma_ctx = phy_bridgedma_init(&user_data, _bridgedma_segmentation_cb, _bridgedma_deffered_cb); test_fail_unless( (bridgedma_ctx != NULL) && (bridgedma_ctx->job_first == NULL) && (bridgedma_ctx->job_current == NULL) && (bridgedma_ctx->job_last == NULL) && (bridgedma_ctx->user_data == &user_data) && (bridgedma_ctx->bridgedma_cb == _bridgedma_segmentation_cb) && (bridgedma_ctx->deferred_cb == _bridgedma_deffered_cb) && !bridgedma_ctx->status.running && bridgedma_ctx->status.stop ); } test_end; return; } void bridgedma_segmentation_test_case(test_t t) { uint i; pb_t *my_current; dbg_assert (bridgedma_ctx); test_case_begin(t, "segmentation"); pb_first = blk_alloc_desc_range(5, &pb_last); pb_last->next = NULL; my_pb_first = (pb_t *) pb_first; my_pb_last = (pb_t *)pb_last; my_current = my_pb_first; for (i = 0; i < 5; i++) { my_current->header.ssn = i; my_current = my_current->next; } crc_ctx.width = 32; crc_ctx.generator = HPAV_CRC32_GENERATOR; crc_ctx.init = HPAV_CRC32_INIT; crc_ctx.refin = true; crc_ctx.refout = true; crc_ctx.xorout = 0xffffffff; crc_ctx.reg_init = 0; crc_ctx.table.t32 = enc_tab; crc_init(&crc_ctx); ats = 0x12345678; /************************************************************************ * simple segmentation with 3 mac frames into 5 PBs * 1st mac frame: len=1518, offset=128, ATS, ICV into 1st to 4th PB * 2nd mac frame: len=64, ATS, ICV into 4th PB * 3nd mac frame: len=466, ATS, ICV, padding into 4th to 5th PB ***********************************************************************/ memset(&job1, '\0', sizeof(job1)); job1.next = &job2; job1.data_addr = frame_buffer; job1.header_len = 6; job1.data_len = ETH_PACKET_MAX_SIZE; job1.first_pb_desc = pb_first; job1.first_pb_offset = START_OFFSET; job1.segment_len = 512; job1.direction = 0; job1.crc_reset = 1; job1.crc_store = 1; job1.job_it = 1; job1.eth_buffer_mask = 0x1fffff0; /* 2048 bytes mask */ job1.mf_header1 = (((job1.data_len + 4 - 1) << 2) | 0x02) | (ats << 16); /* Payload + ATS */ job1.mf_header2 = (ats >> 16); memset(&job2, '\0', sizeof(job2)); job2.next = &job3; job2.data_addr = frame_buffer + job1.data_len; job2.header_len = 6; job2.data_len = ETH_PACKET_MIN_SIZE; job2.first_pb_desc = pb_first->next->next->next; /* 4th PB */ job2.first_pb_offset = (START_OFFSET + job1.data_len + 10) % 512; job2.segment_len = 512; job2.direction = 0; job2.crc_reset = 1; job2.crc_store = 1; job2.job_it = 1; job2.eth_buffer_mask = 0x1fffff0; /* 2048 bytes mask */ job2.mf_header1 = (((job2.data_len + 4 - 1) << 2) | 0x02) | (ats << 16); /* Payload + ATS */ job2.mf_header2 = (ats >> 16); memset(&job3, '\0', sizeof(job3)); job3.next = NULL; job3.data_addr = frame_buffer + job1.data_len + job2.data_len; job3.header_len = 6; job3.data_len = sizeof(frame_buffer) - ETH_PACKET_MAX_SIZE - ETH_PACKET_MIN_SIZE; job3.first_pb_desc = pb_first->next->next->next; /* 4th PB */ job3.first_pb_offset = (START_OFFSET + job1.data_len + 10 + job2.data_len + 10) % 512; job3.segment_len = 512; job3.last = 1; job3.direction = 0; job3.crc_reset = 1; job3.crc_store = 1; job3.append_zero = 1; job3.job_it = 1; job3.eth_buffer_mask = 0x1fffff0; /* 2048 bytes mask */ job3.mf_header1 = (((job3.data_len + 4 - 1) << 2) | 0x02) | (ats << 16); /* Payload + ATS */ job3.mf_header2 = (ats >> 16); job_current = &job1; phy_bridgedma_start (bridgedma_ctx, &job1, &job3); return; } void bridgedma_segmentation_verify_test_case (test_t test) { uint payload_cnt; uint crc_current; pb_t *my_pb_current; uint i; uint length; uint pb_offset; uint qte_pb; uint frame_offset; bool cont; test_begin(test, "segmentation of 3 frames") { for (i = 0, my_pb_current = my_pb_first; my_pb_current; my_pb_current = my_pb_current->next, i++) { test_fail_if (my_pb_current->header.ssn != i, "Wong sequence"); } /* check pb content */ /* check 1st mac frame into PB */ payload_cnt = 0; crc_current = crc_compute_begin(&crc_ctx); pb_offset = START_OFFSET; job_current = &job1; frame_offset = 0; for (pb_current = pb_first, i = 0; i < 3; i++, job_current = job_current->next) { cont = true; length = 1 + (read_u16_from_word (pb_current->data + pb_offset) >> 2); // To get the payload length, the frame length is 10 // bytes greater. length -= 4; diag_printf ("Length read in pb : %d\n", length); diag_printf ("pb ssn : %d\n", ((pb_t *)pb_current)->header.ssn); diag_printf ("pb offset : %d\n", pb_offset); test_fail_unless (length == job_current->data_len, "Data length is wrong."); // Copy the data of the current pb. // Jump directly to the start of the payload. pb_offset += 6; if (length + pb_offset > BLK_SIZE) { test_fail_unless ( bitstream_memcmp (frame_buffer + frame_offset, pb_current->data + pb_offset, BLK_SIZE - pb_offset), "data corrupted"); frame_offset += BLK_SIZE - pb_offset; length -= BLK_SIZE - pb_offset; } else { test_fail_unless ( bitstream_memcmp (frame_buffer + frame_offset, pb_current->data + pb_offset, length), "data corrupted"); frame_offset += length; cont = false; } if (cont) { // Add 10 to the length to use the complete MF length // (ATS + MFH + ICV), the ATS and MFH are already include in the // pb_offset. for (qte_pb = (pb_offset + length + 4) / BLK_SIZE + 1; qte_pb; qte_pb --) { pb_current = pb_current->next; if (length > BLK_SIZE) { test_fail_unless( bitstream_memcmp (frame_buffer + frame_offset, pb_current->data , BLK_SIZE), "data corrupted"); length -= BLK_SIZE; frame_offset += BLK_SIZE; } else { test_fail_unless( bitstream_memcmp (frame_buffer + frame_offset, pb_current->data , length), "data corrupted"); frame_offset += length; } } } // The futur offset is length + 4 cause of the ICV of the MF. // The ATS and the MFH has already been jumped above in the // pb_offset. pb_offset = (pb_offset + job_current->data_len + 4) % BLK_SIZE; } } test_end; blk_release_desc_range((blk_t *)my_pb_first, (blk_t *) my_pb_last); } void test_thread_process (cyg_addrword_t data) { test_t *test; test = (test_t *) data; bridgedma_init_test_case (*test); bridgedma_segmentation_test_case (*test); /* Just to test. */ diag_printf ("Job 1 header : %x\n", job1.mf_header1); diag_printf ("Job 2 header : %x\n", job2.mf_header1); diag_printf ("Job 3 header : %x\n", job3.mf_header1); /* */ bridgedma_segmentation_verify_test_case (*test); phy_bridgedma_uninit (bridgedma_ctx); test_result (*test); #ifndef __sparc__ HAL_PLATFORM_EXIT (test_nb_failed (*test) == 0 ? 0 : 1); #endif } int main (void) { test_t test; uint i; test_init (test, 0, NULL); pb_first = NULL; pb_last = NULL; my_pb_first = NULL; my_pb_last = NULL; for (i = 0; i < 2048; i++) frame_buffer[i] = i; // Create the thread. cyg_thread_create( 9, &test_thread_process, (cyg_addrword_t) &test, "TEST_THREAD", my_test_thread_stack, CYGNUM_HAL_STACK_SIZE_TYPICAL, &my_test_thread_handle, &my_test_thread); cyg_thread_resume (my_test_thread_handle); return 0; }