From: "Damien Riégel" <damien.riegel@silabs.com>
To: greybus-dev@lists.linaro.org, Johan Hovold <johan@kernel.org>,
Alex Elder <elder@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org
Cc: "Silicon Labs Kernel Team" <linux-devel@silabs.com>,
"Damien Riégel" <damien.riegel@silabs.com>
Subject: [PATCH v3 09/14] greybus: cpc: acknowledge all incoming messages
Date: Thu, 12 Feb 2026 09:43:47 -0500 [thread overview]
Message-ID: <20260212144352.93043-10-damien.riegel@silabs.com> (raw)
In-Reply-To: <20260212144352.93043-1-damien.riegel@silabs.com>
Currently, CPC doesn't send messages on its own, it only prepends its
header to outgoing messages. This can lead to messages not being
acknowledged, for instance in the case of an SVC Ping
Host Device
SVC Ping (seq=X, ack=Y)
SVC Ping Reply (seq=Y, ack=X+1)
The "Ping Reply" is never acknowledged at the CPC level, which can lead
to retransmissions, or worst the device might think the link is broken
and attempt to recover.
To prevent that scenario, an ack mechanism is implemented in the most
straightforward manner: send an ACK to all incoming messages. Here, two
flags need to be added:
- First, a flag is needed to differentiate between pure CPC frames,
that are only meaningful at the CPC level, and regular Greybus
operations. This flag is called "CONTROL". Currently there is only
one type of control frame, the standalone ack. Control messages have
the same format as Greybus operations.
- Second, ack themselves should not be acked, so to determine if a
message should be acked or not, a REQUEST_ACK flag is added.
Signed-off-by: Damien Riégel <damien.riegel@silabs.com>
---
Changes in v2:
- add missing cpu_to_le16 conversion when setting message size
drivers/greybus/cpc/cpc.h | 3 ++
drivers/greybus/cpc/cport.c | 1 +
| 41 +++++++++++++++++++++++++
| 3 ++
drivers/greybus/cpc/protocol.c | 55 +++++++++++++++++++++++++++++-----
5 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/drivers/greybus/cpc/cpc.h b/drivers/greybus/cpc/cpc.h
index 87b54a4fd34..725fd7f4afc 100644
--- a/drivers/greybus/cpc/cpc.h
+++ b/drivers/greybus/cpc/cpc.h
@@ -51,6 +51,9 @@ struct cpc_skb_cb {
struct gb_message *gb_message;
u8 seq;
+
+#define CPC_SKB_FLAG_REQ_ACK (1 << 0)
+ u8 cpc_flags;
};
#define CPC_SKB_CB(__skb) ((struct cpc_skb_cb *)&((__skb)->cb[0]))
diff --git a/drivers/greybus/cpc/cport.c b/drivers/greybus/cpc/cport.c
index 7041a6a8a36..847cc8ebe41 100644
--- a/drivers/greybus/cpc/cport.c
+++ b/drivers/greybus/cpc/cport.c
@@ -91,6 +91,7 @@ int cpc_cport_transmit(struct cpc_cport *cport, struct sk_buff *skb)
mutex_lock(&cport->lock);
CPC_SKB_CB(skb)->seq = cport->tcb.seq;
+ CPC_SKB_CB(skb)->cpc_flags = CPC_SKB_FLAG_REQ_ACK;
cport->tcb.seq++;
ack = cport->tcb.ack;
--git a/drivers/greybus/cpc/header.c b/drivers/greybus/cpc/header.c
index 62946d6077e..8875a6fed26 100644
--- a/drivers/greybus/cpc/header.c
+++ b/drivers/greybus/cpc/header.c
@@ -3,8 +3,25 @@
* Copyright (c) 2025, Silicon Laboratories, Inc.
*/
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+
#include "header.h"
+#define CPC_HEADER_CONTROL_IS_CONTROL_MASK BIT(7)
+#define CPC_HEADER_CONTROL_REQ_ACK_MASK BIT(6)
+
+/**
+ * cpc_header_is_control() - Identify if this is a control frame.
+ * @hdr: CPC header.
+ *
+ * Return: True if this is a control frame, false if this a Greybus frame.
+ */
+bool cpc_header_is_control(const struct cpc_header *hdr)
+{
+ return hdr->ctrl_flags & CPC_HEADER_CONTROL_IS_CONTROL_MASK;
+}
+
/**
* cpc_header_get_seq() - Get the sequence number.
* @hdr: CPC header.
@@ -15,3 +32,27 @@ u8 cpc_header_get_seq(const struct cpc_header *hdr)
{
return hdr->seq;
}
+
+/**
+ * cpc_header_get_req_ack() - Get the request acknowledge frame flag.
+ * @hdr: CPC header.
+ *
+ * Return: Request acknowledge frame flag.
+ */
+bool cpc_header_get_req_ack(const struct cpc_header *hdr)
+{
+ return FIELD_GET(CPC_HEADER_CONTROL_REQ_ACK_MASK, hdr->ctrl_flags);
+}
+
+/**
+ * cpc_header_encode_ctrl_flags() - Encode parameters into the control byte.
+ * @control: True if CPC control frame, false if Greybus frame.
+ * @req_ack: Frame flag indicating a request to be acknowledged.
+ *
+ * Return: Encoded control byte.
+ */
+u8 cpc_header_encode_ctrl_flags(bool control, bool req_ack)
+{
+ return FIELD_PREP(CPC_HEADER_CONTROL_IS_CONTROL_MASK, control) |
+ FIELD_PREP(CPC_HEADER_CONTROL_REQ_ACK_MASK, req_ack);
+}
--git a/drivers/greybus/cpc/header.h b/drivers/greybus/cpc/header.h
index 5196422380e..19612012b19 100644
--- a/drivers/greybus/cpc/header.h
+++ b/drivers/greybus/cpc/header.h
@@ -38,6 +38,9 @@ struct cpc_header {
__u8 ack;
} __packed;
+bool cpc_header_is_control(const struct cpc_header *hdr);
u8 cpc_header_get_seq(const struct cpc_header *hdr);
+bool cpc_header_get_req_ack(const struct cpc_header *hdr);
+u8 cpc_header_encode_ctrl_flags(bool control, bool req_ack);
#endif
diff --git a/drivers/greybus/cpc/protocol.c b/drivers/greybus/cpc/protocol.c
index 8f0ac6dfa11..97db70a53b0 100644
--- a/drivers/greybus/cpc/protocol.c
+++ b/drivers/greybus/cpc/protocol.c
@@ -9,6 +9,11 @@
#include "header.h"
#include "host.h"
+static bool cpc_skb_is_sequenced(struct sk_buff *skb)
+{
+ return CPC_SKB_CB(skb)->cpc_flags & CPC_SKB_FLAG_REQ_ACK;
+}
+
void cpc_protocol_prepare_header(struct sk_buff *skb, u8 ack)
{
struct cpc_header *hdr;
@@ -20,26 +25,62 @@ void cpc_protocol_prepare_header(struct sk_buff *skb, u8 ack)
hdr->ack = ack;
hdr->seq = CPC_SKB_CB(skb)->seq;
+ hdr->ctrl_flags = cpc_header_encode_ctrl_flags(!CPC_SKB_CB(skb)->gb_message,
+ cpc_skb_is_sequenced(skb));
+}
+
+static void cpc_protocol_queue_ack(struct cpc_cport *cport, u8 ack)
+{
+ struct gb_operation_msg_hdr *gb_hdr;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(struct cpc_header) + sizeof(*gb_hdr), GFP_KERNEL);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, sizeof(struct cpc_header));
+
+ gb_hdr = skb_put(skb, sizeof(*gb_hdr));
+ memset(gb_hdr, 0, sizeof(*gb_hdr));
+
+ /* In the CPC Operation Header, only the size and cport_id matter for ACKs. */
+ gb_hdr->size = cpu_to_le16(sizeof(*gb_hdr));
+ cpc_cport_pack(gb_hdr, cport->id);
+
+ cpc_protocol_prepare_header(skb, ack);
+
+ cpc_hd_send_skb(cport->cpc_hd, skb);
}
void cpc_protocol_on_data(struct cpc_cport *cport, struct sk_buff *skb)
{
struct cpc_header *cpc_hdr = (struct cpc_header *)skb->data;
+ bool require_ack = cpc_header_get_req_ack(cpc_hdr);
u8 seq = cpc_header_get_seq(cpc_hdr);
bool expected_seq = false;
+ u8 ack;
mutex_lock(&cport->lock);
- expected_seq = seq == cport->tcb.ack;
- if (expected_seq)
- cport->tcb.ack++;
- else
- dev_warn_ratelimited(cpc_hd_dev(cport->cpc_hd),
- "unexpected seq: %u, expected seq: %u\n", seq, cport->tcb.ack);
+ if (require_ack) {
+ expected_seq = seq == cport->tcb.ack;
+ if (expected_seq)
+ cport->tcb.ack++;
+ else
+ dev_warn_ratelimited(cpc_hd_dev(cport->cpc_hd),
+ "unexpected seq: %u, expected seq: %u\n",
+ seq, cport->tcb.ack);
+ }
+
+ ack = cport->tcb.ack;
mutex_unlock(&cport->lock);
- if (expected_seq) {
+ /* Ack no matter if the sequence was valid or not, to resync with remote */
+ if (require_ack)
+ cpc_protocol_queue_ack(cport, ack);
+
+ if (expected_seq && !cpc_header_is_control(cpc_hdr)) {
skb_pull(skb, sizeof(*cpc_hdr));
greybus_data_rcvd(cport->cpc_hd->gb_hd, cport->id, skb->data, skb->len);
--
2.52.0
next prev parent reply other threads:[~2026-02-12 14:44 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-12 14:43 [PATCH v3 00/14] greybus: introduce CPC as transport layer Damien Riégel
2026-02-12 14:43 ` [PATCH v3 01/14] greybus: cpc: add minimal CPC Host Device infrastructure Damien Riégel
2026-02-12 14:43 ` [PATCH v3 02/14] greybus: cpc: introduce CPC cport structure Damien Riégel
2026-02-12 14:43 ` [PATCH v3 03/14] greybus: cpc: use socket buffers instead of gb_message in TX path Damien Riégel
2026-02-12 14:43 ` [PATCH v3 04/14] greybus: cpc: pack cport ID in Greybus header Damien Riégel
2026-02-12 14:43 ` [PATCH v3 05/14] greybus: cpc: switch RX path to socket buffers Damien Riégel
2026-02-12 14:43 ` [PATCH v3 06/14] greybus: cpc: introduce CPC header structure Damien Riégel
2026-02-12 14:43 ` [PATCH v3 07/14] greybus: cpc: account for CPC header size in RX and TX path Damien Riégel
2026-02-12 14:43 ` [PATCH v3 08/14] greybus: cpc: add and validate sequence numbers Damien Riégel
2026-02-12 14:43 ` Damien Riégel [this message]
2026-02-12 14:43 ` [PATCH v3 10/14] greybus: cpc: use holding queue instead of sending out immediately Damien Riégel
2026-02-13 6:44 ` kernel test robot
2026-02-12 14:43 ` [PATCH v3 11/14] greybus: cpc: honour remote's RX window Damien Riégel
2026-02-13 21:56 ` kernel test robot
2026-02-12 14:43 ` [PATCH v3 12/14] greybus: cpc: let host device drivers dequeue TX frames Damien Riégel
2026-02-12 14:43 ` [PATCH v3 13/14] greybus: cpc: add private data pointer in CPC Host Device Damien Riégel
2026-02-12 14:43 ` [PATCH v3 14/14] greybus: cpc: add CPC SDIO host driver Damien Riégel
2026-02-13 0:31 ` kernel test robot
2026-02-13 9:35 ` Jérôme Pouiller
2026-02-13 16:00 ` Damien Riégel
2026-02-19 14:38 ` Damien Riégel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260212144352.93043-10-damien.riegel@silabs.com \
--to=damien.riegel@silabs.com \
--cc=elder@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=greybus-dev@lists.linaro.org \
--cc=johan@kernel.org \
--cc=linux-devel@silabs.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®