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/astlpc.c b/astlpc.c
index d322b7c..0acc39b 100644
--- a/astlpc.c
+++ b/astlpc.c
@@ -870,6 +870,26 @@
 	return rc == -EBUSY ? 0 : rc;
 }
 
+/* Update binding pkt_size and reallocate tx_storage */
+static int mctp_astlpc_set_pkt_size(struct mctp_binding_astlpc *astlpc,
+				    size_t pkt_size)
+{
+	size_t body = MCTP_BODY_SIZE(pkt_size);
+	body += astlpc->binding.pkt_header + astlpc->binding.pkt_trailer;
+	size_t pktbuf_size = MCTP_PKTBUF_SIZE(body);
+	/* Reallocate TX storage */
+	if (astlpc->binding.tx_storage) {
+		__mctp_free(astlpc->binding.tx_storage);
+	}
+	astlpc->binding.tx_storage = __mctp_alloc(pktbuf_size);
+	if (!astlpc->binding.tx_storage) {
+		return -ENOMEM;
+	}
+
+	astlpc->binding.pkt_size = pkt_size;
+	return 0;
+}
+
 static uint32_t mctp_astlpc_calculate_mtu(struct mctp_binding_astlpc *astlpc,
 					  struct mctp_astlpc_layout *layout)
 {
@@ -940,8 +960,13 @@
 		return -EINVAL;
 	}
 
-	if (astlpc->proto->version >= 2)
-		astlpc->binding.pkt_size = MCTP_PACKET_SIZE(mtu);
+	if (astlpc->proto->version >= 2) {
+		rc = mctp_astlpc_set_pkt_size(astlpc, MCTP_PACKET_SIZE(mtu));
+		if (rc) {
+			astlpc_prwarn(astlpc, "Allocation error");
+			return rc;
+		}
+	}
 
 	return 0;
 }
@@ -1056,9 +1081,9 @@
 		mctp_bus_rx(&astlpc->binding, pkt);
 	} else {
 		/* TODO: Drop any associated assembly */
-		mctp_pktbuf_free(pkt);
 		astlpc_prdebug(astlpc, "Dropped corrupt packet");
 	}
+	mctp_pktbuf_free(pkt);
 }
 
 static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc)
@@ -1266,8 +1291,6 @@
 	astlpc->requested_mtu = mtu;
 	astlpc->binding.name = "astlpc";
 	astlpc->binding.version = 1;
-	astlpc->binding.pkt_size =
-		MCTP_PACKET_SIZE(mtu > MCTP_BTU ? mtu : MCTP_BTU);
 	astlpc->binding.pkt_header = 4;
 	astlpc->binding.pkt_trailer = 4;
 	astlpc->binding.tx = mctp_binding_astlpc_tx;
@@ -1281,6 +1304,14 @@
 		return NULL;
 	}
 
+	if (mctp_astlpc_set_pkt_size(
+		    astlpc,
+		    MCTP_PACKET_SIZE(mtu > MCTP_BTU ? mtu : MCTP_BTU)) != 0) {
+		astlpc_prerr(astlpc, "%s: Allocation error", __func__);
+		__mctp_free(astlpc);
+		return NULL;
+	}
+
 	return astlpc;
 }
 
@@ -1326,6 +1357,7 @@
 	/* Clear channel-active and bmc-ready */
 	if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC)
 		mctp_astlpc_kcs_set_status(astlpc, 0);
+	__mctp_free(astlpc->binding.tx_storage);
 	__mctp_free(astlpc);
 }