/** @file Copyright (c) 2016 - 2017, Socionext Inc. All rights reserved.
Copyright (c) 2017, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "ogma_internal.h" #include "ogma_basic_access.h" #include "ogma_desc_ring_access_internal.h" const ogma_uint32 ogma_desc_start_reg_addr_upper[OGMA_DESC_RING_ID_MAX+1] = { OGMA_REG_ADDR_NRM_TX_DESC_START_UP, OGMA_REG_ADDR_NRM_RX_DESC_START_UP, }; const ogma_uint32 ogma_desc_start_reg_addr_lower[OGMA_DESC_RING_ID_MAX+1] = { OGMA_REG_ADDR_NRM_TX_DESC_START_LW, OGMA_REG_ADDR_NRM_RX_DESC_START_LW, }; const ogma_uint32 desc_ring_irq_inten_reg_addr[OGMA_DESC_RING_ID_MAX + 1] = { OGMA_REG_ADDR_NRM_TX_INTEN, OGMA_REG_ADDR_NRM_RX_INTEN, }; const ogma_uint32 desc_ring_irq_inten_set_reg_addr[OGMA_DESC_RING_ID_MAX + 1] = { OGMA_REG_ADDR_NRM_TX_INTEN_SET, OGMA_REG_ADDR_NRM_RX_INTEN_SET, }; const ogma_uint32 desc_ring_irq_inten_clr_reg_addr[OGMA_DESC_RING_ID_MAX + 1] = { OGMA_REG_ADDR_NRM_TX_INTEN_CLR, OGMA_REG_ADDR_NRM_RX_INTEN_CLR, }; static const ogma_uint32 int_tmr_reg_addr[OGMA_DESC_RING_ID_MAX+1] = { OGMA_REG_ADDR_NRM_TX_TXINT_TMR, OGMA_REG_ADDR_NRM_RX_RXINT_TMR, }; static const ogma_uint32 rx_pkt_cnt_reg_addr[OGMA_DESC_RING_ID_MAX+1] = { 0, OGMA_REG_ADDR_NRM_RX_PKTCNT, }; static const ogma_uint32 tx_pkt_cnt_reg_addr[OGMA_DESC_RING_ID_MAX+1] = { OGMA_REG_ADDR_NRM_TX_PKTCNT, 0, }; static const ogma_uint32 int_pkt_cnt_reg_addr[OGMA_DESC_RING_ID_MAX+1] = { OGMA_REG_ADDR_NRM_TX_DONE_TXINT_PKTCNT, OGMA_REG_ADDR_NRM_RX_RXINT_PKTCNT, }; static const ogma_uint32 tx_done_pkt_cnt_reg_addr[OGMA_DESC_RING_ID_MAX+1] = { OGMA_REG_ADDR_NRM_TX_DONE_PKTCNT, 0, }; STATIC void ogma_set_tx_desc_entry ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 idx, const ogma_tx_pkt_ctrl_t *tx_pkt_ctrl_p, ogma_bool first_flag, ogma_bool last_flag, ogma_bool trs_flag, const ogma_frag_info_t *frag_info_p, pfdep_pkt_handle_t pkt_handle); STATIC void ogma_set_rx_desc_entry ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 idx, const ogma_frag_info_t *frag_info_p, pfdep_pkt_handle_t pkt_handle); STATIC void ogma_get_rx_desc_entry ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 idx, ogma_rx_pkt_info_t *rx_pkt_info_p, ogma_frag_info_t *frag_info_p, ogma_uint16 *len_p, pfdep_pkt_handle_t *pkt_handle_p); STATIC void ogma_clean_tx_desc_ring_sub ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ); STATIC void ogma_clean_rx_desc_ring_sub ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ); STATIC void ogma_inc_desc_head_idx ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 increment); STATIC void ogma_inc_desc_tail_idx ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 increment); STATIC ogma_uint16 ogma_get_tx_avail_num_sub ( ogma_ctrl_t *ctrl_p, const ogma_desc_ring_t *desc_ring_p ); STATIC ogma_uint16 ogma_get_tx_done_num_sub ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ); static __inline void ogma_desc_ring_cpy_to_mem( void *dst_p, void *src_p, ogma_uint32 len) { pfdep_memcpy(dst_p,src_p,len); } static __inline void ogma_desc_ring_cpy_from_mem( void *dst_p, void *src_p, ogma_uint32 len) { pfdep_memcpy(dst_p,src_p,len); } static __inline void ogma_desc_ring_memclr( void *dst_p, ogma_uint32 len) { pfdep_memset(dst_p,0,len); } /********************************************************************** * Function definitions **********************************************************************/ ogma_err_t ogma_alloc_desc_ring ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_id_t ring_id ) { ogma_err_t ogma_err = OGMA_ERR_OK; ogma_desc_ring_t *desc_ring_p = &ctrl_p->desc_ring[ring_id]; ogma_desc_ring_param_t *desc_ring_param_p = &ctrl_p->desc_ring[ring_id].param; pfdep_err_t pfdep_err; if ( ( ctrl_p->param.desc_ring_param[ring_id].valid_flag) && ( ( ctrl_p->param.desc_ring_param[ring_id].entry_num < OGMA_DESC_ENTRY_NUM_MIN) || ( ctrl_p->param.desc_ring_param[ring_id].entry_num > OGMA_DESC_ENTRY_NUM_MAX) ) ) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_alloc_desc_ring.\n" "Please set entry_num between %d and %d.\n", OGMA_DESC_ENTRY_NUM_MIN, OGMA_DESC_ENTRY_NUM_MAX); return OGMA_ERR_PARAM; } desc_ring_p->ring_id = ring_id; pfdep_memcpy( desc_ring_param_p, &ctrl_p->param.desc_ring_param[ring_id], sizeof( ogma_desc_ring_param_t) ); if ( !desc_ring_param_p->valid_flag) { desc_ring_p->desc_ring_phys_addr = ctrl_p->dummy_desc_entry_phys_addr; ogma_write_reg( ctrl_p, ogma_desc_start_reg_addr_upper[ring_id], (ogma_uint32)(desc_ring_p->desc_ring_phys_addr >> 32)); ogma_write_reg( ctrl_p, ogma_desc_start_reg_addr_lower[ring_id], (ogma_uint32)desc_ring_p->desc_ring_phys_addr); return OGMA_ERR_OK; } switch ( ring_id) { case OGMA_DESC_RING_ID_NRM_TX: desc_ring_p->tx_desc_ring_flag = OGMA_TRUE; desc_ring_p->desc_entry_len = sizeof( ogma_tx_desc_entry_t); break; case OGMA_DESC_RING_ID_NRM_RX: desc_ring_p->rx_desc_ring_flag = OGMA_TRUE; desc_ring_p->desc_entry_len = sizeof( ogma_rx_desc_entry_t); break; default: pfdep_assert(0); } if ( ( pfdep_err = pfdep_init_hard_lock ( &desc_ring_p->inten_reg_hard_lock) ) != PFDEP_ERR_OK) { pfdep_memset( desc_ring_param_p, 0, sizeof( ogma_desc_ring_param_t) ); pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_alloc_desc_ring.\n" "Failed to inten_reg_hard_lock's initialization.\n"); return OGMA_ERR_ALLOC; } if ( ( pfdep_err = pfdep_init_soft_lock ( &desc_ring_p->soft_lock) ) != PFDEP_ERR_OK) { pfdep_uninit_hard_lock ( &desc_ring_p->inten_reg_hard_lock); pfdep_memset( desc_ring_param_p, 0, sizeof( ogma_desc_ring_param_t) ); pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_alloc_desc_ring.\n" "Failed to soft_lock's initialization.\n"); return OGMA_ERR_ALLOC; } if ( ( pfdep_err = pfdep_dma_malloc ( ( pfdep_dev_handle_t) ctrl_p->dev_handle, ( pfdep_uint32) desc_ring_p->desc_entry_len * desc_ring_param_p->entry_num, ( void **) &desc_ring_p->desc_ring_cpu_addr, ( pfdep_phys_addr_t *) &desc_ring_p->desc_ring_phys_addr) ) != PFDEP_ERR_OK) { ogma_err = OGMA_ERR_ALLOC; pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_alloc_desc_ring.\n" "Failed to desc_ring entry memory allocation.\n"); goto err; } ogma_desc_ring_memclr( desc_ring_p->desc_ring_cpu_addr, ( ogma_uint32)desc_ring_p->desc_entry_len * desc_ring_param_p->entry_num); ogma_write_reg( ctrl_p, ogma_desc_start_reg_addr_upper[ring_id], (ogma_uint32)(desc_ring_p->desc_ring_phys_addr >> 32)); ogma_write_reg( ctrl_p, ogma_desc_start_reg_addr_lower[ring_id], (ogma_uint32)desc_ring_p->desc_ring_phys_addr); if ( ( desc_ring_p->frag_info_p = pfdep_malloc( sizeof( ogma_frag_info_t) * desc_ring_param_p->entry_num) ) == NULL) { ogma_err = OGMA_ERR_ALLOC; pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_alloc_desc_ring.\n" "Failed to fragment infomation memory allocation.\n"); goto err; } pfdep_memset( desc_ring_p->frag_info_p, 0, sizeof( ogma_frag_info_t) * desc_ring_param_p->entry_num); if ( ( desc_ring_p->priv_data_p = pfdep_malloc( sizeof( ogma_desc_entry_priv_t) * desc_ring_param_p->entry_num) ) == NULL) { ogma_err = OGMA_ERR_ALLOC; pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_alloc_desc_ring.\n" "Failed to private data memory allocation.\n"); goto err; } pfdep_memset( desc_ring_p->priv_data_p, 0, sizeof( ogma_desc_entry_priv_t) * desc_ring_param_p->entry_num); return OGMA_ERR_OK; err: ogma_free_desc_ring( ctrl_p, desc_ring_p); return ogma_err; } void ogma_free_desc_ring ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ) { if ( !desc_ring_p->param.valid_flag) { return ; } if ( ogma_is_pkt_desc_ring ( desc_ring_p) ) { if ( ( desc_ring_p->desc_ring_cpu_addr != NULL) && ( desc_ring_p->frag_info_p != NULL) && ( desc_ring_p->priv_data_p != NULL) ) { ogma_uninit_pkt_desc_ring( ctrl_p, desc_ring_p); } } if ( desc_ring_p->desc_ring_cpu_addr != NULL) { pfdep_dma_free( ctrl_p->dev_handle, ( ogma_uint32)desc_ring_p->desc_entry_len * desc_ring_p->param.entry_num, desc_ring_p->desc_ring_cpu_addr, desc_ring_p->desc_ring_phys_addr); } if ( desc_ring_p->frag_info_p != NULL) { pfdep_free(desc_ring_p->frag_info_p); } if ( desc_ring_p->priv_data_p != NULL) { pfdep_free( desc_ring_p->priv_data_p); } pfdep_uninit_hard_lock ( &desc_ring_p->inten_reg_hard_lock); pfdep_uninit_soft_lock ( &desc_ring_p->soft_lock); pfdep_memset( desc_ring_p, 0, sizeof( ogma_desc_ring_t) ); } ogma_err_t ogma_setup_rx_desc_ring ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ) { ogma_uint16 idx; ogma_frag_info_t frag_info= {0,0,0}; pfdep_err_t pfdep_err; pfdep_pkt_handle_t tmp_pkt_handle; frag_info.len = ctrl_p->rx_pkt_buf_len; for ( idx = 0; idx < desc_ring_p->param.entry_num; idx++) { if ( ( pfdep_err = pfdep_alloc_pkt_buf ( ( pfdep_dev_handle_t)ctrl_p->dev_handle, ( ogma_uint16)frag_info.len, ( void **)&frag_info.addr, ( pfdep_phys_addr_t *)&frag_info.phys_addr, ( pfdep_pkt_handle_t *)&tmp_pkt_handle) ) != PFDEP_ERR_OK) { ogma_uninit_pkt_desc_ring( ctrl_p, desc_ring_p); pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_setup_rx_desc_ring.\n" "Failed to rx packet memory allocation.\n"); return OGMA_ERR_ALLOC; } ogma_set_rx_desc_entry( ctrl_p, desc_ring_p, idx, &frag_info, tmp_pkt_handle); } return OGMA_ERR_OK; } void ogma_uninit_pkt_desc_ring ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ) { ogma_uint16 idx; ogma_uint32 tmp; ogma_bool last_flag; for ( idx = 0; idx < desc_ring_p->param.entry_num; idx++) { if ( desc_ring_p->frag_info_p[idx].addr == NULL ) { continue; } tmp = ogma_get_desc_ring_attr(desc_ring_p, idx); last_flag = ( ( ( tmp >> 8) & 0x1) != 0); pfdep_free_pkt_buf ( ctrl_p->dev_handle, desc_ring_p->frag_info_p[idx].len, desc_ring_p->frag_info_p[idx].addr, desc_ring_p->frag_info_p[idx].phys_addr, last_flag, desc_ring_p->priv_data_p[idx].pkt_handle); } /* clear frag_info_p */ pfdep_memset( desc_ring_p->frag_info_p, 0, sizeof( ogma_frag_info_t) * desc_ring_p->param.entry_num); /* clear pkt_handle_p */ pfdep_memset( desc_ring_p->priv_data_p, 0, sizeof( ogma_desc_entry_priv_t) * desc_ring_p->param.entry_num); /* clear desc ring entry*/ ogma_desc_ring_memclr ( desc_ring_p->desc_ring_cpu_addr, ( ogma_uint32)desc_ring_p->desc_entry_len * desc_ring_p->param.entry_num); } STATIC void ogma_set_tx_desc_entry ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 idx, const ogma_tx_pkt_ctrl_t *tx_pkt_ctrl_p, ogma_bool first_flag, ogma_bool last_flag, ogma_bool trs_flag, const ogma_frag_info_t *frag_info_p, pfdep_pkt_handle_t pkt_handle ) { ogma_tx_desc_entry_t tx_desc_entry; ogma_uint32 attr, i, *debug_desc_entry_p; ogma_check_desc_own_sanity(ctrl_p, desc_ring_p, idx, 0); pfdep_memset( &tx_desc_entry, 0, sizeof( ogma_tx_desc_entry_t) ); attr = ( 1UL << OGMA_TX_PKT_DESC_RING_OWN_FIELD) | ( desc_ring_p->ring_id << OGMA_TX_PKT_DESC_RING_DRID_FIELD) | ( tx_pkt_ctrl_p->pass_through_flag << OGMA_TX_PKT_DESC_RING_PT_FIELD) | ( tx_pkt_ctrl_p->target_desc_ring_id << OGMA_TX_PKT_DESC_RING_TDRID_FIELD) | ( first_flag << OGMA_TX_PKT_DESC_RING_FS_FIELD) | ( last_flag << OGMA_TX_PKT_DESC_RING_LS_FIELD) | ( tx_pkt_ctrl_p->cksum_offload_flag << OGMA_TX_PKT_DESC_RING_CO_FIELD) | ( tx_pkt_ctrl_p->tcp_seg_offload_flag << OGMA_TX_PKT_DESC_RING_SO_FIELD) | ( trs_flag << OGMA_TX_PKT_DESC_RING_TRS_FIELD); if ( idx == ( desc_ring_p->param.entry_num - 1) ) { attr |= ( 0x1U << OGMA_TX_PKT_DESC_RING_LD_FIELD); /* LD = 1 */ } tx_desc_entry.attr = attr; tx_desc_entry.data_buf_addr_upper = (ogma_uint32)(frag_info_p->phys_addr >> 32); tx_desc_entry.data_buf_addr_lower = (ogma_uint32)frag_info_p->phys_addr; tx_desc_entry.buf_len_info = ( tx_pkt_ctrl_p->tcp_seg_len << 16) | frag_info_p->len; ogma_desc_ring_cpy_to_mem( ( (void *) ( ( pfdep_cpu_addr_t)desc_ring_p->desc_ring_cpu_addr + desc_ring_p->desc_entry_len * idx) ), ( void *)&tx_desc_entry, desc_ring_p->desc_entry_len); debug_desc_entry_p = ( ogma_uint32 *)&tx_desc_entry; for ( i = 0; i < ( sizeof( ogma_tx_desc_entry_t) >> 2); i++) { pfdep_print( PFDEP_DEBUG_LEVEL_DEBUG_MORE_DETAILED, "%08x\n", debug_desc_entry_p[i]); } desc_ring_p->frag_info_p[idx].phys_addr = frag_info_p->phys_addr; desc_ring_p->frag_info_p[idx].addr = frag_info_p->addr; desc_ring_p->frag_info_p[idx].len = frag_info_p->len; desc_ring_p->priv_data_p[idx].pkt_handle = pkt_handle; } STATIC void ogma_set_rx_desc_entry ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 idx, const ogma_frag_info_t *frag_info_p, pfdep_pkt_handle_t pkt_handle ) { ogma_rx_desc_entry_t rx_desc_entry; ogma_check_desc_own_sanity(ctrl_p, desc_ring_p, idx, 0); pfdep_memset( &rx_desc_entry, 0, sizeof ( ogma_rx_desc_entry_t) ); rx_desc_entry.attr = ( 1UL << OGMA_RX_PKT_DESC_RING_OWN_FIELD) | ( 1UL << OGMA_RX_PKT_DESC_RING_FS_FIELD) | ( 1UL << OGMA_RX_PKT_DESC_RING_LS_FIELD) ; /* OWN = FS = LS = 1 */ rx_desc_entry.data_buf_addr_upper = (ogma_uint32)(frag_info_p->phys_addr >> 32); rx_desc_entry.data_buf_addr_lower = (ogma_uint32)frag_info_p->phys_addr; rx_desc_entry.buf_len_info = frag_info_p->len; if ( idx == ( desc_ring_p->param.entry_num - 1) ) { rx_desc_entry.attr |= ( 0x1U << OGMA_RX_PKT_DESC_RING_LD_FIELD); /* LD = 1 */ } ogma_desc_ring_cpy_to_mem( ( ( void *) ( ( pfdep_cpu_addr_t)desc_ring_p->desc_ring_cpu_addr + desc_ring_p->desc_entry_len * idx + 4) ), ( void *) ( ( pfdep_cpu_addr_t)&rx_desc_entry + 4), ( ogma_uint32)( desc_ring_p->desc_entry_len - 4U) ); pfdep_write_mem_barrier(); ogma_desc_ring_cpy_to_mem( ( ( void *) ( ( pfdep_cpu_addr_t)desc_ring_p->desc_ring_cpu_addr + desc_ring_p->desc_entry_len * idx) ), ( void *)&rx_desc_entry, 4); desc_ring_p->frag_info_p[idx].phys_addr = frag_info_p->phys_addr; desc_ring_p->frag_info_p[idx].addr = frag_info_p->addr; desc_ring_p->frag_info_p[idx].len = frag_info_p->len; desc_ring_p->priv_data_p[idx].pkt_handle = pkt_handle; } STATIC void ogma_get_rx_desc_entry ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 idx, ogma_rx_pkt_info_t *rx_pkt_info_p, ogma_frag_info_t *frag_info_p, ogma_uint16 *len_p, pfdep_pkt_handle_t *pkt_handle_p) { ogma_uint32 *debug_desc_entry_p; ogma_rx_desc_entry_t rx_desc_entry; ogma_check_desc_own_sanity( ctrl_p, desc_ring_p, idx, 0); pfdep_memset( &rx_desc_entry, 0, sizeof( ogma_rx_desc_entry_t) ); pfdep_memset( rx_pkt_info_p, 0, sizeof( ogma_rx_pkt_info_t) ); ogma_desc_ring_cpy_from_mem( &rx_desc_entry, (void *) ( ( pfdep_cpu_addr_t)desc_ring_p->desc_ring_cpu_addr + desc_ring_p->desc_entry_len * idx), desc_ring_p->desc_entry_len); debug_desc_entry_p = (ogma_uint32 *)&rx_desc_entry; pfdep_print( PFDEP_DEBUG_LEVEL_DEBUG_MORE_DETAILED, "%08x\n", *debug_desc_entry_p); *len_p = rx_desc_entry.buf_len_info >> 16; rx_pkt_info_p->fragmented_flag = ( rx_desc_entry.attr >> OGMA_RX_PKT_DESC_RING_FR_FIELD) & 0x1; /* FR*/ rx_pkt_info_p->err_flag = ( rx_desc_entry.attr >> OGMA_RX_PKT_DESC_RING_ER_FIELD) & 0x1; /* ER */ rx_pkt_info_p->rx_cksum_result = ( rx_desc_entry.attr >> OGMA_RX_PKT_DESC_RING_CO_FIELD) & 0x3; /* CO */ rx_pkt_info_p->err_code = ( rx_desc_entry.attr >> OGMA_RX_PKT_DESC_RING_ERROR_CODE_FIELD) & OGMA_RX_PKT_DESC_RING_ERROR_CODE_FIELD_MASK; /* Error Code */ pfdep_memcpy( frag_info_p, &desc_ring_p->frag_info_p[idx], sizeof(ogma_frag_info_t) ); *pkt_handle_p = desc_ring_p->priv_data_p[idx].pkt_handle; } #ifdef OGMA_CONFIG_REC_STAT STATIC __inline ogma_uint16 ogma_calc_busy_entry_num ( ogma_uint16 head_idx, ogma_uint16 tail_idx, ogma_uint16 entry_num, ogma_bool full_flag ) { ogma_int16 busy_entry_num; if (full_flag) { busy_entry_num = entry_num; } else if (head_idx >= tail_idx) { busy_entry_num = head_idx - tail_idx; } else { busy_entry_num = entry_num + head_idx - tail_idx; } return busy_entry_num; } #endif /* OGMA_CONFIG_REC_STAT */ STATIC void ogma_clean_tx_desc_ring_sub ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ) { ogma_uint32 tmp; ogma_get_tx_done_num_sub( ctrl_p, desc_ring_p); while( ( (desc_ring_p->tail_idx != desc_ring_p->head_idx) || desc_ring_p->full_flag) && ( desc_ring_p->tx_done_num != 0) ) { tmp = ogma_get_desc_ring_attr(desc_ring_p, desc_ring_p->tail_idx); pfdep_free_pkt_buf ( ctrl_p->dev_handle, desc_ring_p->frag_info_p[desc_ring_p->tail_idx].len, desc_ring_p->frag_info_p[desc_ring_p->tail_idx].addr, desc_ring_p->frag_info_p[desc_ring_p->tail_idx].phys_addr, ( ( ( tmp >> OGMA_TX_PKT_DESC_RING_LS_FIELD) & 0x1) != 0), desc_ring_p->priv_data_p[desc_ring_p->tail_idx].pkt_handle); pfdep_memset( &desc_ring_p->frag_info_p[desc_ring_p->tail_idx], 0, sizeof( ogma_frag_info_t) ); ogma_inc_desc_tail_idx( ctrl_p, desc_ring_p, 1); if ( ( tmp & ( 1UL << OGMA_TX_PKT_DESC_RING_LS_FIELD) ) != 0) { pfdep_assert( desc_ring_p->tx_done_num != 0); desc_ring_p->tx_done_num--; } } } STATIC void ogma_clean_rx_desc_ring_sub ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ) { while( desc_ring_p->full_flag || ( desc_ring_p->tail_idx != desc_ring_p->head_idx) ) { ogma_set_rx_desc_entry( ctrl_p, desc_ring_p, desc_ring_p->tail_idx, &desc_ring_p->frag_info_p[desc_ring_p->tail_idx], desc_ring_p->priv_data_p[desc_ring_p->tail_idx].pkt_handle); --desc_ring_p->rx_num; ogma_inc_desc_tail_idx( ctrl_p, desc_ring_p, 1); } pfdep_assert( desc_ring_p->rx_num == 0);/* error check*/ } STATIC void ogma_inc_desc_head_idx ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 increment) { ogma_uint32 sum; if ( ( desc_ring_p->tail_idx > desc_ring_p->head_idx) || desc_ring_p->full_flag) { pfdep_assert( increment <= ( desc_ring_p->tail_idx - desc_ring_p->head_idx)); } else { pfdep_assert( increment <= ( desc_ring_p->param.entry_num + desc_ring_p->tail_idx - desc_ring_p->head_idx) ); } sum = (ogma_uint32) desc_ring_p->head_idx + increment; if ( sum >= desc_ring_p->param.entry_num) { sum -= desc_ring_p->param.entry_num; } desc_ring_p->head_idx = ( ogma_uint16)sum; if ( desc_ring_p->head_idx == desc_ring_p->tail_idx) { desc_ring_p->full_flag = OGMA_TRUE; } } STATIC void ogma_inc_desc_tail_idx ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p, ogma_uint16 increment) { ogma_uint32 sum; if ( ( desc_ring_p->head_idx >= desc_ring_p->tail_idx) && ( !desc_ring_p->full_flag) ) { pfdep_assert( increment <= ( desc_ring_p->head_idx - desc_ring_p->tail_idx) ); } else { pfdep_assert( increment <= ( desc_ring_p->param.entry_num + desc_ring_p->head_idx - desc_ring_p->tail_idx) ); } sum = (ogma_uint32) desc_ring_p->tail_idx + increment; if ( sum >= desc_ring_p->param.entry_num) { sum -= desc_ring_p->param.entry_num; } desc_ring_p->tail_idx = ( ogma_uint16)sum; desc_ring_p->full_flag = OGMA_FALSE; } STATIC ogma_uint16 ogma_get_tx_avail_num_sub ( ogma_ctrl_t *ctrl_p, const ogma_desc_ring_t *desc_ring_p ) { ogma_uint16 tx_avail_num; if ( desc_ring_p->full_flag) { tx_avail_num = 0; } else if ( desc_ring_p->tail_idx > desc_ring_p->head_idx) { tx_avail_num = desc_ring_p->tail_idx - desc_ring_p->head_idx; } else { tx_avail_num = desc_ring_p->param.entry_num + desc_ring_p->tail_idx - desc_ring_p->head_idx; } return tx_avail_num; } STATIC ogma_uint16 ogma_get_tx_done_num_sub ( ogma_ctrl_t *ctrl_p, ogma_desc_ring_t *desc_ring_p ) { ogma_uint32 value; value = ogma_read_reg ( ctrl_p, tx_done_pkt_cnt_reg_addr[desc_ring_p->ring_id] ); desc_ring_p->tx_done_num += value; return desc_ring_p->tx_done_num; } ogma_err_t ogma_start_desc_ring ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id ) { ogma_err_t ogma_err = OGMA_ERR_OK; ogma_uint32 value; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p; pfdep_soft_lock_ctx_t soft_lock_ctx; pfdep_err_t pfdep_err; if ( ctrl_p == NULL) { return OGMA_ERR_PARAM; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } desc_ring_p = &ctrl_p->desc_ring[ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { return OGMA_ERR_INTERRUPT; } if ( desc_ring_p->running_flag) { pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return OGMA_ERR_BUSY; } if ( desc_ring_p->rx_desc_ring_flag) { ogma_write_reg ( ctrl_p, desc_ring_irq_inten_set_reg_addr[ring_id], OGMA_CH_IRQ_REG_RCV); ogma_write_reg ( ctrl_p, int_pkt_cnt_reg_addr[ring_id], 1); } if ( desc_ring_p->tx_desc_ring_flag) { value = OGMA_CH_IRQ_REG_EMPTY; ogma_write_reg ( ctrl_p, desc_ring_irq_inten_set_reg_addr[ring_id], value); ogma_write_reg ( ctrl_p, int_pkt_cnt_reg_addr[ring_id], 1); } desc_ring_p->running_flag = OGMA_TRUE; pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return ogma_err; } ogma_err_t ogma_stop_desc_ring ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id ) { ogma_uint32 value; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p; pfdep_err_t pfdep_err; pfdep_soft_lock_ctx_t soft_lock_ctx; if ( ( ctrl_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { return OGMA_ERR_PARAM; } if ( !ogma_is_pkt_desc_ring( &ctrl_p->desc_ring[ring_id] ) ) { return OGMA_ERR_PARAM; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } desc_ring_p = &ctrl_p->desc_ring[ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { return OGMA_ERR_INTERRUPT; } if ( !desc_ring_p->running_flag) { pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return OGMA_ERR_INVALID; } value = ( OGMA_CH_IRQ_REG_RCV | OGMA_CH_IRQ_REG_EMPTY | OGMA_CH_IRQ_REG_SND); ogma_write_reg ( ctrl_p, desc_ring_irq_inten_clr_reg_addr[ring_id], value); desc_ring_p->running_flag = OGMA_FALSE; pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return OGMA_ERR_OK; } ogma_uint16 ogma_get_rx_num ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id ) { ogma_uint32 result; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p = NULL; ogma_desc_ring_id_t tmp_ring_id; pfdep_soft_lock_ctx_t soft_lock_ctx; pfdep_err_t pfdep_err; if ( ( ctrl_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_rx_num.\n" "Please set valid argument.\n"); return 0; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_rx_num.\n" "Please set valid argument.\n"); return 0; } tmp_ring_id = ring_id; if (! ctrl_p->desc_ring[tmp_ring_id].rx_desc_ring_flag) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_rx_num.\n" "Please select rx packet desc ring or bulk desc ring.\n"); return 0; } desc_ring_p = &ctrl_p->desc_ring[tmp_ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_rx_num.\n" "Failed to get soft lock.\n"); return 0; } result = ogma_read_reg( ctrl_p, rx_pkt_cnt_reg_addr[tmp_ring_id]); desc_ring_p->rx_num += result; if ( desc_ring_p->rx_desc_ring_flag && ( result != 0) ) { ogma_inc_desc_head_idx( ctrl_p, desc_ring_p, ( ogma_uint16)result); } pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return desc_ring_p->rx_num; } ogma_uint16 ogma_get_tx_avail_num ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id ) { ogma_uint16 result; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_id_t tmp_ring_id; ogma_desc_ring_t *desc_ring_p = NULL; pfdep_soft_lock_ctx_t soft_lock_ctx; pfdep_err_t pfdep_err; if ( ( ctrl_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) || ( !ctrl_p->desc_ring[ring_id].param.valid_flag) ) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_tx_avail_num.\n" "Please select valid argument.\n"); return 0; } tmp_ring_id = ring_id; if (! ctrl_p->desc_ring[tmp_ring_id].tx_desc_ring_flag) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_tx_avail_num.\n" "Please select tx packet desc ring or bulk desc ring.\n"); return 0; } desc_ring_p = &ctrl_p->desc_ring[tmp_ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_tx_avail_num.\n" "Failed to get soft lock.\n"); return 0; } if ( !desc_ring_p->running_flag) { pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_get_tx_avail_num.\n" "Please select running desc ring.\n"); return 0; } result = ogma_get_tx_avail_num_sub( ctrl_p, desc_ring_p); pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return result; } ogma_err_t ogma_clean_tx_desc_ring ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id ) { ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p; pfdep_err_t pfdep_err; pfdep_soft_lock_ctx_t soft_lock_ctx; if ( ( ctrl_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { return OGMA_ERR_PARAM; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } if ( !ctrl_p->desc_ring[ring_id].tx_desc_ring_flag) { return OGMA_ERR_PARAM; } desc_ring_p = &ctrl_p->desc_ring[ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { return OGMA_ERR_INTERRUPT; } ogma_clean_tx_desc_ring_sub(ctrl_p, desc_ring_p); pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return OGMA_ERR_OK; } ogma_err_t ogma_clean_rx_desc_ring ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id ) { ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p; pfdep_err_t pfdep_err; pfdep_soft_lock_ctx_t soft_lock_ctx; if ( ( ctrl_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { return OGMA_ERR_PARAM; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } if ( !ctrl_p->desc_ring[ring_id].rx_desc_ring_flag) { return OGMA_ERR_PARAM; } desc_ring_p = &ctrl_p->desc_ring[ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { return OGMA_ERR_INTERRUPT; } ogma_clean_rx_desc_ring_sub(ctrl_p, desc_ring_p); pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return OGMA_ERR_OK; } ogma_err_t ogma_set_tx_pkt_data ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id, const ogma_tx_pkt_ctrl_t *tx_pkt_ctrl_p, ogma_uint8 scat_num, const ogma_frag_info_t *scat_info_p, pfdep_pkt_handle_t pkt_handle ) { ogma_uint i; ogma_uint16 tx_avail_num; ogma_uint32 sum_len = 0; ogma_err_t ogma_err = OGMA_ERR_OK; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p; pfdep_err_t pfdep_err; pfdep_soft_lock_ctx_t soft_lock_ctx; pfdep_print( PFDEP_DEBUG_LEVEL_DEBUG, "%s call.\n", __func__); if ( ( ctrl_p == NULL) || ( tx_pkt_ctrl_p == NULL) || ( scat_info_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { return OGMA_ERR_PARAM; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } if ( !ctrl_p->desc_ring[ring_id].tx_desc_ring_flag) { return OGMA_ERR_PARAM; } { if ( !ctrl_p->param.use_gmac_flag || ( tx_pkt_ctrl_p->target_desc_ring_id != OGMA_DESC_RING_ID_GMAC) ) { return OGMA_ERR_DATA; } } if ( tx_pkt_ctrl_p->tcp_seg_offload_flag && ( !tx_pkt_ctrl_p->cksum_offload_flag) ) { return OGMA_ERR_DATA; } if ( tx_pkt_ctrl_p->tcp_seg_offload_flag) { if ( tx_pkt_ctrl_p->tcp_seg_len == 0) { return OGMA_ERR_DATA; } if ( ctrl_p->param.use_jumbo_pkt_flag) { if (tx_pkt_ctrl_p->tcp_seg_len > OGMA_TCP_JUMBO_SEG_LEN_MAX) { return OGMA_ERR_DATA; } } else { if (tx_pkt_ctrl_p->tcp_seg_len > OGMA_TCP_SEG_LEN_MAX) { return OGMA_ERR_DATA; } } } else { if ( tx_pkt_ctrl_p->tcp_seg_len != 0) { return OGMA_ERR_DATA; } } if ( scat_num == 0) { return OGMA_ERR_RANGE; } for ( i = 0; i < scat_num; i++) { if ( ( scat_info_p[i].len == 0) || ( scat_info_p[i].len > 0xffffU) ) { pfdep_print( PFDEP_DEBUG_LEVEL_FATAL, "An error occurred at ogma_set_tx_pkt_data.\n" "Pleas check scat_info_p[%u].len.\n", i); return OGMA_ERR_DATA; } sum_len += scat_info_p[i].len; } if ( !tx_pkt_ctrl_p->tcp_seg_offload_flag) { if ( ctrl_p->param.use_jumbo_pkt_flag) { if ( sum_len > OGMA_MAX_TX_JUMBO_PKT_LEN) { return OGMA_ERR_DATA; } } else { if ( sum_len > OGMA_MAX_TX_PKT_LEN) { return OGMA_ERR_DATA; } } } desc_ring_p = &ctrl_p->desc_ring[ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { return OGMA_ERR_INTERRUPT; } if ( !desc_ring_p->running_flag) { ogma_err = OGMA_ERR_NOTAVAIL; goto end; } tx_avail_num = ogma_get_tx_avail_num_sub( ctrl_p, desc_ring_p); if ( scat_num > tx_avail_num ) { ogma_err = OGMA_ERR_BUSY; goto end; } for ( i = 0; i < scat_num; i++) { ogma_set_tx_desc_entry( ctrl_p, desc_ring_p, desc_ring_p->head_idx, tx_pkt_ctrl_p, ( i == 0), ( i == ( scat_num - 1U) ), OGMA_TRUE, &scat_info_p[i], pkt_handle); ogma_inc_desc_head_idx( ctrl_p, desc_ring_p, 1); } pfdep_write_mem_barrier(); ogma_write_reg( ctrl_p, tx_pkt_cnt_reg_addr[ring_id], (ogma_uint32)1); end: pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return ogma_err; } ogma_err_t ogma_get_rx_pkt_data ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id, ogma_rx_pkt_info_t *rx_pkt_info_p, ogma_frag_info_t *frag_info_p, ogma_uint16 *len_p, pfdep_pkt_handle_t *pkt_handle_p ) { ogma_err_t ogma_err = OGMA_ERR_OK; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; ogma_desc_ring_t *desc_ring_p; ogma_frag_info_t tmp_frag_info; pfdep_err_t pfdep_err; pfdep_pkt_handle_t tmp_pkt_handle; pfdep_soft_lock_ctx_t soft_lock_ctx; pfdep_print( PFDEP_DEBUG_LEVEL_DEBUG, "%s call.\n", __func__); if ( ( ctrl_p == NULL) || ( rx_pkt_info_p == NULL) || ( frag_info_p == NULL) || ( len_p == NULL) || ( pkt_handle_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { return OGMA_ERR_PARAM; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } if ( !ctrl_p->desc_ring[ring_id].rx_desc_ring_flag) { return OGMA_ERR_PARAM; } desc_ring_p = &ctrl_p->desc_ring[ring_id]; if ( ( pfdep_err = pfdep_acquire_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx ) ) != PFDEP_ERR_OK) { return OGMA_ERR_INTERRUPT; } if ( desc_ring_p->rx_num == 0 ) { ogma_err = OGMA_ERR_INVALID; goto end; } tmp_frag_info.len = ctrl_p->rx_pkt_buf_len; pfdep_read_mem_barrier(); if ( ( pfdep_err = pfdep_alloc_pkt_buf ( ctrl_p->dev_handle, tmp_frag_info.len, &tmp_frag_info.addr, &tmp_frag_info.phys_addr, &tmp_pkt_handle) ) != PFDEP_ERR_OK) { ogma_set_rx_desc_entry( ctrl_p, desc_ring_p, desc_ring_p->tail_idx, &desc_ring_p->frag_info_p[desc_ring_p->tail_idx], desc_ring_p->priv_data_p[desc_ring_p->tail_idx].pkt_handle); ogma_err = OGMA_ERR_ALLOC; } else { ogma_get_rx_desc_entry( ctrl_p, desc_ring_p, desc_ring_p->tail_idx, rx_pkt_info_p, frag_info_p, len_p, pkt_handle_p); ogma_set_rx_desc_entry( ctrl_p, desc_ring_p, desc_ring_p->tail_idx, &tmp_frag_info, tmp_pkt_handle); } ogma_inc_desc_tail_idx( ctrl_p, desc_ring_p, 1); --desc_ring_p->rx_num; end: pfdep_release_soft_lock( &desc_ring_p->soft_lock, &soft_lock_ctx); return ogma_err; } ogma_err_t ogma_set_irq_coalesce_param ( ogma_handle_t ogma_handle, ogma_desc_ring_id_t ring_id, ogma_uint16 int_pktcnt, ogma_bool int_tmr_unit_ms_flag, ogma_uint16 int_tmr_cnt ) { ogma_err_t ogma_err = OGMA_ERR_OK; ogma_ctrl_t *ctrl_p = (ogma_ctrl_t *)ogma_handle; if ( ( ctrl_p == NULL) || ( ring_id > OGMA_DESC_RING_ID_MAX) ) { return OGMA_ERR_PARAM; } if ( int_pktcnt > OGMA_INT_PKTCNT_MAX) { return OGMA_ERR_RANGE; } if ( !ctrl_p->desc_ring[ring_id].param.valid_flag) { return OGMA_ERR_NOTAVAIL; } if ( !ogma_is_pkt_desc_ring( &ctrl_p->desc_ring[ring_id]) ) { return OGMA_ERR_PARAM; } ogma_write_reg( ctrl_p, int_pkt_cnt_reg_addr[ring_id], int_pktcnt); ogma_write_reg( ctrl_p, int_tmr_reg_addr[ring_id], ( ( ( ( ogma_uint32)int_tmr_unit_ms_flag) << 31) | int_tmr_cnt) ); return ogma_err; }