summaryrefslogtreecommitdiffstats
path: root/libs/Network/tx.c
diff options
context:
space:
mode:
authorEvan Lojewski <github@meklort.com>2019-07-14 20:25:38 -0600
committerEvan Lojewski <github@meklort.com>2019-07-14 20:26:46 -0600
commit0d3f077b9beb392a0b23381123b2c5660ef0f33a (patch)
treed53bc57b77007ba8249f2e175487fc5d59582d25 /libs/Network/tx.c
parentfb28a33268eee8c69e6362b9cb27f0f255bd002e (diff)
downloadbcm5719-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.c66
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;
}
OpenPOWER on IntegriCloud