core,bindings: Allow bindings to specify packet size

Currently, we fix all packet sizes to the baseline MTU size. However,
bindings may support larger packet sizes.

This change makes the packet allocator use binding-specific parameters
to suit the binding itself, and uses the max packet size in the
packetisation path.

Since packet sizes may now exceed 255, we change the size and offset
types from uint8_t to size_t.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Change-Id: Ica932479f251dc33c67ea19e9e3e5a193cbe0b32
diff --git a/astlpc.c b/astlpc.c
index 5218c92..616ed1d 100644
--- a/astlpc.c
+++ b/astlpc.c
@@ -178,12 +178,12 @@
 		return;
 	}
 
-	if (len > MCTP_MTU + sizeof(struct mctp_hdr)) {
+	if (len > astlpc->binding.pkt_size) {
 		mctp_prwarn("invalid RX len 0x%x", len);
 		return;
 	}
 
-	pkt = mctp_pktbuf_alloc(len);
+	pkt = mctp_pktbuf_alloc(&astlpc->binding, len);
 	if (!pkt)
 		goto out_complete;
 
@@ -335,6 +335,8 @@
 	astlpc->binding.name = "astlpc";
 	astlpc->binding.version = 1;
 	astlpc->binding.tx = mctp_binding_astlpc_tx;
+	astlpc->binding.pkt_size = MCTP_BMTU;
+	astlpc->binding.pkt_pad = 0;
 
 	rc = mctp_astlpc_init_lpc(astlpc);
 	if (rc) {
diff --git a/core.c b/core.c
index 2a9784e..ff4bd63 100644
--- a/core.c
+++ b/core.c
@@ -60,16 +60,18 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 #endif
 
-struct mctp_pktbuf *mctp_pktbuf_alloc(uint8_t len)
+struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len)
 {
 	struct mctp_pktbuf *buf;
+	size_t size;
 
-	BUILD_ASSERT(MCTP_PKTBUF_SIZE <= 0xff);
+	size = binding->pkt_size + binding->pkt_pad;
 
 	/* todo: pools */
-	buf = __mctp_alloc(sizeof(*buf));
+	buf = __mctp_alloc(sizeof(*buf) + size);
 
-	buf->start = MCTP_PKTBUF_BINDING_PAD;
+	buf->size = size;
+	buf->start = binding->pkt_pad;
 	buf->end = buf->start + len;
 	buf->mctp_hdr_off = buf->start;
 	buf->next = NULL;
@@ -97,30 +99,28 @@
 	return pkt->end - pkt->start;
 }
 
-void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, uint8_t size)
+void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size)
 {
 	assert(size <= pkt->start);
 	pkt->start -= size;
 	return pkt->data + pkt->start;
 }
 
-void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, uint8_t size)
+void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size)
 {
 	void *buf;
 
-	assert(size < (MCTP_PKTBUF_SIZE - pkt->end));
+	assert(size < (pkt->size - pkt->end));
 	buf = pkt->data + pkt->end;
 	pkt->end += size;
 	return buf;
 }
 
-int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, uint8_t len)
+int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len)
 {
 	void *p;
 
-	assert(pkt->end + len <= MCTP_PKTBUF_SIZE);
-
-	if (pkt->end + len > MCTP_PKTBUF_SIZE)
+	if (pkt->end + len > pkt->size)
 		return -1;
 
 	p = pkt->data + pkt->end;
@@ -355,9 +355,6 @@
 	if (!bus->tx_enabled)
 		return -1;
 
-	mctp_prdebug("sending pkt, len %d",
-			mctp_pktbuf_size(pkt));
-
 	return bus->binding->tx(bus->binding, pkt);
 }
 
@@ -392,21 +389,22 @@
 int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
 		void *msg, size_t msg_len)
 {
+	size_t max_payload_len, payload_len, p;
 	struct mctp_pktbuf *pkt;
 	struct mctp_hdr *hdr;
 	struct mctp_bus *bus;
-	size_t pkt_len, p;
 	int i;
 
 	bus = find_bus_for_eid(mctp, eid);
+	max_payload_len = bus->binding->pkt_size - sizeof(*hdr);
 
 	/* queue up packets, each of max MCTP_MTU size */
 	for (p = 0, i = 0; p < msg_len; i++) {
-		pkt_len = msg_len - p;
-		if (pkt_len > MCTP_MTU)
-			pkt_len = MCTP_MTU;
+		payload_len = msg_len - p;
+		if (payload_len > max_payload_len)
+			payload_len = max_payload_len;
 
-		pkt = mctp_pktbuf_alloc(pkt_len + sizeof(*hdr));
+		pkt = mctp_pktbuf_alloc(bus->binding, payload_len + sizeof(*hdr));
 		hdr = mctp_pktbuf_hdr(pkt);
 
 		/* todo: tags */
@@ -418,12 +416,12 @@
 
 		if (i == 0)
 			hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
-		if (p + pkt_len >= msg_len)
+		if (p + payload_len >= msg_len)
 			hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
 		hdr->flags_seq_tag |=
 			(i & MCTP_HDR_SEQ_MASK) << MCTP_HDR_SEQ_SHIFT;
 
-		memcpy(mctp_pktbuf_data(pkt), msg + p, pkt_len);
+		memcpy(mctp_pktbuf_data(pkt), msg + p, payload_len);
 
 		/* add to tx queue */
 		if (bus->tx_queue_tail)
@@ -432,7 +430,7 @@
 			bus->tx_queue_head = pkt;
 		bus->tx_queue_tail = pkt;
 
-		p += pkt_len;
+		p += payload_len;
 	}
 
 	mctp_send_tx_queue(bus);
diff --git a/libmctp.h b/libmctp.h
index ecf78c6..5219a35 100644
--- a/libmctp.h
+++ b/libmctp.h
@@ -31,41 +31,33 @@
 #define MCTP_HDR_TAG_SHIFT	(0)
 #define MCTP_HDR_TAG_MASK	(0x7)
 
-/* Maximum size of *payload* data in a MCTP packet
- * @todo: dynamic sixing based on channel implementation.
- */
-#define MCTP_MTU	64
+/* Baseline maximum size of a MCTP packet */
+#define MCTP_BMTU_PAYLOAD	64
+#define MCTP_BMTU		(MCTP_BMTU_PAYLOAD + sizeof(struct mctp_hdr))
 
 /* packet buffers */
 
-/* Allow a little space before the MCTP header in the packet, for bindings that
- * may add their own header
- */
-#define MCTP_PKTBUF_BINDING_PAD	2
-
-#define MCTP_PKTBUF_SIZE	(MCTP_PKTBUF_BINDING_PAD + \
-		(sizeof(struct mctp_hdr) + MCTP_MTU))
-
 struct mctp_pktbuf {
-	unsigned char	data[MCTP_PKTBUF_SIZE];
-	uint8_t		start, end;
-	uint8_t		mctp_hdr_off;
+	size_t		start, end, size;
+	size_t		mctp_hdr_off;
 	struct mctp_pktbuf *next;
+	unsigned char	data[];
 };
 
-struct mctp_pktbuf *mctp_pktbuf_alloc(uint8_t len);
+struct mctp_binding;
+
+struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *hw, size_t len);
 void mctp_pktbuf_free(struct mctp_pktbuf *pkt);
 struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt);
 void *mctp_pktbuf_data(struct mctp_pktbuf *pkt);
 uint8_t mctp_pktbuf_size(struct mctp_pktbuf *pkt);
-void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, uint8_t size);
-void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, uint8_t size);
-int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, uint8_t len);
+void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size);
+void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size);
+int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len);
 
 /* MCTP core */
 struct mctp;
 struct mctp_bus;
-struct mctp_binding;
 
 struct mctp *mctp_init(void);
 
@@ -90,6 +82,8 @@
 	uint8_t		version;
 	struct mctp_bus	*bus;
 	struct mctp	*mctp;
+	int		pkt_size;
+	int		pkt_pad;
 	int		(*tx)(struct mctp_binding *binding,
 				struct mctp_pktbuf *pkt);
 };
diff --git a/serial.c b/serial.c
index 7e27b1c..081538f 100644
--- a/serial.c
+++ b/serial.c
@@ -149,7 +149,7 @@
 static void mctp_serial_start_packet(struct mctp_binding_serial *serial,
 		uint8_t len)
 {
-	serial->rx_pkt = mctp_pktbuf_alloc(len);
+	serial->rx_pkt = mctp_pktbuf_alloc(&serial->binding, len);
 }
 
 static void mctp_rx_consume_one(struct mctp_binding_serial *serial,
@@ -183,8 +183,8 @@
 		}
 		break;
 	case STATE_WAIT_LEN:
-		if (c > (MCTP_MTU + sizeof(struct mctp_hdr))
-				|| c < sizeof(struct mctp_hdr)) {
+		if (c > serial->binding.pkt_size ||
+				c < sizeof(struct mctp_hdr)) {
 			mctp_prdebug("invalid size %d", c);
 			serial->rx_state = STATE_WAIT_SYNC_START;
 		} else {
@@ -305,6 +305,8 @@
 	serial->rx_pkt = NULL;
 	serial->binding.name = "serial";
 	serial->binding.version = 1;
+	serial->binding.pkt_size = MCTP_BMTU;
+	serial->binding.pkt_pad = 0;
 
 	serial->binding.tx = mctp_binding_serial_tx;
 
diff --git a/tests/test-utils.c b/tests/test-utils.c
index 71de8a3..dc0a5f3 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -27,6 +27,8 @@
 	test->binding.name = "test";
 	test->binding.version = 1;
 	test->binding.tx = mctp_binding_test_tx;
+	test->binding.pkt_size = MCTP_BMTU;
+	test->binding.pkt_pad = 0;
 	return test;
 }
 
@@ -35,7 +37,7 @@
 {
 	struct mctp_pktbuf *pkt;
 
-	pkt = mctp_pktbuf_alloc(len);
+	pkt = mctp_pktbuf_alloc(&test->binding, len);
 	assert(pkt);
 	memcpy(mctp_pktbuf_hdr(pkt), buf, len);
 	mctp_bus_rx(&test->binding, pkt);