summaryrefslogtreecommitdiffstats
path: root/c/src/libchip/network/dwmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/libchip/network/dwmac.c')
-rw-r--r--c/src/libchip/network/dwmac.c451
1 files changed, 236 insertions, 215 deletions
diff --git a/c/src/libchip/network/dwmac.c b/c/src/libchip/network/dwmac.c
index 10f6b75b3a..eda1433300 100644
--- a/c/src/libchip/network/dwmac.c
+++ b/c/src/libchip/network/dwmac.c
@@ -262,9 +262,14 @@ static inline void dwmac_enable_irq_rx( dwmac_common_context *self )
dwmac_core_enable_dma_irq_rx( self );
}
-static inline void dwmac_enable_irq_tx( dwmac_common_context *self )
+static inline void dwmac_enable_irq_tx_default( dwmac_common_context *self )
{
- dwmac_core_enable_dma_irq_tx( self );
+ dwmac_core_enable_dma_irq_tx_default( self );
+}
+
+static inline void dwmac_enable_irq_tx_transmitted( dwmac_common_context *self )
+{
+ dwmac_core_enable_dma_irq_tx_transmitted( self );
}
static inline void dwmac_disable_irq_rx( dwmac_common_context *self )
@@ -272,16 +277,20 @@ static inline void dwmac_disable_irq_rx( dwmac_common_context *self )
dwmac_core_disable_dma_irq_rx( self );
}
-static inline void dwmac_diable_irq_tx( dwmac_common_context *self )
+static inline void dwmac_disable_irq_tx_all( dwmac_common_context *self )
+{
+ dwmac_core_disable_dma_irq_tx_all( self );
+}
+
+static inline void dwmac_disable_irq_tx_transmitted ( dwmac_common_context *self )
{
- dwmac_core_disable_dma_irq_tx( self );
+ dwmac_core_disable_dma_irq_tx_transmitted( self );
}
static void dwmac_control_request_complete( const dwmac_common_context *self )
{
rtems_status_code sc = rtems_event_transient_send( self->task_id_control );
-
assert( sc == RTEMS_SUCCESSFUL );
}
@@ -1342,263 +1351,275 @@ static void dwmac_task_tx( void *arg )
);
assert( sc == RTEMS_SUCCESSFUL );
- /* Handle a status change of the ethernet PHY */
- if ( ( events & DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE ) != 0 ) {
- dwmac_common_phy_status_counts *counts =
- &self->stats.phy_status_counts;
- dwmac_phy_event phy_events = 0;
- int eno;
-
- /* Get tripped PHY events */
- eno = CALLBACK->phy_events_get(
- self->arg,
- &phy_events
- );
-
- if ( eno == 0 ) {
- /* Clear the PHY events */
- eno = CALLBACK->phy_event_clear( self->arg );
- }
-
- if ( eno == 0 ) {
- if ( ( phy_events & PHY_EVENT_LINK_DOWN ) != 0 ) {
- ++counts->link_down;
- }
-
- if ( ( phy_events & PHY_EVENT_LINK_UP ) != 0 ) {
- ++counts->link_up;
+ while( events != 0 ) {
+ /* Handle a status change of the ethernet PHY */
+ if ( ( events & DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE ) != 0 ) {
+ events &= ~DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE;
+ dwmac_common_phy_status_counts *counts =
+ &self->stats.phy_status_counts;
+ dwmac_phy_event phy_events = 0;
+ int eno;
+
+ /* Get tripped PHY events */
+ eno = CALLBACK->phy_events_get(
+ self->arg,
+ &phy_events
+ );
- /* A link up events means that we have a new connection.
- * Thus the autonegotiation paremeters must get updated */
- (void) dwmac_update_autonegotiation_params( self );
+ if ( eno == 0 ) {
+ /* Clear the PHY events */
+ eno = CALLBACK->phy_event_clear( self->arg );
}
- }
- assert( eno == 0 );
- }
+ if ( eno == 0 ) {
+ if ( ( phy_events & PHY_EVENT_LINK_DOWN ) != 0 ) {
+ ++counts->link_down;
+ }
- /* Stop the task */
- if ( ( events & DWMAC_COMMON_EVENT_TASK_STOP ) != 0 ) {
- dwmac_core_dma_stop_tx( self );
- dwmac_diable_irq_tx( self );
+ if ( ( phy_events & PHY_EVENT_LINK_UP ) != 0 ) {
+ ++counts->link_up;
- /* Release all tx mbufs at the risk of data loss */
- ( DESC_OPS->release_tx_bufs )( self );
+ /* A link up events means that we have a new connection.
+ * Thus the autonegotiation paremeters must get updated */
+ (void) dwmac_update_autonegotiation_params( self );
+ }
+ }
- dwmac_control_request_complete( self );
+ assert( eno == 0 );
+ }
- /* Return to events reception without re-enabling the interrupts
- * The task needs a re-initialization to to resume work */
- continue;
- }
+ /* Stop the task */
+ if ( ( events & DWMAC_COMMON_EVENT_TASK_STOP ) != 0 ) {
+ dwmac_core_dma_stop_tx( self );
+ dwmac_disable_irq_tx_all( self );
- /* Ininitialize / Re-initialize transmission handling */
- if ( ( events & DWMAC_COMMON_EVENT_TASK_INIT ) != 0 ) {
- (void) dwmac_update_autonegotiation_params( self );
- dwmac_core_dma_stop_tx( self );
- ( DESC_OPS->release_tx_bufs )( self );
- idx_transmit = 0;
- idx_transmit_first = 0;
- idx_transmitted = 0;
- idx_release = 0;
- p_m = NULL;
- is_first = false;
- is_last = false;
- size = 0;
- ( DESC_OPS->init_tx_desc )( self );
- dwmac_core_dma_start_tx( self );
- dwmac_core_dma_restart_tx( self );
+ /* Release all tx mbufs at the risk of data loss */
+ ( DESC_OPS->release_tx_bufs )( self );
- /* Clear our interrupt statuses */
- dwmac_core_reset_dma_irq_status_tx( self );
+ dwmac_control_request_complete( self );
- dwmac_control_request_complete( self );
- }
+ /* Return to events reception without re-enabling the interrupts
+ * The task needs a re-initialization to to resume work */
+ events = 0;
+ continue;
+ }
- /* Try to bump up the dma threshold due to a failure */
- if ( ( events & DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD ) != 0 ) {
- if ( self->dma_threshold_control
- != DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
- && self->dma_threshold_control <= 256 ) {
- self->dma_threshold_control += 64;
- ( DMA_OPS->dma_mode )(
- self,
- self->dma_threshold_control,
- DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
- );
+ /* Ininitialize / Re-initialize transmission handling */
+ if ( ( events & DWMAC_COMMON_EVENT_TASK_INIT ) != 0 ) {
+ events &= ~DWMAC_COMMON_EVENT_TASK_INIT;
+ (void) dwmac_update_autonegotiation_params( self );
+ dwmac_core_dma_stop_tx( self );
+ ( DESC_OPS->release_tx_bufs )( self );
+ idx_transmit = 0;
+ idx_transmit_first = 0;
+ idx_transmitted = 0;
+ idx_release = 0;
+ p_m = NULL;
+ is_first = false;
+ is_last = false;
+ size = 0;
+ ( DESC_OPS->init_tx_desc )( self );
+ dwmac_core_dma_start_tx( self );
+ dwmac_core_dma_restart_tx( self );
+
+ /* Clear our interrupt statuses */
+ dwmac_core_reset_dma_irq_status_tx( self );
+ dwmac_enable_irq_tx_default( self );
+
+ dwmac_control_request_complete( self );
}
- }
- /* Handle one or more transmitted frames */
- if ( ( events & DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED ) != 0 ) {
- dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx;
-
- /* Next index to be transmitted */
- unsigned int idx_transmitted_next = dwmac_increment(
- idx_transmitted, INDEX_MAX );
-
- /* Free consumed fragments */
- while ( idx_release != idx_transmitted_next
- && ( DESC_OPS->am_i_tx_owner )( self, idx_release ) ) {
- /* Status handling per packet */
- if ( ( DESC_OPS->get_tx_ls )( self, idx_release ) ) {
- int status = ( DESC_OPS->tx_status )(
- self, idx_release
+ /* Try to bump up the dma threshold due to a failure */
+ if ( ( events & DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD ) != 0 ) {
+ events &= ~DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD;
+ if ( self->dma_threshold_control
+ != DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
+ && self->dma_threshold_control <= 256 ) {
+ self->dma_threshold_control += 64;
+ ( DMA_OPS->dma_mode )(
+ self,
+ self->dma_threshold_control,
+ DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
);
-
- if ( status == 0 ) {
- ++counts->packets_tranmitted_by_DMA;
- } else {
- ++counts->packet_errors;
- }
}
+ }
- DWMAC_PRINT_DBG(
- "tx: release %u\n",
- idx_release
- );
+ /* Handle one or more transmitted frames */
+ if ( ( events & DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED ) != 0 ) {
+ events &= ~DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED;
+ dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx;
+ dwmac_disable_irq_tx_transmitted( self );
+
+ /* Next index to be transmitted */
+ unsigned int idx_transmitted_next = dwmac_increment(
+ idx_transmitted, INDEX_MAX );
+
+ /* Free consumed fragments */
+ if( idx_release != idx_transmitted_next
+ && ( DESC_OPS->am_i_tx_owner )( self, idx_release ) ) {
+ while ( idx_release != idx_transmitted_next
+ && ( DESC_OPS->am_i_tx_owner )( self, idx_release ) ) {
+ /* Status handling per packet */
+ if ( ( DESC_OPS->get_tx_ls )( self, idx_release ) ) {
+ int status = ( DESC_OPS->tx_status )(
+ self, idx_release
+ );
- /* Release the DMA descriptor */
- ( DESC_OPS->release_tx_desc )( self, idx_release );
+ if ( status == 0 ) {
+ ++counts->packets_tranmitted_by_DMA;
+ } else {
+ ++counts->packet_errors;
+ }
+ }
- /* Release mbuf */
- m_free( self->mbuf_addr_tx[idx_release] );
- self->mbuf_addr_tx[idx_release] = NULL;
+ DWMAC_PRINT_DBG(
+ "tx: release %u\n",
+ idx_release
+ );
- /* Next release index */
- idx_release = dwmac_increment(
- idx_release, INDEX_MAX );
- }
+ /* Release the DMA descriptor */
+ ( DESC_OPS->release_tx_desc )( self, idx_release );
- /* Clear transmit interrupt status */
- self->dmagrp->status = DMAGRP_STATUS_TI;
+ /* Release mbuf */
+ m_free( self->mbuf_addr_tx[idx_release] );
+ self->mbuf_addr_tx[idx_release] = NULL;
- if ( ( self->arpcom.ac_if.if_flags & IFF_OACTIVE ) != 0 ) {
- /* The last tranmission has been incomplete
- * (for example due to lack of DMA descriptors).
- * Continue it now! */
- events |= DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME;
+ /* Next release index */
+ idx_release = dwmac_increment(
+ idx_release, INDEX_MAX );
+ }
+ if ( ( self->arpcom.ac_if.if_flags & IFF_OACTIVE ) != 0 ) {
+ /* The last tranmission has been incomplete
+ * (for example due to lack of DMA descriptors).
+ * Continue it now! */
+ events |= DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME;
+ }
+ } else {
+ /* Clear transmit interrupt status */
+ self->dmagrp->status = DMAGRP_STATUS_TI;
+ /* Get re-activated by the next interrupt */
+ dwmac_enable_irq_tx_transmitted( self );
+ }
}
- }
- /* There are one or more frames to be transmitted. */
- if ( ( events & DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME ) != 0 ) {
- dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx;
+ /* There are one or more frames to be transmitted. */
+ if ( ( events & DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME ) != 0 ) {
+ events &= ~DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME;
+ dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx;
- if ( p_m != NULL ) {
- /* This frame will get re-counted */
- --counts->frames_from_stack;
- }
+ if ( p_m != NULL ) {
+ /* This frame will get re-counted */
+ --counts->frames_from_stack;
+ }
- while ( true ) {
- unsigned int idx = dwmac_increment(
- idx_transmit, INDEX_MAX );
+ while ( true ) {
+ unsigned int idx = dwmac_increment(
+ idx_transmit, INDEX_MAX );
- p_m = dwmac_next_fragment(
- &self->arpcom.ac_if,
- p_m,
- &is_first,
- &is_last,
- &size
- );
+ p_m = dwmac_next_fragment(
+ &self->arpcom.ac_if,
+ p_m,
+ &is_first,
+ &is_last,
+ &size
+ );
- /* New fragment? */
- if ( p_m != NULL ) {
- ++counts->frames_from_stack;
+ /* New fragment? */
+ if ( p_m != NULL ) {
+ ++counts->frames_from_stack;
- /* Queue full? */
- if ( idx == idx_release ) {
- DWMAC_PRINT_DBG( "tx: full queue: 0x%08x\n", p_m );
+ /* Queue full? */
+ if ( idx == idx_release ) {
+ DWMAC_PRINT_DBG( "tx: full queue: 0x%08x\n", p_m );
- /* The queue is full, wait for transmitted interrupt */
- break;
- }
+ /* The queue is full, wait for transmitted interrupt */
+ break;
+ }
- /* Set the transfer data */
- rtems_cache_flush_multiple_data_lines(
- mtod( p_m, const void * ),
- size
- );
+ /* Set the transfer data */
+ rtems_cache_flush_multiple_data_lines(
+ mtod( p_m, const void * ),
+ size
+ );
- ( DESC_OPS->prepare_tx_desc )(
- self,
- idx_transmit,
- is_first,
- size,
- mtod( p_m, const void * )
- );
- self->mbuf_addr_tx[idx_transmit] = p_m;
+ ( DESC_OPS->prepare_tx_desc )(
+ self,
+ idx_transmit,
+ is_first,
+ size,
+ mtod( p_m, const void * )
+ );
+ self->mbuf_addr_tx[idx_transmit] = p_m;
- ++counts->frames_to_dma;
- counts->bytes_to_dma += size;
- DWMAC_PRINT_DBG(
- "tx: %02" PRIu32 ": %u %s%s\n",
- idx_transmit, size,
- ( is_first != false ) ? ( "F" ) : ( "" ),
- ( is_last != false ) ? ( "L" ) : ( "" )
+ ++counts->frames_to_dma;
+ counts->bytes_to_dma += size;
+ DWMAC_PRINT_DBG(
+ "tx: %02" PRIu32 ": %u %s%s\n",
+ idx_transmit, size,
+ ( is_first != false ) ? ( "F" ) : ( "" ),
+ ( is_last != false ) ? ( "L" ) : ( "" )
- );
+ );
- if ( is_first ) {
- idx_transmit_first = idx_transmit;
- is_first = false;
- } else {
- /* To avoid race condition */
- ( DESC_OPS->release_tx_ownership )( self, idx_transmit );
- }
+ if ( is_first ) {
+ idx_transmit_first = idx_transmit;
+ is_first = false;
+ } else {
+ /* To avoid race condition */
+ ( DESC_OPS->release_tx_ownership )( self, idx_transmit );
+ }
- if ( is_last ) {
- /* Interrupt on completition only for the latest fragment */
- ( DESC_OPS->close_tx_desc )( self, idx_transmit );
+ if ( is_last ) {
+ /* Interrupt on completition only for the latest fragment */
+ ( DESC_OPS->close_tx_desc )( self, idx_transmit );
+
+ /* To avoid race condition */
+ ( DESC_OPS->release_tx_ownership )( self, idx_transmit_first );
+ idx_transmitted = idx_transmit;
+
+ if ( ( self->dmagrp->status & DMAGRP_STATUS_TU ) != 0 ) {
+ /* Re-enable the tranmit DMA */
+ dwmac_core_dma_restart_tx( self );
+ DWMAC_PRINT_DBG(
+ "tx DMA restart: %02u\n",
+ idx_transmit_first
+ );
+ }
+ }
- /* To avoid race condition */
- ( DESC_OPS->release_tx_ownership )( self, idx_transmit_first );
- idx_transmitted = idx_transmit;
+ /* Next transmit index */
+ idx_transmit = idx;
- if ( ( self->dmagrp->status & DMAGRP_STATUS_TU ) != 0 ) {
- /* Re-enable the tranmit DMA */
- dwmac_core_dma_restart_tx( self );
- DWMAC_PRINT_DBG(
- "tx DMA restart: %02u\n",
- idx_transmit_first
- );
+ if ( is_last ) {
+ ++counts->packets_to_dma;
}
- }
- /* Next transmit index */
- idx_transmit = idx;
-
- if ( is_last ) {
- ++counts->packets_to_dma;
+ /* Next fragment of the frame */
+ p_m = p_m->m_next;
+ } else {
+ /* Nothing to transmit */
+ break;
}
+ }
- /* Next fragment of the frame */
- p_m = p_m->m_next;
+ /* No more packets and fragments? */
+ if ( p_m == NULL ) {
+ /* Interface is now inactive */
+ self->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
} else {
- /* Nothing to transmit */
- break;
+ /* There are more packets pending to be sent,
+ * but we have run out of DMA descriptors.
+ * We will continue sending once descriptors
+ * have been freed due to a transmitted interupt */
+ DWMAC_PRINT_DBG( "tx: transmission incomplete\n" );
+ events |= DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED;
}
- }
- /* No more packets and fragments? */
- if ( p_m == NULL ) {
- /* Interface is now inactive */
- self->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
- } else {
- /* There are more packets pending to be sent,
- * but we have run out of DMA descriptors.
- * We will continue sending once descriptors
- * have been freed due to a transmitted interupt */
- DWMAC_PRINT_DBG( "tx: transmission incomplete\n" );
+ /* TODO: Add handling */
}
- /* TODO: Add handling */
+ DWMAC_PRINT_DBG( "tx: enable transmit interrupts\n" );
}
-
- DWMAC_PRINT_DBG( "tx: enable transmit interrupts\n" );
-
- /* Re-enable transmit interrupts */
- dwmac_enable_irq_tx( self );
}
}