Переменные
Код
volatile alt_sgdma_descriptor *SGDMARxDscrTab = (alt_sgdma_descriptor*)(DESCRIPTORS_ETH_BASE);
volatile alt_sgdma_descriptor *SGDMATxDscrTab = (alt_sgdma_descriptor*)(DESCRIPTORS_ETH_BASE+ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE*4);
volatile alt_sgdma_descriptor *SGDMARxDescToSet;
volatile alt_sgdma_descriptor *SGDMATxDescToSet;
volatile alt_sgdma_descriptor *SGDMATxDscrTab = (alt_sgdma_descriptor*)(DESCRIPTORS_ETH_BASE+ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE*4);
volatile alt_sgdma_descriptor *SGDMARxDescToSet;
volatile alt_sgdma_descriptor *SGDMATxDescToSet;
Настройка TSE и SGDMA.
Код
int MAC_init(void){
uint32_t errCount=0;
uint32_t *cached_packet_payload;
uint16_t temp;
/* Set phy address at marvell 88E11111*/
IOWR_ALTERA_TSEMAC_MDIO_ADDR0(TSE_BASE,PHY_ADDR);
printf("Initialization MAC and PHY.\n");
/* Wait while the bit of status register is wake up */
do{
errCount++;
temp = IORD_ALTERA_TSEMAC_MDIO(TSE_BASE,0,ALTERA_TSEMAC_PHY_ADDR_STATUS);
if(errCount>=0xFFFF0){
printf("\nError read status\n");
return 2;
}
}while(!(temp&PHY_LINK_UP)||(temp==0xFFFF));
errCount = 0;
/* Open scatter-gather DMA for receiver and transmitter */
sgdma_rx_dev = alt_avalon_sgdma_open(SGDMA_RX_NAME);
sgdma_tx_dev = alt_avalon_sgdma_open(SGDMA_TX_NAME);
if(ALT_ERRNO==ENODEV)
printf("Error opening sgdma rx or/and tx.\n");
/* Soft reset sgdma rx */
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,0x00);
/* Software reset MAC altera and enable rx and tx */
IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE,ALTERA_TSEMAC_CMD_SW_RESET_MSK|
ALTERA_TSEMAC_CMD_RX_ENA_MSK|
ALTERA_TSEMAC_CMD_TX_ENA_MSK);
while(IORD_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE)&ALTERA_TSEMAC_CMD_SW_RESET_MSK);
/* Configure MAC */
IOWR_ALTERA_TSEMAC_FRM_LENGTH(TSE_BASE,ALTERA_TSE_MAC_MAX_FRAME_LENGTH);
IOWR_ALTERA_TSEMAC_RX_ALMOST_EMPTY(TSE_BASE,8);
IOWR_ALTERA_TSEMAC_RX_ALMOST_FULL(TSE_BASE,8);
IOWR_ALTERA_TSEMAC_RX_SECTION_EMPTY(TSE_BASE,TSETHERNET_RECEIVE_FIFO_DEPTH-16);
IOWR_ALTERA_TSEMAC_RX_SECTION_FULL(TSE_BASE,16);
IOWR_ALTERA_TSEMAC_TX_ALMOST_EMPTY(TSE_BASE,8);
IOWR_ALTERA_TSEMAC_TX_ALMOST_FULL(TSE_BASE,3);
IOWR_ALTERA_TSEMAC_TX_SECTION_EMPTY(TSE_BASE,TSETHERNET_TRANSMIT_FIFO_DEPTH-16);
IOWR_ALTERA_TSEMAC_TX_SECTION_FULL(TSE_BASE,16);
IOWR_ALTERA_TSEMAC_TX_CMD_STAT(TSE_BASE,0);
IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_BASE,ALTERA_TSEMAC_RX_CMD_STAT_RXSHIFT16_MSK);
IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_BASE,0);
IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE,ALTERA_TSEMAC_CMD_RX_ENA_MSK|ALTERA_TSEMAC_CMD_TX_ENA_MSK|
ALTERA_TSEMAC_CMD_TX_ADDR_INS_MSK|ALTERA_TSEMAC_CMD_PAD_EN_MSK|
ALTERA_TSEMAC_CMD_RX_ERR_DISC_MSK|
ALTERA_TSEMAC_CMD_ETH_SPEED_MSK);
IOWR_ALTERA_TSEMAC_MAC_0(TSE_BASE,(mac_addr[1]<<8|mac_addr[2]<<16|mac_addr[3]<<24|mac_addr[0])&0xFFFFFFFF);
IOWR_ALTERA_TSEMAC_MAC_1(TSE_BASE,(mac_addr[5]<<8|mac_addr[4] & 0xFFFF));
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE)|ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);
/* Registering callback function for receiving */
alt_avalon_sgdma_register_callback(sgdma_rx_dev,(alt_avalon_sgdma_callback)&tse_sgdmaRx_isr,(uint16_t)ALTERA_TSE_SGDMA_INTR_MASK,sgdma_rx_dev);
/* Reforming non-cached memory to cached */
alt_avalon_sgdma_rx_reg_chain((alt_sgdma_descriptor*)SGDMARxDscrTab,(alt_u8*)Rx_Buff,4);
alt_avalon_sgdma_tx_reg_chain((alt_sgdma_descriptor*)SGDMATxDscrTab,(alt_u8*)Tx_Buff,2);
while(IORD_ALTERA_AVALON_SGDMA_STATUS(TSE_BASE)&ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
SGDMARxDescToSet->control |= ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev,(alt_sgdma_descriptor*)SGDMARxDscrTab);
printf("Pointer to SGDMA->CONTROL: %x\n",IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE));
sem=0;
return SUCCESS;
}
void alt_avalon_sgdma_rx_reg_chain(alt_sgdma_descriptor *sgdma_table,alt_u8 *RxBuff,alt_u32 length_table){
uint32_t i = 0;
alt_sgdma_descriptor *SGDMARxDesc;
while((((alt_u32)sgdma_table) % ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE) != 0){
sgdma_table++; // slide the pointer until 32 byte boundary is found
}
/* Set the DMARxDescToGet pointer with the first one of the DMARxDescTab list */
SGDMARxDescToSet = sgdma_table;
/* Fill each DMARxDesc descriptor with the right values */
for(i=0; i < length_table; i++){
/* Get the pointer on the ith member of the Rx Desc list */
SGDMARxDesc = sgdma_table+i;
/* Set Own bit of the Rx descriptor Status */
//SGDMARxDesc->Status = ETH_DMARxDesc_OWN;
/* Set Buffer1 size and Second Address Chained bit */
//SGDMARxDesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)ETH_RX_BUF_SIZE;
/* Set Buffer1 address pointer */
SGDMARxDesc->write_addr = i==0?(uint32_t*)(RxBuff):(uint32_t*)(RxBuff+i*1524);
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
if(i < (length_table-1)){
/* Set next descriptor address register with next descriptor base address */
SGDMARxDesc->next = (uint32_t*)(sgdma_table+i+1);
}
else{
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
SGDMARxDesc->next = (uint32_t*)(sgdma_table);
}
alt_avalon_sgdma_construct_stream_to_mem_desc((alt_sgdma_descriptor*)(SGDMARxDesc),
(alt_sgdma_descriptor*)SGDMARxDesc->next,SGDMARxDesc->write_addr,0,0);
while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) );
printf("Pointer to Desc: %p Pointer to next: %p RX buffer: %p\n",SGDMARxDesc,SGDMARxDesc->next,SGDMARxDesc->write_addr);
}
}
uint32_t errCount=0;
uint32_t *cached_packet_payload;
uint16_t temp;
/* Set phy address at marvell 88E11111*/
IOWR_ALTERA_TSEMAC_MDIO_ADDR0(TSE_BASE,PHY_ADDR);
printf("Initialization MAC and PHY.\n");
/* Wait while the bit of status register is wake up */
do{
errCount++;
temp = IORD_ALTERA_TSEMAC_MDIO(TSE_BASE,0,ALTERA_TSEMAC_PHY_ADDR_STATUS);
if(errCount>=0xFFFF0){
printf("\nError read status\n");
return 2;
}
}while(!(temp&PHY_LINK_UP)||(temp==0xFFFF));
errCount = 0;
/* Open scatter-gather DMA for receiver and transmitter */
sgdma_rx_dev = alt_avalon_sgdma_open(SGDMA_RX_NAME);
sgdma_tx_dev = alt_avalon_sgdma_open(SGDMA_TX_NAME);
if(ALT_ERRNO==ENODEV)
printf("Error opening sgdma rx or/and tx.\n");
/* Soft reset sgdma rx */
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,0x00);
/* Software reset MAC altera and enable rx and tx */
IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE,ALTERA_TSEMAC_CMD_SW_RESET_MSK|
ALTERA_TSEMAC_CMD_RX_ENA_MSK|
ALTERA_TSEMAC_CMD_TX_ENA_MSK);
while(IORD_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE)&ALTERA_TSEMAC_CMD_SW_RESET_MSK);
/* Configure MAC */
IOWR_ALTERA_TSEMAC_FRM_LENGTH(TSE_BASE,ALTERA_TSE_MAC_MAX_FRAME_LENGTH);
IOWR_ALTERA_TSEMAC_RX_ALMOST_EMPTY(TSE_BASE,8);
IOWR_ALTERA_TSEMAC_RX_ALMOST_FULL(TSE_BASE,8);
IOWR_ALTERA_TSEMAC_RX_SECTION_EMPTY(TSE_BASE,TSETHERNET_RECEIVE_FIFO_DEPTH-16);
IOWR_ALTERA_TSEMAC_RX_SECTION_FULL(TSE_BASE,16);
IOWR_ALTERA_TSEMAC_TX_ALMOST_EMPTY(TSE_BASE,8);
IOWR_ALTERA_TSEMAC_TX_ALMOST_FULL(TSE_BASE,3);
IOWR_ALTERA_TSEMAC_TX_SECTION_EMPTY(TSE_BASE,TSETHERNET_TRANSMIT_FIFO_DEPTH-16);
IOWR_ALTERA_TSEMAC_TX_SECTION_FULL(TSE_BASE,16);
IOWR_ALTERA_TSEMAC_TX_CMD_STAT(TSE_BASE,0);
IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_BASE,ALTERA_TSEMAC_RX_CMD_STAT_RXSHIFT16_MSK);
IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_BASE,0);
IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE,ALTERA_TSEMAC_CMD_RX_ENA_MSK|ALTERA_TSEMAC_CMD_TX_ENA_MSK|
ALTERA_TSEMAC_CMD_TX_ADDR_INS_MSK|ALTERA_TSEMAC_CMD_PAD_EN_MSK|
ALTERA_TSEMAC_CMD_RX_ERR_DISC_MSK|
ALTERA_TSEMAC_CMD_ETH_SPEED_MSK);
IOWR_ALTERA_TSEMAC_MAC_0(TSE_BASE,(mac_addr[1]<<8|mac_addr[2]<<16|mac_addr[3]<<24|mac_addr[0])&0xFFFFFFFF);
IOWR_ALTERA_TSEMAC_MAC_1(TSE_BASE,(mac_addr[5]<<8|mac_addr[4] & 0xFFFF));
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE)|ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);
/* Registering callback function for receiving */
alt_avalon_sgdma_register_callback(sgdma_rx_dev,(alt_avalon_sgdma_callback)&tse_sgdmaRx_isr,(uint16_t)ALTERA_TSE_SGDMA_INTR_MASK,sgdma_rx_dev);
/* Reforming non-cached memory to cached */
alt_avalon_sgdma_rx_reg_chain((alt_sgdma_descriptor*)SGDMARxDscrTab,(alt_u8*)Rx_Buff,4);
alt_avalon_sgdma_tx_reg_chain((alt_sgdma_descriptor*)SGDMATxDscrTab,(alt_u8*)Tx_Buff,2);
while(IORD_ALTERA_AVALON_SGDMA_STATUS(TSE_BASE)&ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
SGDMARxDescToSet->control |= ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev,(alt_sgdma_descriptor*)SGDMARxDscrTab);
printf("Pointer to SGDMA->CONTROL: %x\n",IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE));
sem=0;
return SUCCESS;
}
void alt_avalon_sgdma_rx_reg_chain(alt_sgdma_descriptor *sgdma_table,alt_u8 *RxBuff,alt_u32 length_table){
uint32_t i = 0;
alt_sgdma_descriptor *SGDMARxDesc;
while((((alt_u32)sgdma_table) % ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE) != 0){
sgdma_table++; // slide the pointer until 32 byte boundary is found
}
/* Set the DMARxDescToGet pointer with the first one of the DMARxDescTab list */
SGDMARxDescToSet = sgdma_table;
/* Fill each DMARxDesc descriptor with the right values */
for(i=0; i < length_table; i++){
/* Get the pointer on the ith member of the Rx Desc list */
SGDMARxDesc = sgdma_table+i;
/* Set Own bit of the Rx descriptor Status */
//SGDMARxDesc->Status = ETH_DMARxDesc_OWN;
/* Set Buffer1 size and Second Address Chained bit */
//SGDMARxDesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)ETH_RX_BUF_SIZE;
/* Set Buffer1 address pointer */
SGDMARxDesc->write_addr = i==0?(uint32_t*)(RxBuff):(uint32_t*)(RxBuff+i*1524);
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
if(i < (length_table-1)){
/* Set next descriptor address register with next descriptor base address */
SGDMARxDesc->next = (uint32_t*)(sgdma_table+i+1);
}
else{
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
SGDMARxDesc->next = (uint32_t*)(sgdma_table);
}
alt_avalon_sgdma_construct_stream_to_mem_desc((alt_sgdma_descriptor*)(SGDMARxDesc),
(alt_sgdma_descriptor*)SGDMARxDesc->next,SGDMARxDesc->write_addr,0,0);
while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) );
printf("Pointer to Desc: %p Pointer to next: %p RX buffer: %p\n",SGDMARxDesc,SGDMARxDesc->next,SGDMARxDesc->write_addr);
}
}
Обработка прерывания
Код
#define DEBUGE 1
int tse_sgdmaRx_isr(void * context, alt_u32 irqnum){
alt_u32 t2=0;
alt_u32 *uncached_packet_payload;
t2=IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE);
alt_sgdma_descriptor *SGDMARx_OWEN = (alt_sgdma_descriptor *)IORD_ALTERA_AVALON_SGDMA_NEXT_DESC_POINTER(SGDMA_RX_BASE);
//SGDMARxDescToSet = (alt_sgdma_descriptor*)(SGDMARxDescToSet->next);
if (t2 & (ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK|
ALTERA_AVALON_SGDMA_STATUS_DESC_COMPLETED_MSK)){
p_counter++;
//alt_printf("Packet counter:%x\n",p_counter);
IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK);
t2=IORD_ALTERA_TSE_SGDMA_DESC_STATUS((alt_sgdma_descriptor *)SGDMARxDescToSet);
/*check status and handle packet*/
if((t2&(ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK |
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK |
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK |
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK ) ) == 0){
t2=IORD_16DIRECT((alt_sgdma_descriptor *)SGDMARxDescToSet->actual_bytes_transferred, 0)-2;
}
else{
alt_printf("RX descriptor reported error. Packet dropped\n");
}
}
/*alt_avalon_sgdma_construct_stream_to_mem_desc((alt_sgdma_descriptor*)(SGDMARxDescToSet),
(alt_sgdma_descriptor*)SGDMARxDescToSet->next,SGDMARxDescToSet->write_addr,0,0);
while(IORD_ALTERA_AVALON_SGDMA_STATUS(TSE_BASE)&ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
t2=alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, (alt_sgdma_descriptor *)SGDMARxDescToSet);*/
#ifdef DEBUGE
printf("Frame coming\n");
printf("Pointer to Desc: %p Pointer to next: %p RX buffer: %p\n",SGDMARx_OWEN,SGDMARx_OWEN->next,SGDMARx_OWEN->write_addr);
for(t2=0;t2<10;t2++){
printf("%x ",SGDMARx_OWEN->write_addr[t2]);
}
printf("\n");
#endif
eth_filter((eth_frame_t*)SGDMARx_OWEN->write_addr);
printf("\n");
return 0;
}
int tse_sgdmaRx_isr(void * context, alt_u32 irqnum){
alt_u32 t2=0;
alt_u32 *uncached_packet_payload;
t2=IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE);
alt_sgdma_descriptor *SGDMARx_OWEN = (alt_sgdma_descriptor *)IORD_ALTERA_AVALON_SGDMA_NEXT_DESC_POINTER(SGDMA_RX_BASE);
//SGDMARxDescToSet = (alt_sgdma_descriptor*)(SGDMARxDescToSet->next);
if (t2 & (ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK|
ALTERA_AVALON_SGDMA_STATUS_DESC_COMPLETED_MSK)){
p_counter++;
//alt_printf("Packet counter:%x\n",p_counter);
IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK);
t2=IORD_ALTERA_TSE_SGDMA_DESC_STATUS((alt_sgdma_descriptor *)SGDMARxDescToSet);
/*check status and handle packet*/
if((t2&(ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK |
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK |
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK |
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK ) ) == 0){
t2=IORD_16DIRECT((alt_sgdma_descriptor *)SGDMARxDescToSet->actual_bytes_transferred, 0)-2;
}
else{
alt_printf("RX descriptor reported error. Packet dropped\n");
}
}
/*alt_avalon_sgdma_construct_stream_to_mem_desc((alt_sgdma_descriptor*)(SGDMARxDescToSet),
(alt_sgdma_descriptor*)SGDMARxDescToSet->next,SGDMARxDescToSet->write_addr,0,0);
while(IORD_ALTERA_AVALON_SGDMA_STATUS(TSE_BASE)&ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
t2=alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, (alt_sgdma_descriptor *)SGDMARxDescToSet);*/
#ifdef DEBUGE
printf("Frame coming\n");
printf("Pointer to Desc: %p Pointer to next: %p RX buffer: %p\n",SGDMARx_OWEN,SGDMARx_OWEN->next,SGDMARx_OWEN->write_addr);
for(t2=0;t2<10;t2++){
printf("%x ",SGDMARx_OWEN->write_addr[t2]);
}
printf("\n");
#endif
eth_filter((eth_frame_t*)SGDMARx_OWEN->write_addr);
printf("\n");
return 0;
}
Как видно из обработчика прерывания, повторно запуска alt_avalon_sgdma_do_async_transfer нет. Но данные продолжают приниматься, но все время в один и тот же буфер с тем же дескриптором.