diff options
author | Evan Lojewski <github@meklort.com> | 2019-07-14 20:25:38 -0600 |
---|---|---|
committer | Evan Lojewski <github@meklort.com> | 2019-07-14 20:26:46 -0600 |
commit | 0d3f077b9beb392a0b23381123b2c5660ef0f33a (patch) | |
tree | d53bc57b77007ba8249f2e175487fc5d59582d25 /libs/Network/tx.c | |
parent | fb28a33268eee8c69e6362b9cb27f0f255bd002e (diff) | |
download | bcm5719-ortega-0d3f077b9beb392a0b23381123b2c5660ef0f33a.tar.gz bcm5719-ortega-0d3f077b9beb392a0b23381123b2c5660ef0f33a.zip |
Network: Improve error handling when unable to allocate blocks.
- Refactor init code to allow external code to reset TX or RX state machines.
- Update the TX routines to return true on sucessfull allocation, and false otherwise.
- When allocation fails, drain the ramining passthrough buffer to ensure that the NCSI block is not locked up.
Diffstat (limited to 'libs/Network/tx.c')
-rw-r--r-- | libs/Network/tx.c | 66 |
1 files changed, 45 insertions, 21 deletions
diff --git a/libs/Network/tx.c b/libs/Network/tx.c index d619bf4..a1cd30e 100644 --- a/libs/Network/tx.c +++ b/libs/Network/tx.c @@ -43,6 +43,7 @@ //////////////////////////////////////////////////////////////////////////////// #include <APE_APE.h> +#include <APE_SHM.h> #include <APE_TX_PORT0.h> #include <Ethernet.h> #include <Network.h> @@ -52,6 +53,7 @@ #include <endian.h> #include <stdio.h> #else +#include <printf.h> /* ARM */ static inline uint32_t be32toh(uint32_t be32) { @@ -75,9 +77,6 @@ uint32_t Network_TX_numBlocksNeeded(uint32_t frame_size) blocks += DIVIDE_RND_UP(frame_size, ADDITIONAL_FRAME_MAX); } -#ifdef CXX_SIMULATOR - printf("%d blocks needed for packet with frame size %d\n", blocks, frame_size); -#endif return blocks; } @@ -101,16 +100,11 @@ int32_t __attribute__((noinline)) Network_TX_allocateBlock(NetworkPort_t *port) if (APE_TX_TO_NET_BUFFER_ALLOCATOR_STATE_ALLOCATION_OK != status.bits.State) { block = -1; -#if CXX_SIMULATOR printf("Error: Failed to allocate TX block.\n"); -#endif } else { block = status.bits.Index; -#if CXX_SIMULATOR - printf("Allocated TX block %d\n", block); -#endif } return block; @@ -233,18 +227,17 @@ static uint32_t inline Network_TX_initAdditionalBlock(RegTX_PORTOut_t *block, in return control.bits.payload_length; } -static inline void Network_TX_transmitPacket_internal(uint8_t *packet, uint32_t length, bool big_endian, NetworkPort_t *port) +static inline bool Network_TX_transmitPacket_internal(uint8_t *packet, uint32_t length, bool big_endian, NetworkPort_t *port) { if (!length) { - return; + return false; } uint32_t *packet_32 = (uint32_t *)packet; uint32_t consumed = 0; uint32_t blocks = Network_TX_numBlocksNeeded(length); int total_blocks = blocks; - ; // First block int32_t tail; @@ -252,7 +245,7 @@ static inline void Network_TX_transmitPacket_internal(uint8_t *packet, uint32_t if (first <= 0) { // Error - return; + return false; } int32_t next_block = -1; if (blocks > 1) @@ -287,16 +280,18 @@ static inline void Network_TX_transmitPacket_internal(uint8_t *packet, uint32_t doorbell.bits.Length = total_blocks; *((RegAPETxToNetDoorbell_t *)port->tx_doorbell) = doorbell; + + return true; } -void Network_TX_transmitBePacket(uint8_t *packet, uint32_t length, NetworkPort_t *port) +bool Network_TX_transmitBePacket(uint8_t *packet, uint32_t length, NetworkPort_t *port) { - Network_TX_transmitPacket_internal(packet, length, true, port); + return Network_TX_transmitPacket_internal(packet, length, true, port); } -void Network_TX_transmitLePacket(uint8_t *packet, uint32_t length, NetworkPort_t *port) +bool Network_TX_transmitLePacket(uint8_t *packet, uint32_t length, NetworkPort_t *port) { - Network_TX_transmitPacket_internal(packet, length, false, port); + return Network_TX_transmitPacket_internal(packet, length, false, port); } static uint32_t inline Network_TX_initFirstPassthroughBlock(RegTX_PORTOut_t *block, uint32_t length, int32_t blocks, int32_t next_block) @@ -396,38 +391,65 @@ static uint32_t inline Network_TX_initAdditionalPassthroughBlock(RegTX_PORTOut_t return control.bits.payload_length; } -void Network_TX_transmitPassthroughPacket(uint32_t length, NetworkPort_t *port) +static void drainPassthroughBytes(uint32_t bytes) { - if (!length) + printf("Dropping %d bytes\n", bytes); + // Drain any passthrough bytes to ensure that the NCSI input buffers are not locked up. + int num_words = DIVIDE_RND_UP(bytes, sizeof(uint32_t)) + 1; // +1 for FCS word. + for (int i = 0; i < num_words; i++) { - return; + uint32_t word = APE_PERI.BmcToNcReadBuffer.r32; + (void)word; } +} +bool Network_TX_transmitPassthroughPacket(uint32_t length, NetworkPort_t *port) +{ + if (!length) + { + return false; + } // Drop the FCS word. It will be generated by hardware. length -= 4; int32_t tail; int32_t first = tail = Network_TX_allocateBlock(port); + if(first < 0) + { + // Unable to allocate block. + drainPassthroughBytes(length); + return false; + } int32_t next_block = -1; uint32_t blocks = Network_TX_numBlocksNeeded(length); int total_blocks = blocks; - ; + + printf("Sending passhrough packet to Net. First block: %d (%d total).\n", first, blocks); if (blocks > 1) { next_block = Network_TX_allocateBlock(port); + if(next_block < 0) + { + return false; + } } RegTX_PORTOut_t *block = (RegTX_PORTOut_t *)&port->tx_port->Out[TX_PORT_OUT_ALL_BLOCK_WORDS * first]; length -= Network_TX_initFirstPassthroughBlock(block, length, blocks, next_block); blocks -= 1; + while (blocks--) { - block = (RegTX_PORTOut_t *)&port->tx_port->Out[TX_PORT_OUT_ALL_BLOCK_WORDS * next_block]; if (blocks) { next_block = Network_TX_allocateBlock(port); + if(next_block < 0) + { + drainPassthroughBytes(length); + return false; + } length -= Network_TX_initAdditionalPassthroughBlock(block, next_block, length); } else @@ -449,4 +471,6 @@ void Network_TX_transmitPassthroughPacket(uint32_t length, NetworkPort_t *port) // Read last RX word (FCS) to clear the buffer uint32_t data = APE_PERI.BmcToNcReadBuffer.r32; (void)data; + + return true; } |