core: Reuse buffers for tx, allow message pools

Use new m_msg_alloc/m_msg_free operations for whole-message
MCTP buffers. m_realloc is no longer used, instead the maximum
sized buffer is allocated for each reassembly.
This allows applications to keep a pool of MCTP message buffers.

Don't create a queue of packets to transmit, instead reuse a single
binding-provided tx_storage buffer for each transmitted packet, which
can be static for bindings that have a known maximum packet size.

Asynchronous users/bindings can no longer rely on the core for queueing
TX packets, instead they should test mctp_is_tx_ready() prior to calling
mctp_message_tx(). The stack will return -EBUSY from mctp_message_tx()
if there is already a message pending to send.

Bindings must be updated to add the tx_storage member, and the core will
no longer free packets passed to mctp_bus_rx().

Change-Id: I2598bb91026ccef01b268c52b06c0f8e20bebb1e
Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
diff --git a/alloc.c b/alloc.c
index 84c3f65..0639e87 100644
--- a/alloc.c
+++ b/alloc.c
@@ -9,15 +9,33 @@
 #include "config.h"
 #endif
 
+#include "compiler.h"
+
+#ifdef MCTP_DEFAULT_ALLOC
+static void *default_msg_malloc(size_t size, void *ctx __unused)
+{
+	void *ptr = __mctp_alloc(size);
+	return ptr;
+}
+
+static void default_msg_free(void *msg, void *ctx __unused)
+{
+	__mctp_free(msg);
+}
+#endif
+
 struct {
 	void *(*m_alloc)(size_t);
 	void (*m_free)(void *);
-	void *(*m_realloc)(void *, size_t);
+	/* Final argument is ctx */
+	void *(*m_msg_alloc)(size_t, void *);
+	void (*m_msg_free)(void *, void *);
 } alloc_ops = {
 #ifdef MCTP_DEFAULT_ALLOC
 	malloc,
 	free,
-	realloc,
+	default_msg_malloc,
+	default_msg_free,
 #endif
 };
 
@@ -26,8 +44,6 @@
 {
 	if (alloc_ops.m_alloc)
 		return alloc_ops.m_alloc(size);
-	if (alloc_ops.m_realloc)
-		return alloc_ops.m_realloc(NULL, size);
 	assert(0);
 	return NULL;
 }
@@ -36,24 +52,32 @@
 {
 	if (alloc_ops.m_free)
 		alloc_ops.m_free(ptr);
-	else if (alloc_ops.m_realloc)
-		alloc_ops.m_realloc(ptr, 0);
 	else
 		assert(0);
 }
 
-void *__mctp_realloc(void *ptr, size_t size)
+void *__mctp_msg_alloc(size_t size, struct mctp *mctp)
 {
-	if (alloc_ops.m_realloc)
-		return alloc_ops.m_realloc(ptr, size);
+	void *ctx = mctp_get_alloc_ctx(mctp);
+	if (alloc_ops.m_msg_alloc)
+		return alloc_ops.m_msg_alloc(size, ctx);
 	assert(0);
 	return NULL;
 }
 
+void __mctp_msg_free(void *ptr, struct mctp *mctp)
+{
+	void *ctx = mctp_get_alloc_ctx(mctp);
+	if (alloc_ops.m_msg_free)
+		alloc_ops.m_msg_free(ptr, ctx);
+}
+
 void mctp_set_alloc_ops(void *(*m_alloc)(size_t), void (*m_free)(void *),
-			void *(m_realloc)(void *, size_t))
+			void *(*m_msg_alloc)(size_t, void *),
+			void (*m_msg_free)(void *, void *))
 {
 	alloc_ops.m_alloc = m_alloc;
 	alloc_ops.m_free = m_free;
-	alloc_ops.m_realloc = m_realloc;
+	alloc_ops.m_msg_alloc = m_msg_alloc;
+	alloc_ops.m_msg_free = m_msg_free;
 }