Skip to content

Commit 3a77ce0

Browse files
Reformat, fix STM32 Eth v2 potential to have issues when the Tx ring gets full
1 parent 1dc339c commit 3a77ce0

File tree

4 files changed

+39
-14
lines changed

4 files changed

+39
-14
lines changed

connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace mbed {
4848
void giveToDMA(size_t descIdx, uint8_t const * buffer, size_t len, bool firstDesc, bool lastDesc) override;
4949
public:
5050
explicit TxDMA(ETH_TypeDef * const base):
51+
GenericTxDMARing(1), // Request that 1 Tx descriptor is always left unfilled
5152
base(base)
5253
{}
5354
};

connectivity/drivers/emac/include/GenericEthDMA.h

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ namespace mbed {
3939
/// Number of entries in the Tx descriptor ring
4040
static constexpr size_t TX_NUM_DESCS = MBED_CONF_NSAPI_EMAC_TX_NUM_DESCS;
4141

42+
/// Extra, unfilled Tx descs to leave in the DMA ring at all times.
43+
/// This is used to support Eth MACs that don't allow enqueuing every single descriptor at a time.
44+
const size_t extraTxDescsToLeave;
45+
4246
/// Pointer to first memory buffer in the chain associated with descriptor n.
4347
/// The buffer address shall only be set for the *last* descriptor, so that the entire chain is freed
4448
/// when the last descriptor is returned.
@@ -55,6 +59,11 @@ namespace mbed {
5559
std::atomic<size_t> txDescsOwnedByApplication; ///< Number of Tx descriptors owned by the application. Decremented by txPacket() and incremented by reclaimTxDescs()
5660
size_t txReclaimIndex; ///< Index of the next Tx descriptor that will be reclaimed by the mac thread calling reclaimTxDescs().
5761

62+
/// Construct, passing a value for extraTxDescsToLeave
63+
GenericTxDMARing(size_t extraTxDescsToLeave = 0):
64+
extraTxDescsToLeave(extraTxDescsToLeave)
65+
{}
66+
5867
/// Configure DMA registers to point to the DMA ring,
5968
/// and enable DMA. This is done before the MAC itself is enabled.
6069
virtual void startDMA() = 0;
@@ -181,17 +190,18 @@ namespace mbed {
181190

182191
CompositeEMAC::ErrCode txPacket(net_stack_mem_buf_t * buf) {
183192
// Step 1: Figure out if we can send this zero-copy, or if we need to copy it.
184-
size_t neededDescs = memory_manager->count_buffers(buf);
193+
size_t packetDescsUsed = memory_manager->count_buffers(buf);
194+
size_t neededFreeDescs = packetDescsUsed + extraTxDescsToLeave;
185195
bool needToCopy = false;
186-
if(neededDescs >= TX_NUM_DESCS)
196+
if(neededFreeDescs >= TX_NUM_DESCS)
187197
{
188198
// Packet uses too many buffers, we have to copy it into a continuous buffer.
189199
// Note: Some Eth DMAs (e.g. STM32 v2) cannot enqueue all the descs in the ring at the same time
190200
// so we can't use every single descriptor to send the packet.
191201
needToCopy = true;
192202
}
193203

194-
if(!needToCopy && (neededDescs > txDescsOwnedByApplication && txDescsOwnedByApplication > 0)) {
204+
if(!needToCopy && (neededFreeDescs > txDescsOwnedByApplication && txDescsOwnedByApplication > extraTxDescsToLeave)) {
195205
// Packet uses more buffers than we have descriptors, but we can send it immediately if we copy
196206
// it into a single buffer.
197207
needToCopy = true;
@@ -233,7 +243,8 @@ namespace mbed {
233243

234244
// We should have gotten just one contiguous buffer
235245
MBED_ASSERT(memory_manager->get_next(newBuf) == nullptr);
236-
neededDescs = 1;
246+
packetDescsUsed = 1;
247+
neededFreeDescs = packetDescsUsed + extraTxDescsToLeave;
237248

238249
// Copy data over
239250
memory_manager->copy_from_buf(static_cast<uint8_t *>(memory_manager->get_ptr(newBuf)), memory_manager->get_len(newBuf), buf);
@@ -245,14 +256,14 @@ namespace mbed {
245256
// Note that, in my experience, it's better to block here, as dropping the packet
246257
// due to not having enough buffers can create weird effects when the application sends
247258
// lots of packets at once.
248-
while(txDescsOwnedByApplication < neededDescs)
259+
while(txDescsOwnedByApplication < neededFreeDescs)
249260
{
250261
txDescAvailFlag.wait_any_for(1, rtos::Kernel::wait_for_u32_forever);
251262
}
252263

253264
// Step 4: Load buffer into descriptors and send
254265
net_stack_mem_buf_t * currBuf = buf;
255-
for(size_t descCount = 0; descCount < neededDescs; descCount++)
266+
for(size_t descCount = 0; descCount < packetDescsUsed; descCount++)
256267
{
257268
#if __DCACHE_PRESENT
258269
// Write buffer back to main memory
@@ -453,6 +464,8 @@ namespace mbed {
453464
// This could potentially produce a false positive if we do this in the middle of receiving
454465
// an existing packet, but that is unlikely and will not cause anything bad to happen if it does.
455466

467+
bool seenFirstDesc = false;
468+
456469
for(size_t descCount = 0; descCount < RX_NUM_DESCS; descCount++)
457470
{
458471
size_t descIdx = (rxNextIndex + descCount) % RX_NUM_DESCS;
@@ -466,6 +479,20 @@ namespace mbed {
466479
// Descriptor owned by DMA. We are out of descriptors to process.
467480
return false;
468481
}
482+
if(isFirstDesc(descIdx))
483+
{
484+
if(seenFirstDesc)
485+
{
486+
// First desc seen after another first desc.
487+
// Some MACs do this if they run out of Rx descs when halfway through a packet.
488+
// dequeuePacket() can clean this up and reclaim the partial packet desc(s).
489+
return true;
490+
}
491+
else
492+
{
493+
seenFirstDesc = true;
494+
}
495+
}
469496
if(isErrorDesc(descIdx) || isLastDesc(descIdx))
470497
{
471498
// Reclaimable descriptor or complete packet detected.

connectivity/netsocket/tests/TESTS/network/emac/emac_test_memory.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,10 @@ void test_emac_memory_cb(int opt)
4949
// Verify that, if this was a test step where allocations were supposed to fail, they actually did fail.
5050
// We can accept a couple of successful packets due to buffers that had been allocated earlier, but the
5151
// *majority* of the packets should have failed.
52-
if(test_step > 0 && !echo_may_succeed)
53-
{
54-
if(successful_pkts_this_step >= failed_pkts_this_step)
55-
{
52+
if (test_step > 0 && !echo_may_succeed) {
53+
if (successful_pkts_this_step >= failed_pkts_this_step) {
5654
printf("Too many successful packets (%d) vs failed packets (%d). This was supposed to be a failure test!\r\n",
57-
successful_pkts_this_step, failed_pkts_this_step);
55+
successful_pkts_this_step, failed_pkts_this_step);
5856
SET_ERROR_FLAGS(TEST_FAILED);
5957
END_TEST_LOOP;
6058
}
@@ -164,8 +162,7 @@ void test_emac_memory_cb(int opt)
164162
}
165163
}
166164

167-
if(opt == INPUT)
168-
{
165+
if (opt == INPUT) {
169166
successful_pkts_this_step += 1;
170167
}
171168

connectivity/netsocket/tests/emac_test_utils/emac_util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void emac_if_add_multicast_group(uint8_t *address);
114114
void emac_if_remove_multicast_group(uint8_t *address);
115115

116116
/// If called with false as the arg, disables memory allocation
117-
/// (a) from the pool at all times, and
117+
/// (a) from the pool at all times, and
118118
/// (b) from the heap when not actively transmitting a packet
119119
void emac_if_set_output_memory(bool memory);
120120

0 commit comments

Comments
 (0)