This is a problem in the application layer, it should be asking transmission buffers to the driver and write there directly. Assuming that a driver can transmit from a generic buffer is a huge assumption that does not consider things like, buffers in dedicated memory accessible by the MAC or alignment constraints. IMHO lwIP is flawed in this regards, buffers management should be in the driver.
I totally agree. lwIP has a unified buffer management that makes no distinction on the purpose of a buffer when it's allocated, and I also consider it a flaw because it makes it totally impossible to implement what you describe, just because allocation is done at the application level and such a change would break all existing applications which is unacceptable.
That said, let's not forget that in a real time OS running in a microcontroller transmit performance is hardly going to be a problem in most, if not all applications. The bottleneck is going to be always somewhere else, and even if it is not, you have total control on the timing of your source of data so with some care you can synchronize things so you don't need large transmit buffer memory and buffer copying before handling the data to the MAC peripheral is just a tiny penalty.
Reception is a whole different story. There you're at the mercy of the network conditions, something you can't control in any possible way, so you must do your best to cope with hostile scenarios.
I'll keep it looking forward to the day we will have a dedicated TCP/IP stack, lwIP is not much appealing to me, way too complex for a "lw".
That would certainly fall into the cathegory of "reiventing the wheel". The value of lwIP is not only the work involved in creating it (though huge) but also its maturiry. BTW, I think there's also uIP (don't know much about it though).
Releasing a descriptor is meant to release all the buffers associated to the descriptor, how this is done is up to the implementation. I can't make a public API for an implementation-specific issue. Moreover, ther would be potential atomicity issues, would be OK to release buffers belonging to a descriptor one by one? in you case probably yes but you cannot do such assumptions.
Mmm... yes, you are right. With STM32 there is no problem, when a buffer is released you just assign it to a descriptor and mark it as owned by the DMA. That's all.
I agree this mechanism may not be feasible to implement in some architectures, but THEN AGAIN, for those architectures you can go with a single buffer per frame. Think about it. Maybe exposing a buffer release API (instead of descriptor release) is not that bad. If the architecture doesn't support it well, just don't implement the multibuffer receive and you're done. Buffer release becomes equal to descritptor release, and you leave the door open to implement multibuffer frame reception in architectures where it is easily doable, like the STM32. I assure you that in my case it has meant a HUGE difference in my ability to cope with those hostile situations I mentioned.
That said, there is also a way to go without per-buffer release:
I prefered to go that way because lwIP already implements the "custom pbuf" mechanism and in order to keep an hypothetical lwIP patch at a minimum. In this case, we would have to just use what lwIP provides, and the mechanism calls the release callback in a per-pbuf fashion when a pbuf chain is being released.
However, I just realized that though each mac_lld buffer ends up being placed into a separate pbuf, all those pbuf belong to a single chain and will remain together throughout their life cycle. That means that when one of them is being released it means it's being released from pbuf_free and ALL of them are being released as part of the same operation by pbuf_free. So what we can do in lwipthread when creating the pbuf chain is mark only the first (or last) pbuf as "custom pbuf" and place there a callback function that will just call the mac_lld release function. Note that no matter if you use the first or the last pbuf, it's up to pbuf_free the order of release (though I believe it goes from first to last), but also there is no harm in, for example, releasing ALL buffers of a descriptor when the first pbuf of a chain is being released by pbuf_free. Sure, the other buffers become immediately available to the MAC DMA while there are still "live" pbufs pointing to them, but those pbufs will live for just a few microseconds more while pbuf_free releases them and we are sure the associated buffers will not be accessed.
Post it here, I will evaluate the changes however I am oriented keeping the code as simple as possible because I am unable to do serious testing on this driver. The STM32 has 16KB of dedicated memory for the MAC DMA so you can have plenty buffers without having to handle frames as fragments.
"Plenty" is 10, and that's using the full 16K for receive buffers. I would not use "plenty". Note that AFIK USB/ethernet DMA can use directly those 16KB but also the other 112KB. The point is to have two separate areas with independent connections to the buffer matrix so they can be accessed simultaneously. The "natural" usage is to use the 16KB for USB/ethernet DMA and the 112KB for other stuff, but you could do it the other way around too. And of course you can place the DMA buffers in both chunks, and the only performance penalty would be bus contention due to the different bus masters competing for access to the SRAM (the CPU and the other two general purpose DMA, basically). The STM32F4 also has a 64KB chunk of SRAM called CCM, but it's connected directly to the CPU, not the bus matrix, and thus it can't be used for any DMA related operation.
See link below to download the patch (I'm including mac_lld.c, mac_ldd.h and also a unified patch so you can easily assess the modifications). I use to write lots of explicative comments so I think you'll find it easy to follow. I think the modifications do not add much complexity while meaning a huge performance improvement in the scenarios I'm facing and I've already described. Note also that if instead of small buffers you just use large (1522 bytes) receive buffers, the code behaves EXACTLY like the old code with no performance penaly whatsoever.
The transmit section hasn't been touched at all (though I might do shortly, now that I'm on this). The buffer size #define has been split to be able to specify different buffer sizes for transmision and reception.
https://dl.dropbox.com/u/35035041/stm32 ... eceive.zip