From nobody Mon Sep 28 16:22:44 2026 Received: from mail-pg1-f179.google.com (mail-pg1-f179.google.com [209.85.215.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A1CA23E0C58 for ; Thu, 20 Aug 2026 09:26:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787217973; cv=none; b=AjaIlts44IIGMhR8NXl8anDHosFCSG55lAMy+P478ZGqYnI3EcSQMJ7ZFZ0N3yEPwMVBrAwrIhnktvCb8MgGzB/qJSXklYmKbGblFGSm2RmCkmcWGca6HtPgztHLDchjD6rdFuP3rhNQet+8MF+rEt2B3eZcqz/xiKn0uTSfqsc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787217973; c=relaxed/simple; bh=3v8CbSbKdFVV/RjS8CpC/g5rvbPZ6MrtTulOIvBnDLU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RtgBgG+I0dgOi/SUdipHNLdBlhCX8q2XPFIOjGaECdA1cGJ+PbDad9rnq0LhSJjYdQI1OJZGG6TvXwm4FM25pdcreYY6HG81yHqX18+QprxwT3jPNmVp0wEa9aELwmDEKd1mbm9R6gq7BgKMUs5TcvplZsH0l33uEZwk8SSAR7M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=jrE1Au7U; arc=none smtp.client-ip=209.85.215.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="jrE1Au7U" Received: by mail-pg1-f179.google.com with SMTP id 41be03b00d2f7-cbedda4c154so929510a12.1 for ; Thu, 20 Aug 2026 02:26:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787217966; x=1787822766; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=xzjBZTtu53iWfTHftmKggPYuL4K3uk7JwnFJe0vNmS0=; b=jrE1Au7UIuqUWYwSAgGzCN8kNsWAcORNfod6US5g6hdgcCi+aBsrKUBGf7X/MMn+sK p4ZSYKYI7WI8SCGxmZrERg8yEFA0htUjH/ElIpuvHP1KKrJGpatjPE2kIRChCTve5kbP YdBk06roHFVQhB7WVOpBup96CKHUUrKcL6hLzDuzhqDO+r3xVSx8H23em+cZbS5Qz1k/ TN+IUZl3Qxa5oTIv5J8KCt9m5RebJx9QB/xeWKVMMcio0evTRyhGA06BGRGn8fAQUvHB 974/lLy8Hv7BIXywpc17KgCZHrEXBzdKqkhPCjxqlFaII8Ye7dNsnA7HFc1Mjjdljsp2 XSyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787217966; x=1787822766; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=xzjBZTtu53iWfTHftmKggPYuL4K3uk7JwnFJe0vNmS0=; b=fT2w/ec6X5D/zZPcjZjsMUU9j6k12HKAJUokqOsiC97EnaqLq5o7Tbh+zUqfiQSar5 Lcm+iuDAp8e0/7LE5J+Nx0Bid1DpBjO0c88qef4kvdgj8ogWQIe7eov6Nrfa297p57Uu gLtupfB/w+muWr0QCctr0LsHQTYVNzSy2s4PWl+PSkTq3TwqpzRniCgklKO75DwMjwLS V7UHQ1B5rdUvJ/bqb45ndalCOfX4zcE/3a79Q8i6UFTVyvb96M50wiKGv90sfLDthfh1 XaWLdDUYmU+YFQ2127uu6mIipSqDCcK4fWf/XbKrQq+/uKtLZR7QkpOHoRut0VerbO4i AiQA== X-Forwarded-Encrypted: i=1; AHgh+RoPy7aRQRwbDYGORSjfZxlf8SG7QArn99cjPXxO4iigVkEl/5d9WL46iaYUvPsL8YCmW7/+hR1rnzbQa1g=@vger.kernel.org X-Gm-Message-State: AOJu0YwAkYezwTBgr+CyKtYrPCcHw4xBgjn1t8s6OkFyhAJMMIH1k1Zb vxxiB4qwudkZcPTONQrlKp8bVJw5h608Q+K4OuyaXMB/SrYVG8XXxNlBK5LFR7CseQ== X-Gm-Gg: AR+sD113lrUqOc6rOB3Ojs61j/3k3K7+yEO4QnVTA9EeFCCseh+h5di3IhmHJLjYtx4 W6bACjUMFyRM/NHEIIvaKuXfWk07bYZJeMGANFcjQUNRJrGCi9aWuxmsj8O0PyqYFFHKGiHK+Q2 LEEKA7qQ1GRcWcu67QHGXW67lnJYtpllMuTiccUpMLsCzPAIpa3iSbLNj+ToPnXwOXYP7qP7cZi YsKH9avExEXazDPpTCr/jIRO/UVmqUvK5ncMHEI7nKH2BZcQkTcYxEAJsBAvYJEl0wD5j3jfXNA daKazFLkOet7ZiGufdIOqXByjDE5agMWrN7l+bbWNSW/Nj9b2lYcWjl+f7SLcG3hW1uBCo1z4jM PaU6caqUGp4vvFVyrQiJIFnbbd264vikOwuMWoJeMO/mTijuELmB8TMR+BT5S9sQB0yuTs3PR0/ xt04y7iX9y1dMsRtJy56QJKM3JHlou75q9O4uTtNRXQ8MOAMblpgBcCFyVIfCbmgiIqf9tHXM= X-Received: by 2002:a05:6a20:3ca1:b0:3c3:66c5:68d6 with SMTP id adf61e73a8af0-3cd00f77410mr20716026637.9.1787217965814; Thu, 20 Aug 2026 02:26:05 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.25.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:05 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:43 +0530 Subject: [PATCH 1/7] greybus: connection: Export gb_connection_get() and gb_connection_put() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-1-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2142; i=ayush@beagleboard.org; h=from:subject:message-id; bh=3v8CbSbKdFVV/RjS8CpC/g5rvbPZ6MrtTulOIvBnDLU=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgcsGXsXSPB7SXci9/gMJrvKggOA203vrKBM soP+2HaYsqJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHAAKCRAFzvXHieVa dEdiEACWq18kE7iI+UXzmz+hA/pJvhpAA4AaqDxNGkfh/85AAI+4vtEkocPh8pN2lMFEPZY2Wpw fcBkT88GupqSEJOqjq603FuN15iH0mpbpIBqHdSZiddqlWT1VcFcIQlLRjs4Wf03n/Axqvvx8HS 83fvE7JcXHeo1SOVBAaIgWmS4Gx4vjHT82yLvYVn69M/gmQcy3XHbUDjJqvevjWAUqrS1z7/XTA dFh1NHDUC4F0rdv7A7yIFIOXJz9m/6Fj5U2tH77yqH5jL+2Q8duQkQOBIgUOeZ2iHF6GMfQNsmT FAbltVef/eV37V7aAlwvdwJkL5P7viP776sUt1pl421yvjdbnH4IuOaKRi81uTltnJPoGIRS6O2 pTIC3Wu/cnS6x4DIjdmFJou6ThaEIZn80ucHDpB7xCKmBHLl1PifImdKA6VZhJCN8SATJjHGAq5 9Yr5dwlrC87firFBxtQYeBqPpucQsWlsb6RBfRi9sp9PGHUwSr28JHqNpChqGXlrJFIOb5TqfN9 9bB9w0ErZgTmfhr66sQU7+j4Xtsz+rtXx84s0GKCNymCtnndaznUcnGKCrb119Qpuu3/BdAOFMv c04gCdL5nKzj4hVP5SH2Hq6Z85S5q/QP3nU98bycEmOrDGUdslNXNxQMqoPiFPL7ZcDQFTkT5NY ca5dS2Jjqof9QNg== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 gb_connection_get() and gb_connection_put() are currently private to the core. Drivers that hold a connection reference obtained from a lookup helper need to be able to drop it, and drivers that cache a connection pointer need to be able to take one. Make both functions non-static, declare them in the greybus connection header, and export them so modular drivers can manage connection references. The first user is Rust greybus abstractions, added later in this series. No functional change. Signed-off-by: Ayush Singh --- drivers/greybus/connection.c | 6 ++++-- include/linux/greybus/connection.h | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/greybus/connection.c b/drivers/greybus/connection.c index bd04485decb3..f8fda22bc466 100644 --- a/drivers/greybus/connection.c +++ b/drivers/greybus/connection.c @@ -33,19 +33,21 @@ static bool gb_connection_cport_in_use(struct gb_interf= ace *intf, u16 cport_id) return false; } =20 -static void gb_connection_get(struct gb_connection *connection) +void gb_connection_get(struct gb_connection *connection) { kref_get(&connection->kref); =20 trace_gb_connection_get(connection); } +EXPORT_SYMBOL_GPL(gb_connection_get); =20 -static void gb_connection_put(struct gb_connection *connection) +void gb_connection_put(struct gb_connection *connection) { trace_gb_connection_put(connection); =20 kref_put(&connection->kref, gb_connection_kref_release); } +EXPORT_SYMBOL_GPL(gb_connection_put); =20 /* * Returns a reference-counted pointer to the connection if found. diff --git a/include/linux/greybus/connection.h b/include/linux/greybus/con= nection.h index d59b7fc1de3e..b53aad2270d6 100644 --- a/include/linux/greybus/connection.h +++ b/include/linux/greybus/connection.h @@ -128,4 +128,7 @@ static inline void gb_connection_set_data(struct gb_con= nection *connection, connection->private =3D data; } =20 +void gb_connection_get(struct gb_connection *connection); +void gb_connection_put(struct gb_connection *connection); + #endif /* __CONNECTION_H */ --=20 2.55.0 From nobody Mon Sep 28 16:22:44 2026 Received: from mail-pj1-f53.google.com (mail-pj1-f53.google.com [209.85.216.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D0E6B3E7141 for ; Thu, 20 Aug 2026 09:26:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787217986; cv=none; b=tXRFhNVrcDbsCIR4zxAIfEPEWEvaphGjoKXaDMXAdLK6jNE67BF09LV1X7E6uhrWbnPC06+jvQqX05cGd3Qzh8ldwQDmvXPVVxn1zl7W+4WU/roHIYyzLt+Cro5BntkC9v3ZUdDaV5We8Ksn3tHSzJWJubEWdv/AWLREVOI0k8M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787217986; c=relaxed/simple; bh=6FWZ4CXrC3IC3UxJkblN8Q7DcfXAsxDSRH5/oQe6mig=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KFNgLM37pV6FRj5m1+vaRzcmbcAGP6KFVQSX0cDE82pvzoyUkt5sDJxyrwE0U33sur935O08lzbCthZgMBBqwhC3BCjvdWSAysmlqQCAXv3yowpWiGEy5t3/zTqaNXWII2nOU07o1rGdOusBIc5AJuh0X9CzYTokG1Ig+9gkEGQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=cU4FvBSM; arc=none smtp.client-ip=209.85.216.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="cU4FvBSM" Received: by mail-pj1-f53.google.com with SMTP id 98e67ed59e1d1-3811f512167so2829042a91.3 for ; Thu, 20 Aug 2026 02:26:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787217974; x=1787822774; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=cW0TGNliGRgRHinSfGnJ0XJ0b5NU2E5kFB50csiZw9M=; b=cU4FvBSMrwiBxsXmcYA/92P5EjnRgSqvA3peJrpd4rIc2c/zlpe8SjC1B2uKaeO59C Ah+KLJD2EcH/FMOwhUx/wW2c/ihfmSe0TJHKH8GrzevFrH7nRKFMhzA+f6aLBAg2PAEI cEEOgq5fdYMr6ZKExvaFij3KEPg4p8cdfXM3zX4WBRUN/wW5ayX16hG3LmT8DmWGd7PQ 472pPQ9MCgxzEK4tB4pUGkrYqo5ueebh+SyZaINqO1snUR0E3iNMfyMq8IGiN3hIaIUB MJpgSf0SjCa4y6aBp4YfMiD3sxiSRPMVSAgDuLMajJlyuGNEXSLPZZvW1EQQgDyEgvXN kJfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787217974; x=1787822774; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=cW0TGNliGRgRHinSfGnJ0XJ0b5NU2E5kFB50csiZw9M=; b=C83nat/Iq5MY6twhNqrhaT2vpxfVblUKb/egJ4Q377KdBg+ArN+iqIQgQNMytQsAxg zbfa64m8dY5UBt89+kATamIn/BuF5sHcyph6vEMlcMqODJ5D+8aTQUFxOdBMtxmtdyfc F1dNlVLQHTQEGYHmI7w8MXBbX0fUT9BgQZHBnPV2Y+DwACGAgJ+AVSFvMvj+XCjh6xn8 cpPHj1Rr2RLGc61siNyD+MIeH6sTi24jmBsOke1M4t/j9svhL220yaXzDGrK5HlZXkem b8RL9qybY/ThKM7EIXUrHoCtomXVYldjtWJE3AFDz2EAcSPcgqoGjhdDaKA+8NXvBomW Rkkw== X-Forwarded-Encrypted: i=1; AHgh+RrIigzx3x9TFE4MybVXOojm93sKuresIyfqXLns5Yg4cF5g5xURfwYrdxE2TDKcrCqsYrY0RsZM0UIK/Ro=@vger.kernel.org X-Gm-Message-State: AFuF++kfQKiinPUixgoxW8Bwn2kpMHyXdUQ5OQnBW5xTH/v1arMn3Dtg jR8KgWdk6TRS+GPqjeHPsi+6+CQFaAjX7coWF0LmROkyZrIeZKLSXxoHYHMPKc0tBg== X-Gm-Gg: AR+sD107cC5f4QgNVz+VCAVYo9Weo1MC2cIfznIBi7NvRK02VaPLCzrZEOFxargsOSu Aj4F9bzkhFecJKCRRM+u+sLfUbF6u6y6nLJF3Fkk2zBsC7JXLlkI9WFqvH+DUYRMB2MTbPFZ1g/ KfW/ItC6HEjBF3PyfUWiRSJ9JBAasORQia9ztiIiPAHQhn+MTHu+RDa+EUO0A10bgZXeoEVkjOl FpZJBXXTRibnq9Y5+JSNWlBWKj1JZiXTCsOYVo5LAMSSQbgtKFQ5ZC+BgjIRjALerhNVsBgNMAz rZdjrVAa1qwGiUnMlP1RPJ1C1QC43hLXggI1qdY012ErPUG+peJuzHbtR10+e5krofs9D+HGR/p rsaF7alVnEOx1IomxNKlzlvacvgZ/LrKZ9I8hOjG5QiLBsTa7s83lvvqTnLuBNnLhulG9NmDWjN nT9Be9UAAzqkab6If2AwCwj0nQWz9A1oyw5MNDPOodMhNadVgw1VExdim3ZKM6O6fgLmBQ814= X-Received: by 2002:a17:90b:544f:b0:381:152b:d596 with SMTP id 98e67ed59e1d1-3958108a4b0mr21950129a91.11.1787217974316; Thu, 20 Aug 2026 02:26:14 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.26.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:14 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:44 +0530 Subject: [PATCH 2/7] greybus: connection: Add gb_connection_hd_find_by_intf() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-2-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2390; i=ayush@beagleboard.org; h=from:subject:message-id; bh=6FWZ4CXrC3IC3UxJkblN8Q7DcfXAsxDSRH5/oQe6mig=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgczHXrqaZlvmoyFYXnGxoC8dnp2zg1Ri0jd JgP8jvepayJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHAAKCRAFzvXHieVa dI9ID/4qUt8idxVlT1iSbVUvHo/2lFcqC+y1DXdyEaW2PdRkza7VruIwciXjiG6N7KtVNGpLeQl b6vfdN4mEm36VdJZVhWMr45v1hTv0eNQbtYGig3CnCO+BMSyLaiZqMZReVY3ATAQpq/m8zWcLny YrFeNSl+mBOQkzDp4G53qBEY1lV6E4DfP7rjWwzTCZ2HyCy8/ilSe70P2EQzQgICTBeX7rXbXU8 Rk2O5Y0/wigAbF0Q7HH8xklk6lWzHzzVVI5QowLo80aHy61tpw6T0afD4/PyG9LSCQ/lVI/JpqP TJlGTt/52+ivF3DTUQYgnMqIx3syr9DGvYpuCUTQdWxLYkrMUraYpVaz0GtHDCvhqAEEI6fuKVV APrEsHkAtKB00aLSNeSPRJ/VFKgeJFgEZkPQvCVR6C5QfwBvsrGXGSaEwTxAFqbaqY9a4MvB9XV +E3FLzAs/wFTb9TBxH9pAYgKg6300sYmZTnqjXpswVFcrIVqp1Ulb2Umh1vbCj1QANlzUiYsps1 2+gb5Pc2seYoWTeCt/9mbdyoryj25sKRXDiAl35WPRUiKDcPN2ClifW0y5u0Lo52Pin6vGKRKvP yqwP4m9ZkQZidP3rH4R/GAymLLauTTdZLUgL/J4suT0m1UrRFZu61Zb0I+HYQLYqsaR6Xa7r7kg UbZyAiyUYq3lPKQ== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 gb_connection_hd_find() looks up a connection on a host device by its host-side CPort id. Callers that only know the remote end of a connection (the interface id and the CPort id) have no way to find it. Add gb_connection_hd_find_by_intf(), which walks the host device's connection list and returns a reference-counted pointer to the matching connection, or NULL if there is none. The caller is responsible for dropping the reference with gb_connection_put(). The first user is gb-softsvc driver, added later in this series. Signed-off-by: Ayush Singh --- drivers/greybus/connection.c | 22 ++++++++++++++++++++++ include/linux/greybus/connection.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/drivers/greybus/connection.c b/drivers/greybus/connection.c index f8fda22bc466..262161fa4721 100644 --- a/drivers/greybus/connection.c +++ b/drivers/greybus/connection.c @@ -71,6 +71,28 @@ gb_connection_hd_find(struct gb_host_device *hd, u16 cpo= rt_id) return connection; } =20 +struct gb_connection *gb_connection_hd_find_by_intf(struct gb_host_device = *hd, + u8 intf_id, u16 intf_cport) +{ + struct gb_connection *connection; + unsigned long flags; + + spin_lock_irqsave(&gb_connections_lock, flags); + list_for_each_entry(connection, &hd->connections, hd_links) { + if (connection->intf->interface_id =3D=3D intf_id && + connection->intf_cport_id =3D=3D intf_cport) { + gb_connection_get(connection); + goto found; + } + } + connection =3D NULL; +found: + spin_unlock_irqrestore(&gb_connections_lock, flags); + + return connection; +} +EXPORT_SYMBOL_GPL(gb_connection_hd_find_by_intf); + /* * Callback from the host driver to let us know that data has been * received on the bundle. diff --git a/include/linux/greybus/connection.h b/include/linux/greybus/con= nection.h index b53aad2270d6..589721d46015 100644 --- a/include/linux/greybus/connection.h +++ b/include/linux/greybus/connection.h @@ -131,4 +131,7 @@ static inline void gb_connection_set_data(struct gb_con= nection *connection, void gb_connection_get(struct gb_connection *connection); void gb_connection_put(struct gb_connection *connection); =20 +struct gb_connection *gb_connection_hd_find_by_intf(struct gb_host_device = *hd, + u8 intf_id, u16 intf_cport); + #endif /* __CONNECTION_H */ --=20 2.55.0 From nobody Mon Sep 28 16:22:44 2026 Received: from mail-pj1-f48.google.com (mail-pj1-f48.google.com [209.85.216.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C37E3EFD02 for ; Thu, 20 Aug 2026 09:26:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787217996; cv=none; b=RCTy5XEFHmJqrMt8evHJuRsumW0kQSQH4tTay8vAe56jhKLi+yTReEETUF60PEBBdD7BFONUg1zWaT6uMX9O7YGemVzR4WWE3kbD4HUEvxLvVhAVpceJtnICM8WDTrgrCX/aeUrB4o+O9W4unN3zimVf/iRI4A97lP8sDUl+zpQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787217996; c=relaxed/simple; bh=qF6QJG+x2F3MFGOzlWWgsKKJxbY3kfRztIUvB4yU9lY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uUwWSkCzYfeU9of1n250fFLMwV/gtFAG+IC/dgXlUc7+9MEiDrjMvcPdv/5lT1Xd2yzuMG0rHAMVeHKL6zkodLQawj4d1fu7spFMSbeXpZA6MzdUo3vpljHR1EJj9qz9M+/nzzJ7+8j7S4h63WIBeRx30cx7eu4Hlz63U8xDie0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=VFcGkKUR; arc=none smtp.client-ip=209.85.216.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="VFcGkKUR" Received: by mail-pj1-f48.google.com with SMTP id 98e67ed59e1d1-38deea72eebso2056937a91.1 for ; Thu, 20 Aug 2026 02:26:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787217983; x=1787822783; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=P2rVwkPkMhDUTtHvPL9LuODXAGIutmblUUDkUxchgbg=; b=VFcGkKUR7iyL/G91pR0sHWIY6EJpSUuwYVyZNLMn46Zib0km0Iz8tSYYB+87/g/EA8 4glxbcoIsfhYfgKJz1LVGwLgd0coOxpapYIbEklxtbiPpdEWWBjLJhvH3/8FZsLs58fL iw+iRT2A5yd57xTHnSRsBogCcLxHWQzi1243P6kN1PVDTJrV+ge8dsz0S2v/rVknwqPG cfU31WXRTP3DUwl9iGeWlxP2wfWDT8aIyJq1C3qkUJ/YwkS5G7PPplXc/eGoaQuBU7qB JrKIEPcsR4sFSE9KgTZyeWF3uqwi1uIgad57gWqTdasleKkAH49Znxn9tih9Ym7v9HU/ jJcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787217983; x=1787822783; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=P2rVwkPkMhDUTtHvPL9LuODXAGIutmblUUDkUxchgbg=; b=R7tr4PawQwy+E/gPtHqeUcKayFW5lzmfgu8hyrg9EVI0FuWg1jiKkhKZY4GWtopiUX 9P/CoCR8K9CY5ijVAEBWQMkgZbgFkRu2ISsyNOvvLypLyE5Bb4wDeKc26HcpGhuuhGlX t0Ni3ZBJdF3ShQIJkftAJtU+tZdL9QCDgQXYsIgLdYItLaHtiZxdc4P+Esu6x0FIoWNF XdmMJKm8C4utlmynXYUK4LbrvemEYhZI17QL07YRkfAaGkmq7kdm2f+k924TFjkv/jn5 ZRHcqgjXQaN9CtodZ0rq/e7YzRv9wNFy91m5hxuBd7Fk6amRId/ApFhoPeoZRjD9iKsL yVGg== X-Forwarded-Encrypted: i=1; AHgh+RpqA/jDuz8LQcLD+OAoTkIaPfPKxg+TLR0SjLcEEC3gURMalqpJ+ukVIX8HaFh5XhSkuQ8wFJcwi8SJrCc=@vger.kernel.org X-Gm-Message-State: AFuF++mOaJJG3lRkbWJ2yczR4L/wEnS/7KgO0osmgdQAOKk/RjKF+EkT VWwhvqlu0TqIEn+XDNSmzhVHRVyzJo95gs2zASmnq5Uxyquz/dtYhlPGHx1pL/4m+Q== X-Gm-Gg: AR+sD132J5FxVhoJHLk6T+4M5ICrDwroFLIGWjKkqb6sTJZP+vevcAczzfKV3goDCNo ULJWQz4JbsY8FEsWzYe5q11m06YnOFAdw1grTePM+dGIRe5fU6Ty1Zip3vbc9NzqrKA3UagGG+9 K2psIcAQDNnmyj06XvdOBw7vDy5gO32pOEbQ9SBo5lEoh9AgO4Uij8CTKMgDBpNmE3UAnhoWv08 GGogBXWeGIgQbEQs1TrNtbPijaqV41J461N9D4JTQhJXfBF7E2aqDGvg9qjWrlrwch7tlCJS5oV b5HnqNqUVMzBZQWAGBwEs3auojuq1Z9oD01QW9fa/dC3KDVbk7Qq5xAnyt02ioMxbz3sFs8Kel3 KV6vU67kXJJyjC8+UHAkJx+ikk8Ws4PetfORY4Hx6/QvOTcTY6851PVsx9p6JC5dZP1i1CcfNOQ SeZ4yPwMQf76a3htckxtNrFGXPmUgFYWwzAy2MOjKLu8YTgMnHGCOUzGL8vC42ZD+UX10jPRVoV FOj5FFfpg== X-Received: by 2002:a17:90b:1804:b0:38f:dec8:f7e9 with SMTP id 98e67ed59e1d1-395810b5a15mr20049832a91.12.1787217982703; Thu, 20 Aug 2026 02:26:22 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.26.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:22 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:45 +0530 Subject: [PATCH 3/7] rust: crc_ccitt: add CRC-CCITT abstraction Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-3-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3258; i=ayush@beagleboard.org; h=from:subject:message-id; bh=qF6QJG+x2F3MFGOzlWWgsKKJxbY3kfRztIUvB4yU9lY=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgchxLFdpTnYyMaodyuVmlWP5VEW1HbtK7r+ aozb3AJ27+JAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHAAKCRAFzvXHieVa dGDrEACNRLj/fVXbdFOzhvcCj5oDgnno9GNFaye97zITV/IOHQGamlMtDEckqKlkH6+C587HS6R JrvOZ1Luf28bdEiksiaa4rYqDrp9/HJrWn9S75xlmxFYIFXJ1I+4hU0rfDXvLOSebHNrP6zgv4j 4HeePF08GOAUlGaO6vwUOIldAaQGywTxnJz5fsUj0TD+UT/YOJpC9j26sSmJSlsGGwD6Srfbyuu trBi45RVB8iQ2l4rLu17hU1DnzCEMHRhc+AmF3FyZ9T4sfI3aWUUaAiZVTpS6L83zxZfBqxluIb MclGV9hRSeceZpk6MxwPH2AZIGkz3nm/q4J77CP8mB4NFLIpvyhxXiwpbWB7+RZ2KpwvC1VIbUr aIlUFLQtnH6ZUWmjivWJHkhLD8MWQYJx6A1RjfvM88U3AcZVHBi97DF46NhoVkca+Kh6lXn7gSX LOOHHowCO4FV3KRbqGwuY0f1exuvYdFiUtA/qHC4CsbMiPk6ioaktdqAlAkEACfBz7jogglWRkN nglkdxmKNypeEdO23ptVuM2IoZM1GMi/qVUVD8vSWIs5Mk8LOl5MXE+c7us27aHTvAAVh0K4joz mbpK/o1TY/iS9yiOrT6IRG/yLEVmtmQP0WT926HXgEMx9NRpSKNcB4WjhMtNYPJuDcCCu5fdPpA BEgc1WyoP8oiHDQ== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 The module is gated behind the new RUST_CRC_CCITT_ABSTRACTIONS Kconfig symbol, which selects CRC_CCITT, so the C library is only built when a Rust user actually needs it. Signed-off-by: Ayush Singh --- MAINTAINERS | 1 + lib/crc/Kconfig | 7 +++++++ rust/bindings/bindings_helper.h | 1 + rust/kernel/crc_ccitt.rs | 26 ++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 ++ 5 files changed, 37 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6008f16ae2ca..1e3b42eff741 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6921,6 +6921,7 @@ T: git https://git.kernel.org/pub/scm/linux/kernel/gi= t/ebiggers/linux.git crc-ne F: Documentation/staging/crc* F: include/linux/crc* F: lib/crc/ +F: rust/kernel/crc* F: scripts/gen-crc-consts.py =20 CREATIVE SB0540 diff --git a/lib/crc/Kconfig b/lib/crc/Kconfig index 927fc6a6b2b9..aceb8fe8f0ed 100644 --- a/lib/crc/Kconfig +++ b/lib/crc/Kconfig @@ -32,6 +32,13 @@ config CRC_CCITT The CRC-CCITT library functions. Select this if your module uses any of the functions from . =20 +config RUST_CRC_CCITT_ABSTRACTIONS + bool "Rust CRC-CCITT abstractions" + depends on RUST + select CRC_CCITT + help + This enables the Rust abstraction for the CRC-CCITT API. + config CRC_ITU_T tristate help diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 24d659a87c1d..6eb3caaee497 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/crc_ccitt.rs b/rust/kernel/crc_ccitt.rs new file mode 100644 index 000000000000..6042ada16967 --- /dev/null +++ b/rust/kernel/crc_ccitt.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CRC-CCITT computation. +//! +//! C header: [`include/linux/crc-ccitt.h`](srctree/include/linux/crc-ccit= t.h) + +/// Computes the CRC-CCITT of `data`, starting from the seed value `crc`. +/// +/// Pass the result back in as `crc` to compute the checksum of a buffer +/// incrementally. +/// +/// # Examples +/// +/// ``` +/// use kernel::crc_ccitt::crc_ccitt; +/// +/// let one_shot =3D crc_ccitt(0xffff, b"hello world"); +/// let split =3D crc_ccitt(crc_ccitt(0xffff, b"hello "), b"world"); +/// assert_eq!(one_shot, split); +/// ``` +#[inline] +pub fn crc_ccitt(crc: u16, data: &[u8]) -> u16 { + // SAFETY: `data.as_ptr()` is valid for reads of `data.len()` bytes fo= r the + // duration of the call, since it is derived from a live shared slice. + unsafe { bindings::crc_ccitt(crc, data.as_ptr(), data.len()) } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3edc343caba5..45c4f4db51d2 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -61,6 +61,8 @@ #[cfg(CONFIG_CPU_FREQ)] pub mod cpufreq; pub mod cpumask; +#[cfg(CONFIG_RUST_CRC_CCITT_ABSTRACTIONS)] +pub mod crc_ccitt; pub mod cred; pub mod debugfs; pub mod device; --=20 2.55.0 From nobody Mon Sep 28 16:22:44 2026 Received: from mail-oo1-f52.google.com (mail-oo1-f52.google.com [209.85.161.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 16AFC3EDE6E for ; Thu, 20 Aug 2026 09:26:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218006; cv=none; b=PjPW6PyW3QLHms/EBVLW2QTOivC2WqXreLK1Twfer0/F6NDo1C5tcNr26CyPoSZpQH+BUDjk0a0OevxKqcy6WJUfNq3vL2NiYQ7Uafip/Mbp/+pDTFO/GJA2v/odlR29b3Qidlr53vR253Lk1FsSaTJAyq/bJHER2odZR9vb7sc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218006; c=relaxed/simple; bh=k+lc9ZjArLyn0xs/JyUXZ5i/tTLVgM14rXy6c/r2Xt0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PxEqM/H9cZjs6hBETv0mLLWKVCh7mBOwDOwg1XdQcf2A/ppwwuJPLc/iDmoi7ufBP4gCRxtkrg5nqs3oU+w6x27fP/im9YLR7+4swzMfkjpY41QaH7TwQ1WKerKdxyk0um1fvjgkeaH7a2xMmBgqLcPxNZuEFXlzzdKWog00ikA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=BAo0P6xl; arc=none smtp.client-ip=209.85.161.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="BAo0P6xl" Received: by mail-oo1-f52.google.com with SMTP id 006d021491bc7-6b12942ed04so1334395eaf.1 for ; Thu, 20 Aug 2026 02:26:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787217992; x=1787822792; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=x6Xqn6A+v4NtVPtasYhx0txX0CAO7mXeI1W1KVTASws=; b=BAo0P6xlTN6BrhcTHmdxAM5APbtt5q7QsLhR0cGlhJfUo2bVVs7y5quOLoFh5XT6PD oCtGzHT7oQMKd3aZ7mk0RW9juhOvs+/lHlJiO8MHlaTRJeKFgE4yLkyySz9FxtXJnVH6 oGW8LMVJHw0eHOSxkcG0TaI0UkPW96HkeAyLoCMvccLkZyVK0N0U64x+mlT7BgCV2zGM Czd7y7UIEeGR11Rylj4dOzZHneEt+2s23zM52jHG58Vo5BZS0o3ZhYLekmpoZNeMjGdU 84L/Af5Gnw2IAB2DKx+YFTnlbZVvYMs/I1QisMp7siUzODYESIBz/7/0if7tBUktU/7G ui7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787217992; x=1787822792; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=x6Xqn6A+v4NtVPtasYhx0txX0CAO7mXeI1W1KVTASws=; b=NVdx4hJyhi9M5qVZCLaM3EFN6u2x08eb0ngc0oon0U7S6CSmSjJnBgXZwzcXuaat85 7E3Yl/zG0yqfgaWoFFo9sYSxyD+CN5aCFuAktWq9bFXpldn6TxZ6sVzMDFkcWmg+GbnN qAwD7eVPMb1EWcHVPXpS5zuJ4VQ2qsS/lpLTReZNH4jdwnz7cwyai0hFJVEmdOh5LJp3 mryub0zFH0WeF2BpAv9ZQmaIG5zRmHf/kbIsnhSKlFYrAxrbbQ8U4kMHkx6bAk16Iu1u DY83QFWydkhIQD4hewsxHUR/pZgCvw+/NDkgyd45Gv5yVRfNQMRWm7+DLJ0NjlKd10hz RXVg== X-Forwarded-Encrypted: i=1; AHgh+RqIQ59rxrLTGgztZD4Z/f2YJFlJSAMSryVG0PVoBCjYSzNPpQ9OAuz+C/yikF0zJvppAAGVyI5mvOYvySM=@vger.kernel.org X-Gm-Message-State: AOJu0Yy9YoMAOJC3nSE0kQJWg1ghEkU8Oj1Xb4kYJDWk54PA59U31BPF el00AzipX2SUlNZzXYs6D5WoozGSgveECdLookunsHjHLyc8U2T9OWzrQm8iaQ2iNw== X-Gm-Gg: AR+sD12xDyNHMdm6Dya/Z8gp82rsz6d4RqUvB3ho8wI5pq0UA/sbzwnHvielMyNosqM 3me/oXDVOI/LLxzxzoYUPuW9sCdvW9cfnkAKya07RzawM/hhZpcCvghNAWb2M8QEUUHwo+i4FKy nk7TqrHI0HL3ioqhgliHa72YQz4hdzoosz3A2oQ5bmh2OcH4Az56fTlwQXtFP8nBPKhXtikpSwp yGRF7rev/gh4gZGMmVm60G9TH9NQ7295DIzccRRMZciV0q6ZKaNMujYfxmUfFnpm9rr4WUcOJMx Uwb6ohSpI5aMW0dGYLWfGJW46cax6j/1aV70y0QeNhfUeO2SSkjyrYk2BstP8/s9XlKrT9Dd5/6 NXAUmjJuz0R3xz39d29ZuwsOXyx4TWZC87Vn7QI2xDg74sOvsokQFcps3tbOq6hdICaViFGjxPj AHpPsm4qUS/p0wW7NgOPRSEHbvGLXParvqzS/tnFmGMvuKsTll3v1VAMtWtsPcQNmr9yjNy40= X-Received: by 2002:a05:6820:f02b:b0:6a3:7af2:90ef with SMTP id 006d021491bc7-6b13c2d6e0fmr9023543eaf.6.1787217991216; Thu, 20 Aug 2026 02:26:31 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.26.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:30 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:46 +0530 Subject: [PATCH 4/7] rust: kernel: Add greybus abstractions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-4-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=36880; i=ayush@beagleboard.org; h=from:subject:message-id; bh=k+lc9ZjArLyn0xs/JyUXZ5i/tTLVgM14rXy6c/r2Xt0=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgcsu//psaRgy+DsGnVxG7i0VtbEM9QBRSgj IHuqHx1mK2JAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHAAKCRAFzvXHieVa dEZnD/9QZ3nlMXVYV63oVov/wxgGGNYI0g4G1jQaPfgyqidakT+KhPbxFNO4E6H7gz58NDDX/kb YhgsiXvE8Xlwi3NkPa1Ja8sdf2c0MUT4VIDEzyeWKPajP/RaMAfpQB8smMT2gPvnsz6gKLRH6gh BQnoyoDgCEiP3mipywv8OCee+hMGm5qLVQMKfA8H65EbJUTfEviL/c/ddozzV48Ub9ddJ87UJ1v Gunb7ThJiDqIvCi+PxVU4CDvanVt5fmt1c5ges3AhNRbRgOI/dFvv1f7JE0gnMgkaR3LmlsLJ+T OPHN3tsrW5eHQi49DGUN/nNmyGRPaQUVDQFfKLSpOIOj0HVN1frAFoHze3Ol/SZRc+nS7qjGIV6 96knG/daPO/jIR7IIJSiy7KLUnsfLxSyCD+9x9uhceFFrMbdsmKFe12oNvdOfLKOxZN3v1sxqk1 rvrhDolvBjS4GmM2fX8164/HWV4bn6fG+ArkEYR1HQJi3epXQP10eKO6NTW1e9aAIG1NKRyfWeh 5XMxpgIEyaYqHEH1GUZgGulC6Ytlj/UL32BtXa3dmukcfU+Cj4CPaMDNx/b4/OEKTHMiGUVxOAj 6/NZNYeB0nLxP0oEF1mcW1WDWC57aQmIONHn62+QQwQCka1muVDp5kiXIiZa+fTldXHdw14j8EI /kZJ7h+HPrp3t6g== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 Add Rust abstractions for the Greybus core, enough to implement a Greybus host driver in Rust. The abstractions are split into 3 modules: - Top level mod.rs: Basic abstractions greybus structures. - hd.rs: Greybus Host Device specific abstractions. - protocols.rs: Abstractions for greybus_protocols.h, i.e. greybus protocol types and constants. Only the APIs used by gb-softsvc and gb-uart-node driver are covered. As such, protocols.rs also only contains abstractions for greybus structures that are used by SVC and some types such as Greybus Interface do not implement AlwaysRefCounted at the moment. Signed-off-by: Ayush Singh --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/kernel/greybus/hd.rs | 315 +++++++++++++++++++++++++++++++ rust/kernel/greybus/mod.rs | 230 +++++++++++++++++++++++ rust/kernel/greybus/protocols.rs | 392 +++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 2 + 6 files changed, 941 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1e3b42eff741..80247a031353 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11338,6 +11338,7 @@ F: drivers/greybus/ F: drivers/staging/greybus/ F: include/linux/greybus.h F: include/linux/greybus/ +F: rust/kernel/greybus/ =20 GREYBUS UART PROTOCOLS DRIVERS M: David Lin diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 6eb3caaee497..ded5300e75da 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/greybus/hd.rs b/rust/kernel/greybus/hd.rs new file mode 100644 index 000000000000..56435074f8dc --- /dev/null +++ b/rust/kernel/greybus/hd.rs @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Greybus host device abstractions. +//! +//! A driver implements the transmit path through [`HdDriver`] and feeds r= eceived data back into +//! the core with [`Device::data_rcvd`]. +//! +//! A host device is created, populated with driver private data and added= to the Greybus bus by +//! constructing a [`Registration`], which owns the underlying `struct gb_= host_device`. Dropping +//! the registration drops the private data and removes the device from th= e bus, so it is normally +//! stored in the driver data of the parent device and torn down implicitl= y when that device goes +//! away. +//! +//! Individual references to a live host device are represented by [`ARef<= Device>`], which keeps +//! the embedded `struct device` reference count balanced. +//! +//! C header: [`include/linux/greybus/hd.h`](srctree/include/linux/greybus= /hd.h) +//! +//! # Examples +//! +//! ```ignore +//! use kernel::{device, prelude::*}; +//! +//! struct MyHd { +//! // transport state +//! } +//! +//! #[vtable] +//! impl HdDriver for MyHd { +//! fn message_send(data: &Self, dest_cport_id: u16, msg: Message) -> = Result { +//! // Copy what is needed out of `msg`, queue it, and return with= out sleeping. +//! // Call `HostDevice::message_sent()` once the core may release= the message. +//! Ok(()) +//! } +//! +//! fn message_cancel(_msg: Message) {} +//! } +//! +//! fn probe(parent: &device::Device) -> Result> { +//! Registration::new(parent, BUFFER_SIZE_MAX, NUM_CPORTS, try_pin_ini= t!(MyHd {})) +//! } +//! ``` + +use core::ptr::addr_of_mut; +use core::{marker::PhantomData, ptr::NonNull}; + +use kernel::{device, prelude::*}; + +use crate::error::{code, from_err_ptr, to_result}; +use crate::greybus::Connection; +use crate::sync::aref::{ARef, AlwaysRefCounted}; +use crate::{greybus::Message, types::Opaque}; + +/// The set of callbacks a Greybus host driver can provide. +#[vtable] +pub trait HdDriver: Send + Sync + Sized + 'static { + /// Transmits `msg` to `dest_cport_id`. + /// + /// This may be called in atomic context and therefore must not sleep;= queue the message and + /// return. Once the core is allowed to release the message, call + /// [`HostDevice::message_sent`]. + /// + /// The message is only borrowed for the duration of this call: copy w= hat is needed out of it, + /// do not stash the reference. + fn message_send(data: &Self, dest_cport_id: u16, msg: Message) -> Resu= lt; + + /// Aborts the transmission of a message previously handed to [`HdDriv= er::message_send`]. + /// + /// Always called in process context. + fn message_cancel(msg: Message); +} + +/// Builds the C callback table for a [`HdDriver`] implementation. +struct HdDriverVTable(PhantomData); + +impl HdDriverVTable { + const DRIVER: bindings::gb_hd_driver =3D bindings::gb_hd_driver { + // Both are mandatory, hence no `HAS_*` check. See [`HdDriver`]. + message_send: Some(Self::message_send), + message_cancel: Some(Self::message_cancel), + // Every other callback is left `NULL`, which the Greybus core tak= es as "use the default + // behaviour". + ..pin_init::zeroed() + }; + + const fn build() -> &'static bindings::gb_hd_driver { + &Self::DRIVER + } + + /// # Safety + /// + /// `hd` must point at a registered host device whose private area hol= ds a pointer to a live + /// `T`, and `msg` must point at a valid message. + unsafe extern "C" fn message_send( + hd: *mut bindings::gb_host_device, + dest_cport_id: u16, + msg: *mut bindings::gb_message, + _gfp_mask: bindings::gfp_t, + ) -> c_int { + // SAFETY: `gb_host_device` and `HostDevice` have the same layout. + let hd =3D unsafe { Device::>::from_raw(h= d) }; + // SAFETY: `message_send` is only ever called after a successful c= all to + // `gb_hd_add`, hence it's guaranteed that `Device::set_drvdata()`= has been called + // and stored a `Pin>`. + let data =3D unsafe { hd.as_ref().drvdata_borrow() }; + // SAFETY: The caller guarantees `msg` is valid for the duration o= f this call. + let msg =3D unsafe { Message::from_raw(msg) }; + + match T::message_send(&data, dest_cport_id, msg) { + Ok(()) =3D> 0, + Err(e) =3D> e.to_errno(), + } + } + + /// # Safety + /// + /// `msg` must point at a valid message of a registered host device of= this driver. + unsafe extern "C" fn message_cancel(msg: *mut bindings::gb_message) { + // SAFETY: The caller guarantees `msg` is valid for the duration o= f this call. + let msg =3D unsafe { Message::from_raw(msg) }; + + T::message_cancel(msg); + } +} + +/// A Greybus host device. +/// +/// # Invariants +/// +/// The wrapped value is a valid `struct gb_host_device` created by `gb_hd= _create()`, and every +/// [`ARef`] owns an increment on its reference count. +#[repr(transparent)] +pub struct Device { + ptr: Opaque, + _ctx: PhantomData, +} + +// SAFETY: `gb_host_device` is reference counted through its embedded `str= uct device`, which may be +// used from any thread. +unsafe impl Send for Device {} + +// SAFETY: `gb_host_device` has its own internal locking, so it is safe to= share references to it +// across threads. +unsafe impl Sync for Device {} + +// SAFETY: The embedded `struct device` carries the reference count, and `= gb_hd_put()` is just +// `put_device()` on it, so the object stays alive for as long as incremen= ts are outstanding. +unsafe impl AlwaysRefCounted for Device { + #[inline] + fn inc_ref(&self) { + // SAFETY: By the type invariant there is a live reference to the = host device, and `dev` is + // its embedded `struct device`. + unsafe { bindings::get_device(&raw mut (*self.ptr.get()).dev) }; + } + + #[inline] + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: The caller guarantees it owns an increment on the refer= ence count. + unsafe { bindings::gb_hd_put(obj.as_ptr().cast()) } + } +} + +impl Device { + /// # Safety + /// + /// `ptr` must be a valid pointer to a `struct gb_host_device`. + #[inline] + pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::gb_host_de= vice) -> &'a Self { + // SAFETY: `Device` is a transparent wrapper of `Opaque`. + unsafe { &*ptr.cast() } + } + + #[inline] + pub(crate) fn as_raw(&self) -> *mut bindings::gb_host_device { + self.ptr.get() + } + + /// Hands a message received on `hd_cport_id` to the Greybus core. + #[inline] + pub fn data_rcvd(&self, cport_id: u16, msg: &[u8]) { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid + // `struct gb_host_device`. `msg` is valid for reads of ``msg.len(= )` bytes for the duration + // of the call, and the core only reads through the pointer =E2=80= =94 it copies the payload into + // the operation before returning =E2=80=94 so handing it a `*mut`= derived from a shared reference + // is sound. + // + // TODO: The C signature of this function should be changed to tak= e const pointer for msg. + unsafe { + bindings::greybus_data_rcvd(self.as_raw(), cport_id, msg.as_pt= r().cast_mut(), msg.len()) + } + } + + /// Looks up the connection bound to `cport` on interface `id`. + pub fn find_connection_by_intf(&self, id: u8, cport: u16) -> Option> { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid + // `struct gb_host_device`. + let ptr =3D NonNull::new(unsafe { + bindings::gb_connection_hd_find_by_intf(self.as_raw(), id, cpo= rt) + })?; + + // SAFETY: ptr is a valid gb_connection + Some(unsafe { ARef::from_raw(ptr.cast()) }) + } +} + +impl AsRef> for Device { + #[inline] + fn as_ref(&self) -> &device::Device { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid + // `struct gb_host_device`. `dev` points to a valid `struct device= `. + unsafe { device::Device::from_raw(addr_of_mut!((*self.as_raw()).de= v)) } + } +} + +/// A host device owned by its driver, together with the driver's private = data `T`. +/// +/// Created and added to the Greybus bus on construction, removed on drop. +/// +/// # Invariants +/// +/// `ptr` points at a valid `struct gb_host_device` obtained from `gb_hd_c= reate()`, whose driver +/// data holds a live `T` +#[repr(transparent)] +pub struct Registration { + ptr: NonNull, + _data: PhantomData, +} + +impl Registration { + /// Creates a host device under `parent` and adds it to the Greybus bu= s. + /// + /// `buffer_size_max` is the largest message the transport can carry i= n one go, header + /// included. `num_cports` is the number of cports that the greybus ho= st device can connect to. + /// + /// `data` is initialised in place before the device is added, so call= backs may run against it + /// from the moment `gb_hd_add()` succeeds. + pub fn new( + parent: &device::Device, + buffer_size_max: usize, + num_cports: usize, + data: impl PinInit, + ) -> Result { + // SAFETY: `parent` is a valid device, and the driver table is `'s= tatic`. The core only + // ever reads through the driver pointer, so casting away `const` = is fine. + let hd =3D from_err_ptr(unsafe { + bindings::gb_hd_create( + core::ptr::from_ref(HdDriverVTable::::build()).cast_mut= (), + parent.as_raw(), + buffer_size_max, + num_cports, + ) + })?; + + // SAFETY: `gb_host_device` and `HostDevice` have the same layout. + let hd_dev =3D unsafe { &*hd.cast::>>() }; + hd_dev.as_ref().set_drvdata(data)?; + + let res =3D Self { + ptr: NonNull::new(hd).ok_or(code::ENOMEM)?, + _data: PhantomData, + }; + + res.add()?; + + Ok(res) + } +} + +impl Registration { + fn add(&self) -> Result<()> { + // SAFETY: By the type invariant the host device is valid, and it = has not been added yet. + to_result(unsafe { bindings::gb_hd_add(self.as_raw()) }) + } + + fn as_raw(&self) -> *mut bindings::gb_host_device { + self.ptr.as_ptr() + } +} + +impl AsRef for Registration { + #[inline] + fn as_ref(&self) -> &Device { + // SAFETY: By the type invariant the host device is valid. + unsafe { Device::from_raw(self.as_raw()) } + } +} + +impl Drop for Registration { + fn drop<'a>(&'a mut self) { + { + let hd =3D self.as_raw(); + // SAFETY: By the type invariant `hd` points at a valid host d= evice, and + // `gb_host_device` and `Device` have the same layout. + let hd_dev =3D unsafe { &*hd.cast::>>() }; + // SAFETY: The driver data was set to a `T` in `Registration::= new()` and has not been + // taken since, and this is the only place that takes it. + let data =3D unsafe { hd_dev.as_ref().drvdata_obtain::() }; + drop(data); + } + + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid + // `struct gb_host_device`. + unsafe { bindings::gb_hd_del(self.as_raw()) } + } +} + +// SAFETY: The greybus host device API is thread-safe as guaranteed by the= device core, as long as +// gb_hd_del() is guaranteed to only be called once - which is guaranteed = by our type not +// having Copy/Clone. +unsafe impl Send for Registration {} + +// SAFETY: The greybus device API is thread-safe as guaranteed by the devi= ce core, as long as +// gb_hd_del() is guaranteed to only be called once - which is guaranteed = by our type not +// having Copy/Clone. +unsafe impl Sync for Registration {} diff --git a/rust/kernel/greybus/mod.rs b/rust/kernel/greybus/mod.rs new file mode 100644 index 000000000000..5dd1941574cf --- /dev/null +++ b/rust/kernel/greybus/mod.rs @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Abstractions for the Greybus core. +//! +//! C header: [`include/linux/greybus.h`](srctree/include/linux/greybus.h) +//! +//! Greybus host drivers ("host devices") bridge the Greybus core to whate= ver transport actually +//! carries the traffic. A host driver creates a [`HostDevice`], registers= it, and implements +//! [`HdDriver`] to transmit the messages the core hands it. + +use core::ptr::NonNull; + +use kernel::sync::aref::AlwaysRefCounted; +use kernel::transmute::FromBytes; +use kernel::types::Opaque; + +pub mod hd; +pub mod protocols; + +/// The largest Greybus message, header included. +/// +/// Bounded by the 16-bit `size` field in the operation header. +pub const GB_OPERATION_SIZE_MAX: usize =3D u16::MAX as usize; + +/// The largest valid CPort id. +/// +/// Ids above this are reserved by the protocol; a host device's `num_cpor= ts` cannot exceed +/// `CPORT_ID_MAX + 1`. +pub const CPORT_ID_MAX: usize =3D bindings::CPORT_ID_MAX as usize; + +/// A Greybus message handed to a host driver for transmission. +/// +/// # Invariants +/// +/// The shared reference is only ever handed out for the duration of a [`H= dDriver`] callback, during +/// which the Greybus core guarantees the message and its buffer stay aliv= e. +#[repr(transparent)] +pub struct Message(NonNull); + +impl Message { + /// # Safety + /// + /// `ptr` must be non-null and point at a valid `struct gb_message` wh= ich outlives the + /// returned `Self`. + #[inline] + pub(crate) const unsafe fn from_raw(ptr: *mut bindings::gb_message) ->= Self { + // SAFETY: The caller guarantees `ptr` is non-null. + Self(unsafe { NonNull::new_unchecked(ptr) }) + } + + /// Returns the operation header at the start of the message. + #[inline] + pub const fn header(&self) -> &protocols::GbOperationMsgHdr { + // SAFETY: By the type invariant the message is valid, and so is i= ts header. + let msg =3D unsafe { &*self.0.as_ptr() }; + // SAFETY: `header` points at a valid `gb_operation_msg_hdr` for a= s long as the message is + // alive, and `GbOperationMsgHdr` is a transparent wrapper of it. + unsafe { &*msg.header.cast() } + } + + /// Tells the Greybus core the transport is done with this message. + /// + /// `status` is `0` on success or a negative errno describing the tran= smit failure. + #[inline] + pub fn sent(self, status: i32) { + // SAFETY: By the type invariant the message is valid and still ow= ned by the transport, + // and its connection and host device are alive for as long as it = is. + unsafe { + bindings::greybus_message_sent( + self.operation().connection().host_device().as_raw(), + self.0.as_ptr(), + status, + ); + } + } + + /// Returns the payload, i.e. the message without its operation header. + pub const fn payload_bytes(&self) -> &[u8] { + // SAFETY: By the type invariant the message is valid. + let msg =3D unsafe { &*self.0.as_ptr() }; + + if msg.payload.is_null() || msg.payload_size =3D=3D 0 { + return &[]; + } + + // SAFETY: A non-null `payload` points at `payload_size` initializ= ed bytes. + unsafe { core::slice::from_raw_parts(msg.payload.cast::(), msg= .payload_size) } + } + + /// Interprets the message payload as a `T`. + /// + /// Returns `None` if the payload is too short or misaligned for `T`. + #[inline] + pub fn payload(&self) -> Option<&T> { + T::from_bytes(self.payload_bytes()) + } + + /// Returns the operation this message belongs to. + #[inline] + pub const fn operation(&self) -> &Operation { + // SAFETY: By the type invariant the message is valid, and its `op= eration` is set for as + // long as the message is alive. + unsafe { Operation::from_raw((*self.0.as_ptr()).operation) } + } +} + +/// A Greybus operation. +/// +/// # Invariants +/// +/// The wrapped value is a valid `struct gb_operation`. +#[repr(transparent)] +pub struct Operation(Opaque); + +impl Operation { + /// # Safety + /// + /// `ptr` must be a valid pointer to a `struct gb_operation`. + #[inline] + pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::gb_operati= on) -> &'a Self { + // SAFETY: `Operation` is a transparent wrapper of `Opaque`. + unsafe { &*ptr.cast() } + } + + /// Returns the connection this operation travels on. + #[inline] + pub const fn connection(&self) -> &Connection { + // SAFETY: By the type invariant the operation is valid, and its `= connection` is alive for + // as long as the operation is. + unsafe { Connection::from_raw((*self.0.get()).connection) } + } +} + +/// A Greybus connection. +/// +/// # Invariants +/// +/// The wrapped value is a valid `struct gb_connection`. +#[repr(transparent)] +pub struct Connection(Opaque); + +// SAFETY: `gb_connection_put()` drops the reference acquired by `gb_conne= ction_get()`, so the +// connection stays alive for as long as increments are outstanding. +unsafe impl AlwaysRefCounted for Connection { + #[inline] + fn inc_ref(&self) { + // SAFETY: By the type invariant there is a live reference to the = connection. + unsafe { bindings::gb_connection_get(self.0.get()) } + } + + #[inline] + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: The caller guarantees it owns an increment on the refer= ence count. + unsafe { bindings::gb_connection_put(obj.as_ptr().cast()) } + } +} + +impl Connection { + /// # Safety + /// + /// `ptr` must be a valid pointer to a `struct gb_connection`. + #[inline] + pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::gb_connect= ion) -> &'a Self { + // SAFETY: `Connection` is a transparent wrapper of `Opaque`. + unsafe { &*ptr.cast() } + } + + /// Returns the interface at the far end of the connection. In cases = like SVC connection, + /// interface can be NULL. + #[inline] + pub const fn interface(&self) -> Option<&Interface> { + // SAFETY: By the type invariant the connection is valid. + let intf_ptr =3D unsafe { (*self.0.get()).intf }; + + if intf_ptr.is_null() { + None + } else { + // SAFETY: By the previous check, intf_ptr is valid. + Some(unsafe { Interface::from_raw(intf_ptr) }) + } + } + + /// Returns the CPort id this connection uses on the interface. + #[inline] + pub const fn intf_cport_id(&self) -> u16 { + // SAFETY: By the type invariant the connection is valid. + unsafe { (*self.0.get()).intf_cport_id } + } + + /// Returns the CPort id this connection uses on the host device. + #[inline] + pub const fn hd_cport_id(&self) -> u16 { + // SAFETY: By the type invariant the connection is valid. + unsafe { (*self.0.get()).hd_cport_id } + } + + /// Returns the host device this connection belongs to. + #[inline] + pub const fn host_device(&self) -> &hd::Device { + // SAFETY: By the type invariant the connection is valid, and its = `hd` is alive for as + // long as the connection is. + unsafe { hd::Device::from_raw((*self.0.get()).hd) } + } +} + +/// A Greybus interface. +/// +/// # Invariants +/// +/// The wrapped value is a valid `struct gb_interface`. +#[repr(transparent)] +pub struct Interface(Opaque); + +impl Interface { + /// # Safety + /// + /// `ptr` must be a valid pointer to a `struct gb_interface`. + #[inline] + pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::gb_interfa= ce) -> &'a Self { + // SAFETY: `Interface` is a transparent wrapper of `Opaque`. + unsafe { &*ptr.cast() } + } + + /// Returns the interface id, unique within its host device. + #[inline] + pub const fn id(&self) -> u8 { + // SAFETY: By the type invariant the interface is valid. + unsafe { (*self.0.get()).interface_id } + } +} diff --git a/rust/kernel/greybus/protocols.rs b/rust/kernel/greybus/protoco= ls.rs new file mode 100644 index 000000000000..4658ace5e323 --- /dev/null +++ b/rust/kernel/greybus/protocols.rs @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Greybus wire format definitions. +//! +//! Thin `repr(transparent)` wrappers over the generated bindings for the = operation header and the +//! SVC protocol messages, plus the constants that go in their type and re= sult fields. The +//! wrappers exist to keep the byte-order conversions in one place: constr= uctors take native-endian +//! values and store little-endian, accessors convert back. + +/// Set in the header type field to mark a message as a response to the op= eration of the same id. +pub const MESSAGE_TYPE_RESPONSE: u8 =3D 0x80; + +/// The CPort id reserved for the SVC connection on every host device. +pub const GB_SVC_CPORT_ID: u16 =3D bindings::GB_SVC_CPORT_ID as u16; + +/// Defines `u8` constants from same-named `bindings` values. +macro_rules! gb_u8_consts { + ($($name:ident),* $(,)?) =3D> { + $( + #[allow(missing_docs)] + pub const $name: u8 =3D bindings::$name as u8; + )* + }; +} + +// SVC Operation Types +gb_u8_consts! { + GB_SVC_TYPE_PROTOCOL_VERSION, + GB_SVC_TYPE_SVC_HELLO, + GB_SVC_TYPE_INTF_DEVICE_ID, + GB_SVC_TYPE_INTF_RESET, + GB_SVC_TYPE_CONN_CREATE, + GB_SVC_TYPE_CONN_DESTROY, + GB_SVC_TYPE_DME_PEER_GET, + GB_SVC_TYPE_DME_PEER_SET, + GB_SVC_TYPE_ROUTE_CREATE, + GB_SVC_TYPE_ROUTE_DESTROY, + GB_SVC_TYPE_TIMESYNC_ENABLE, + GB_SVC_TYPE_TIMESYNC_DISABLE, + GB_SVC_TYPE_TIMESYNC_AUTHORITATIVE, + GB_SVC_TYPE_INTF_SET_PWRM, + GB_SVC_TYPE_INTF_EJECT, + GB_SVC_TYPE_PING, + GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET, + GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET, + GB_SVC_TYPE_PWRMON_SAMPLE_GET, + GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET, + GB_SVC_TYPE_TIMESYNC_WAKE_PINS_ACQUIRE, + GB_SVC_TYPE_TIMESYNC_WAKE_PINS_RELEASE, + GB_SVC_TYPE_TIMESYNC_PING, + GB_SVC_TYPE_MODULE_INSERTED, + GB_SVC_TYPE_MODULE_REMOVED, + GB_SVC_TYPE_INTF_VSYS_ENABLE, + GB_SVC_TYPE_INTF_VSYS_DISABLE, + GB_SVC_TYPE_INTF_REFCLK_ENABLE, + GB_SVC_TYPE_INTF_REFCLK_DISABLE, + GB_SVC_TYPE_INTF_UNIPRO_ENABLE, + GB_SVC_TYPE_INTF_UNIPRO_DISABLE, + GB_SVC_TYPE_INTF_ACTIVATE, + GB_SVC_TYPE_INTF_RESUME, + GB_SVC_TYPE_INTF_MAILBOX_EVENT, + GB_SVC_TYPE_INTF_OOPS, +} + +// UNIPRO modes +gb_u8_consts! { + GB_SVC_UNIPRO_FAST_MODE, + GB_SVC_UNIPRO_SLOW_MODE, + GB_SVC_UNIPRO_FAST_AUTO_MODE, + GB_SVC_UNIPRO_SLOW_AUTO_MODE, + GB_SVC_UNIPRO_MODE_UNCHANGED, + GB_SVC_UNIPRO_HIBERNATE_MODE, + GB_SVC_UNIPRO_OFF_MODE, +} + +// PWR States +gb_u8_consts! { + GB_SVC_SETPWRM_PWR_OK, + GB_SVC_SETPWRM_PWR_LOCAL, + GB_SVC_SETPWRM_PWR_REMOTE, + GB_SVC_SETPWRM_PWR_BUSY, + GB_SVC_SETPWRM_PWR_ERROR_CAP, + GB_SVC_SETPWRM_PWR_FATAL_ERROR, +} + +// Vsys Result +gb_u8_consts! { + GB_SVC_INTF_VSYS_OK, + GB_SVC_INTF_VSYS_FAIL, +} + +// Refclk Result +gb_u8_consts! { + GB_SVC_INTF_REFCLK_OK, + GB_SVC_INTF_REFCLK_FAIL, +} + +// Unipro Result +gb_u8_consts! { + GB_SVC_INTF_UNIPRO_OK, + GB_SVC_INTF_UNIPRO_FAIL, + GB_SVC_INTF_UNIPRO_NOT_OFF, +} + +// Op Codes +gb_u8_consts! { + GB_SVC_OP_SUCCESS, + GB_SVC_OP_UNKNOWN_ERROR, + GB_SVC_INTF_NOT_DETECTED, + GB_SVC_INTF_NO_UPRO_LINK, + GB_SVC_INTF_UPRO_NOT_DOWN, + GB_SVC_INTF_UPRO_NOT_HIBERNATED, + GB_SVC_INTF_NO_V_SYS, + GB_SVC_INTF_V_CHG, + GB_SVC_INTF_WAKE_BUSY, + GB_SVC_INTF_NO_REFCLK, + GB_SVC_INTF_RELEASING, + GB_SVC_INTF_NO_ORDER, + GB_SVC_INTF_MBOX_SET, + GB_SVC_INTF_BAD_MBOX, + GB_SVC_INTF_OP_TIMEOUT, + GB_SVC_PWRMON_OP_NOT_PRESENT, +} + +// Greybus Interface Types +gb_u8_consts! { + GB_SVC_INTF_TYPE_UNKNOWN, + GB_SVC_INTF_TYPE_DUMMY, + GB_SVC_INTF_TYPE_UNIPRO, + GB_SVC_INTF_TYPE_GREYBUS, +} + +/// The header every Greybus message starts with. +/// +/// # Invariants +/// +/// The `size` field covers the header and the payload that follows it. +#[repr(transparent)] +pub struct GbOperationMsgHdr(bindings::gb_operation_msg_hdr); + +// SAFETY: `gb_operation_msg_hdr` is a POD type with no padding and no int= erior mutability. +unsafe impl kernel::transmute::AsBytes for GbOperationMsgHdr {} + +impl GbOperationMsgHdr { + /// Builds a header. `size` is the whole message, this header included. + #[inline] + pub const fn new(size: u16, operation_id: u16, type_: u8, result: u8) = -> Self { + Self(bindings::gb_operation_msg_hdr { + size: size.to_le(), + operation_id: operation_id.to_le(), + type_, + result, + pad: [0u8; 2], + }) + } + + /// Returns the type field, response bit included. + #[inline] + pub const fn msg_type(&self) -> u8 { + self.0.type_ + } + + /// Returns whether this is a response rather than a request. + #[inline] + pub const fn is_response(&self) -> bool { + self.0.type_ & MESSAGE_TYPE_RESPONSE !=3D 0 + } + + /// Returns the operation id pairing a response with its request. Zero= for unidirectional + /// messages. + #[inline] + pub const fn operation_id(&self) -> u16 { + u16::from_le(self.0.operation_id) + } + + /// Returns the type field with the response bit cleared. + #[inline] + pub const fn request_type(&self) -> u8 { + self.msg_type() & !MESSAGE_TYPE_RESPONSE + } + + /// Returns the whole message size, this header included. + #[inline] + pub const fn size(&self) -> u16 { + u16::from_le(self.0.size) + } +} + +/// Request for [`GB_SVC_TYPE_PROTOCOL_VERSION`]. +#[repr(transparent)] +pub struct GbSvcVersionRequest(bindings::gb_svc_version_request); + +impl GbSvcVersionRequest { + /// Creates a request advertising SVC protocol version `major`.`minor`. + #[inline] + pub const fn new(major: u8, minor: u8) -> Self { + Self(bindings::gb_svc_version_request { major, minor }) + } +} + +/// Request for [`GB_SVC_TYPE_SVC_HELLO`]. +#[repr(transparent)] +pub struct GbSvcHelloRequest(bindings::gb_svc_hello_request); + +impl GbSvcHelloRequest { + /// Creates a hello request identifying the endo as `endo_id` and the = AP's own interface as + /// `interface_id`. + #[inline] + pub const fn new(endo_id: u16, interface_id: u8) -> Self { + Self(bindings::gb_svc_hello_request { + endo_id: endo_id.to_le(), + interface_id, + }) + } +} + +/// Request for [`GB_SVC_TYPE_INTF_SET_PWRM`]. +#[repr(transparent)] +pub struct GbSvcIntfSetPwrmRequest(bindings::gb_svc_intf_set_pwrm_request); + +// SAFETY: `gb_svc_intf_set_pwrm_request` is a struct of `u8` fields, so e= very bit pattern of its +// size is a valid instance. +unsafe impl kernel::transmute::FromBytes for GbSvcIntfSetPwrmRequest {} + +impl GbSvcIntfSetPwrmRequest { + /// Returns the requested TX gear, one of the `GB_SVC_UNIPRO_*` modes. + #[inline] + pub const fn tx_mode(&self) -> u8 { + self.0.tx_mode + } + + /// Returns the requested RX gear, one of the `GB_SVC_UNIPRO_*` modes. + #[inline] + pub const fn rx_mode(&self) -> u8 { + self.0.rx_mode + } +} + +/// Response to [`GB_SVC_TYPE_INTF_SET_PWRM`]. +#[repr(transparent)] +pub struct GbSvcIntfSetPwrmResponse(bindings::gb_svc_intf_set_pwrm_respons= e); + +impl GbSvcIntfSetPwrmResponse { + /// `result_code` is one of the `GB_SVC_SETPWRM_PWR_*` codes. + #[inline] + pub const fn new(result_code: u8) -> Self { + Self(bindings::gb_svc_intf_set_pwrm_response { result_code }) + } +} + +/// Response to [`GB_SVC_TYPE_DME_PEER_GET`]. +#[repr(transparent)] +pub struct GbSvcDmePeerGetResponse(bindings::gb_svc_dme_peer_get_response); + +impl GbSvcDmePeerGetResponse { + /// `result_code` is the UniPro `ConfigResultCode`; `attr_value` is th= e UniPro attribute + /// value. + #[inline] + pub const fn new(result_code: u16, attr_value: u32) -> Self { + Self(bindings::gb_svc_dme_peer_get_response { + result_code: result_code.to_le(), + attr_value: attr_value.to_le(), + }) + } +} + +/// Response to [`GB_SVC_TYPE_DME_PEER_SET`]. +#[repr(transparent)] +pub struct GbSvcDmePeerSetResponse(bindings::gb_svc_dme_peer_set_response); + +impl GbSvcDmePeerSetResponse { + /// `result_code` is the UniPro `ConfigResultCode`. + #[inline] + pub const fn new(result_code: u16) -> Self { + Self(bindings::gb_svc_dme_peer_set_response { + result_code: result_code.to_le(), + }) + } +} + +/// Response to [`GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET`]. +#[repr(transparent)] +pub struct GbSvcPwrmonRailCountGetResponse(bindings::gb_svc_pwrmon_rail_co= unt_get_response); + +impl GbSvcPwrmonRailCountGetResponse { + /// Creates a response reporting `rail_count` available rails. + #[inline] + pub const fn new(rail_count: u8) -> Self { + Self(bindings::gb_svc_pwrmon_rail_count_get_response { rail_count = }) + } +} + +/// Response to [`GB_SVC_TYPE_INTF_VSYS_ENABLE`] and [`GB_SVC_TYPE_INTF_VS= YS_DISABLE`]. +#[repr(transparent)] +pub struct GbSvcIntfVsysResponse(bindings::gb_svc_intf_vsys_response); + +impl GbSvcIntfVsysResponse { + /// `result_code` is [`GB_SVC_INTF_VSYS_OK`] or [`GB_SVC_INTF_VSYS_FAI= L`]. + #[inline] + pub const fn new(result_code: u8) -> Self { + Self(bindings::gb_svc_intf_vsys_response { result_code }) + } +} + +/// Response to [`GB_SVC_TYPE_INTF_REFCLK_ENABLE`] and [`GB_SVC_TYPE_INTF_= REFCLK_DISABLE`]. +#[repr(transparent)] +pub struct GbSvcIntfRefclkResponse(bindings::gb_svc_intf_refclk_response); + +impl GbSvcIntfRefclkResponse { + /// `result_code` is [`GB_SVC_INTF_REFCLK_OK`] or [`GB_SVC_INTF_REFCLK= _FAIL`]. + #[inline] + pub const fn new(result_code: u8) -> Self { + Self(bindings::gb_svc_intf_refclk_response { result_code }) + } +} + +/// Response to [`GB_SVC_TYPE_INTF_UNIPRO_ENABLE`] and [`GB_SVC_TYPE_INTF_= UNIPRO_DISABLE`]. +#[repr(transparent)] +pub struct GbSvcIntfUniproResponse(bindings::gb_svc_intf_unipro_response); + +impl GbSvcIntfUniproResponse { + /// `result_code` is one of the `GB_SVC_INTF_UNIPRO_*` codes. + #[inline] + pub const fn new(result_code: u8) -> Self { + Self(bindings::gb_svc_intf_unipro_response { result_code }) + } +} + +/// Response to [`GB_SVC_TYPE_INTF_ACTIVATE`]. +#[repr(transparent)] +pub struct GbSvcIntfActivateResponse(bindings::gb_svc_intf_activate_respon= se); + +impl GbSvcIntfActivateResponse { + /// `status` is one of the `GB_SVC_OP_*` codes; `intf_type` is one of = the + /// `GB_SVC_INTF_TYPE_*` values and is only meaningful when `status` is + /// [`GB_SVC_OP_SUCCESS`]. + #[inline] + pub const fn new(status: u8, intf_type: u8) -> Self { + Self(bindings::gb_svc_intf_activate_response { status, intf_type }) + } +} + +/// Response to [`GB_SVC_TYPE_INTF_RESUME`]. +#[repr(transparent)] +pub struct GbSvcIntfResumeResponse(bindings::gb_svc_intf_resume_response); + +impl GbSvcIntfResumeResponse { + /// `status` is one of the `GB_SVC_OP_*` codes. + #[inline] + pub const fn new(status: u8) -> Self { + Self(bindings::gb_svc_intf_resume_response { status }) + } +} + +/// Request for [`GB_SVC_TYPE_MODULE_INSERTED`]. +#[repr(transparent)] +pub struct GbSvcModuleInsertedRequest(bindings::gb_svc_module_inserted_req= uest); + +impl GbSvcModuleInsertedRequest { + /// The module spans `intf_count` consecutive interfaces starting at `= primary_intf_id`. + /// `flags` is a mask of `GB_SVC_MODULE_INSERTED_FLAG_*` values. + #[inline] + pub const fn new(primary_intf_id: u8, intf_count: u8, flags: u16) -> S= elf { + Self(bindings::gb_svc_module_inserted_request { + primary_intf_id, + intf_count, + flags: flags.to_le(), + }) + } +} + +/// Request for [`GB_SVC_TYPE_MODULE_REMOVED`]. +#[repr(transparent)] +pub struct GbSvcModuleRemovedRequest(bindings::gb_svc_module_removed_reque= st); + +// SAFETY: `gb_svc_module_removed_request` is a struct of `u8` field, so e= very bit pattern of its +// size is a valid instance. +unsafe impl kernel::transmute::FromBytes for GbSvcModuleRemovedRequest {} + +impl GbSvcModuleRemovedRequest { + /// `primary_intf_id` identifies the module, and matches the one given= when it was inserted. + #[inline] + pub const fn new(primary_intf_id: u8) -> Self { + Self(bindings::gb_svc_module_removed_request { primary_intf_id }) + } + + /// Returns the primary_intf_id field. + #[inline] + pub const fn primary_intf_id(&self) -> u8 { + self.0.primary_intf_id + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 45c4f4db51d2..3c4bdad53de1 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -80,6 +80,8 @@ pub mod fs; #[cfg(CONFIG_GPU_BUDDY =3D "y")] pub mod gpu; +#[cfg(CONFIG_GREYBUS)] +pub mod greybus; #[cfg(CONFIG_I2C =3D "y")] pub mod i2c; pub mod id_pool; --=20 2.55.0 From nobody Mon Sep 28 16:22:44 2026 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5F2423F076F for ; Thu, 20 Aug 2026 09:26:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218014; cv=none; b=OYX7YkEBxlBoThocpXx/UPTSsSU93/gT7/MKLvrGWZ6C/w632yl4DTnSvvyxV+/zlW0XiAkk0urKqR1/rOBEMkOCOYkByV5zx/5w1HH5UFVKZV1Jmbeaunq2skj7S3QQFU7sM+lZ368O7QW3nutwdZ3lpaBPdixnNDDQ1uWvZI8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218014; c=relaxed/simple; bh=br1H6G0eLQ8DbKKw/hwOxavsuwpQvgoofDzMt4PAP7s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qbs/1XP0dKHl7EyoBn85sHPmS1NuQ8A+rF8nkf6/o8piY8RMcWFYQ+yEdSob7r7EWNUB13ovyvKR2sBnzokjFSfIYgvNFNs8tDBl1gNElHMyA1HrFWWKwxyXP08TZN+fGbPNuy2XrThSj7fT+g4vPadQyOI0xTXfb86aNsHkExs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=SePLx4qV; arc=none smtp.client-ip=209.85.216.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="SePLx4qV" Received: by mail-pj1-f47.google.com with SMTP id 98e67ed59e1d1-38e041ea211so1991143a91.0 for ; Thu, 20 Aug 2026 02:26:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787218000; x=1787822800; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=CPlUdERCL/ouvofGvuSbl7Z2Dx80ihMx/Ju0zLUU78M=; b=SePLx4qVCqtOZEiTiucokaRjG2kDEndt4/19ujlHIMhcEKZU7fQsmXd+CqtEIdD0U8 v7HaHg/qoe5oKlekjqFddOSWM50RabWIu6NYqv/c0cSOCUiXKqYa8xN/sopy1eafviQr ZRRL1Hkzbra9jqBMEEJov4/oOATi4NrBLWIz4T9hojnSgWWqQMeeExoYxbEWm77+EECZ jEmins6sEvB0HPhwuHvDVe1e5yMGEY5VQxa0Me+ukI5NFL2jH66O/U1Ta3IfZ6qzHnDk 200gUg5fAll8ZkPX6ggcaPBAvzBvV0fjjgX7NLtR/EMkpMkNFB0po432YCeRl2bEgneE gP1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787218000; x=1787822800; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=CPlUdERCL/ouvofGvuSbl7Z2Dx80ihMx/Ju0zLUU78M=; b=KdDoeYHu8hmcR51PSXDS69GR7jWPDMU2WD6msB+ynFnaywu6ShGU6e4i45BmMy8HSi CYQVcrQQNQUupiu/kegxi1DOJ4wPokFdU0EUCsw6zYgbD3InoglfsQkRVWjDUR06WXPI 3pX2alOr/W0mGp6jMlYWkWggQcdpqiWY0lAGsfCUg4AV+qOYHH1NDJUlbO0gI/gZTzHL +w/2bo7iXiPvBnlU+TABE9fq7+8n9mx3nSpDz+oNsJaVsB7P7uk3hGUuelIC4TSJUbcu l07FSkFOjpU+sGG3cIahNopQqAA581x2W6UViwPKXY84DFCsNGgmADFsgUnqr8jRZK/B G/Kw== X-Forwarded-Encrypted: i=1; AHgh+RrAoQRqBXI1gws9d43TRmar3XIJ7CzvPV9oyvk4t7nVvLFAPuGitkdzw0Dno9xThDN5bXLf1aYRuReJLnM=@vger.kernel.org X-Gm-Message-State: AFuF++npSNzIRsxxF7qFQdM7kuea/zg+UknGkzxdwzCgu1QzKKdpte2k oRjVv0RO+nWRp9z1JaqV2QB6OYzQV4t4IrZGbC8q3eU7yKo/AkfZ7dSPxPlv3EY2+A== X-Gm-Gg: AR+sD112ofaRHSVoxxT6t/f2spi5i3EgaIMk9DAMGdWyBKIs/C3klJ9lU60z8lty+ef WrglaBdKiNwJRuaOXjyY+xJprnS9gd097NQSB7OD5riGJLlIcEjoSiMu0sSIjyjslyU3QW6XndH by6S+ZnTnNketh9uY++zkKlggH3856f5vOwMnIXEVAGn6ij7Rmx8S02IfCTOIFPEa6pQtQk11LR anxv3vdaQquugEjQsCFGniAdqPX0NzZl1rc+s8CkPwauq8j0C34bcQfRtKaT4Wc2rh6VXx4NXdF 9+62EDhSXRwit+sH0bvmBm9mIOw+Ch3FFjay63iYH9Xp7lwZySbMvMIqpwSZLBpA2OfVxMWSS7g +PV/YCTSSWEbSYsNcYw2B1IqQWWjz1z7W+KOtrXOTl0nHrTmpjZZk/ti4E8KTMrY9teINA7yslV McQHrCmnLqCKSEB86zEcgs20NgN96W6c+3+H0v0aBHSRhImtlyC9UJdR4LmqWoYwpGQ/TgKmA= X-Received: by 2002:a17:90b:3cc5:b0:393:194d:5366 with SMTP id 98e67ed59e1d1-39580f3bcdemr22228225a91.10.1787217999728; Thu, 20 Aug 2026 02:26:39 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.26.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:39 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:47 +0530 Subject: [PATCH 5/7] drivers: greybus: Add software SVC implementation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-5-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=21201; i=ayush@beagleboard.org; h=from:subject:message-id; bh=br1H6G0eLQ8DbKKw/hwOxavsuwpQvgoofDzMt4PAP7s=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgc1ApmRr801+/0j+FsgDrfkolWVH+THHKeT T6EhIL64G+JAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHAAKCRAFzvXHieVa dIhOD/9e972oq2c9JR8xGCFVuJdvPt7GRHF+/zWLY0kur9kfq+UPiULYygbFL2rMG8x1GvVgj+K Ed8oV7VzQcuvjk5ajr10sXANdR9AL0WpsugkN0CxCb6uV/Ky/FSXx3SktJnjIBMfb5LHycUDeik Rx6nGHMm0Or44Asw18gAGO1RhT1W98pFS2anQV9gwUPMvqyvHhuvdJd1F0rDD6R+1cavZyDHX8B CB+pJUCOyk6UOzkzqIxVCMOOzkN7X/7wcPG2QYu2UIdInM3InAfgZQAQci/1fXZBmlH7tJN26UO /O+FGUEYhTbh2YMJNYctxthPJUvrgORSsaBO6ykF6wVYwhqHPY9SKYOo60gMkOfZpfDZIEDDw44 +PWShCOun0swnNpY/lNIQAC5Xn/dWxnm4q3O1tiRtUdTaxf+38anhIZ+LpEh4soaoy/VWYb8KqX dM+nbJlwtgy+4x8EFv86zPullG7h6sLnaynQuBLjL24mb3gT/xOg6C+B9ncJzXWs2wsJvAT97jb X4d3JK4lUIHHrgWStHzw2vAsPm7Ngc/FzMpTVo8NO8uON0S5elvOmm2JU7eaTPdKRNCJ51+hDgq mrJpKRNFr6MUcMEFje4MCzsTvkXdOo9WDb2Gnn0Y7rz0QJyzRVf3dIiEIjU7XQ0UP4XFC+u9Ptk mPY60uVP7W39CHg== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 A Greybus network requires an SVC (Supervisory Controller) to bring interfaces up, assign device IDs and connect CPorts to the AP. On a UniPro network the SVC is a real entity on the bus, but transports that merely carry Greybus messages - a UART, an I2C bus, a network link - have no such entity, so every host driver for those transports ends up open-coding an SVC emulation of its own. Add gb-softsvc, a Rust implementation of the SVC that lives in the kernel and registers itself as a Greybus host device. It answers the SVC-side operations the core expects during interface bring-up and teardown. Host drivers use it through a small in-kernel interface. A driver implements the NodeOps trait to send data towards its node and then calls module_insert() to announce a new node, submit_message() to hand incoming Greybus messages back to the core, and module_remove() on disconnect. Interface IDs are allocated by the SVC and returned from module_insert(). Connection create/destroy and interface activate/resume currently just acknowledge the request; callbacks into NodeOps can be added later if transports need to act on them. gb_softsvc_exports.c exports the Rust symbols for dependent modules, as the build system does not yet support Rust cross-module dependencies natively. This hack is taken from nova-core [0]. [0]: https://lore.kernel.org/all/20260622-nova-exports-v5-0-6191773fc977@nv= idia.com/ Signed-off-by: Ayush Singh --- MAINTAINERS | 6 + drivers/greybus/Kconfig | 12 + drivers/greybus/Makefile | 2 + drivers/greybus/gb_softsvc.rs | 472 +++++++++++++++++++++++++++++++= ++++ drivers/greybus/gb_softsvc_exports.c | 15 ++ 5 files changed, 507 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 80247a031353..3ba56cdbf056 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11328,6 +11328,12 @@ S: Maintained F: Documentation/devicetree/bindings/net/ti,cc1352p7.yaml F: drivers/greybus/gb-beagleplay.c =20 +GREYBUS SOFTSVC DRIVERS +M: Ayush Singh +L: greybus-dev@lists.linaro.org (moderated for non-subscribers) +S: Maintained +F: drivers/greybus/gb_softsvc.rs + GREYBUS SUBSYSTEM M: Johan Hovold M: Alex Elder diff --git a/drivers/greybus/Kconfig b/drivers/greybus/Kconfig index c3f056d28b01..30bc491841e1 100644 --- a/drivers/greybus/Kconfig +++ b/drivers/greybus/Kconfig @@ -41,5 +41,17 @@ config GREYBUS_ES2 To compile this code as a module, choose M here: the module will be called gb-es2.ko =20 +config GREYBUS_SOFTSVC + tristate "Greybus software SVC" + depends on RUST + help + Select this option to enable a software implementation of the + Greybus SVC (Supervisory Controller) running in the kernel. It can + be used by host drivers that talk to a Greybus network which does + not provide an SVC of its own. + + To compile this code as a module, choose M here: the module + will be called gb-softsvc.ko + endif # GREYBUS =20 diff --git a/drivers/greybus/Makefile b/drivers/greybus/Makefile index d986e94f8897..e6f594128802 100644 --- a/drivers/greybus/Makefile +++ b/drivers/greybus/Makefile @@ -25,4 +25,6 @@ gb-es2-y :=3D es2.o =20 obj-$(CONFIG_GREYBUS_ES2) +=3D gb-es2.o =20 +obj-$(CONFIG_GREYBUS_SOFTSVC) +=3D gb-softsvc.o +gb-softsvc-y +=3D gb_softsvc.o gb_softsvc_exports.o =20 diff --git a/drivers/greybus/gb_softsvc.rs b/drivers/greybus/gb_softsvc.rs new file mode 100644 index 000000000000..0d125a1a2cc8 --- /dev/null +++ b/drivers/greybus/gb_softsvc.rs @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Greybus software SVC. +//! +//! A Greybus network needs an SVC to bring interfaces up and to connect t= heir CPorts to the AP. +//! Transports that carry Greybus without one - a UART or an I2C bus rathe= r than a UniPro network - +//! have to provide it themselves. +//! +//! This module implements that SVC in software. + +use kernel::error::code; +use kernel::greybus::{self, hd, protocols, CPORT_ID_MAX, GB_OPERATION_SIZE= _MAX}; +use kernel::id_pool::IdPool; +use kernel::sync::{Arc, Mutex, SpinLock}; +use kernel::transmute::AsBytes; +use kernel::{c_str, faux, prelude::*, sync::aref::ARef}; +use kernel::{new_mutex, new_spinlock}; +use pin_init::init_array_from_fn; + +const SVC_VERSION_MAJOR: u8 =3D 0; +const SVC_VERSION_MINOR: u8 =3D 1; +const ENDO_ID: u16 =3D u16::from_le(0x4755); +const AP_INF_ID: u8 =3D 0; + +const MAX_INTF_ID: u8 =3D u8::MAX; +const INTF_ID_START: u8 =3D 1; +const INTF_MAP_LEN: usize =3D (MAX_INTF_ID - INTF_ID_START) as usize; + +#[repr(C, packed)] +struct Msg

{ + hdr: protocols::GbOperationMsgHdr, + payload: P, +} + +// SAFETY: `Msg` is a POD type with no padding and no interior mutability. +unsafe impl

kernel::transmute::AsBytes for Msg

{} + +impl

Msg

{ + const GB_SIZE: u16 =3D size_of::() as u16; + + /// Builds a request of type `ty`. + /// + /// An `operation_id` of zero marks a unidirectional request, for whic= h the AP sends no + /// response. + const fn request(operation_id: u16, ty: u8, payload: P) -> Self { + Self { + hdr: protocols::GbOperationMsgHdr::new(Self::GB_SIZE, operatio= n_id, ty, 0), + payload, + } + } + + /// Builds the response to `request`, carrying `result`. + const fn response(request: &protocols::GbOperationMsgHdr, result: u8, = payload: P) -> Self { + Self { + hdr: protocols::GbOperationMsgHdr::new( + Self::GB_SIZE, + request.operation_id(), + request.msg_type() | protocols::MESSAGE_TYPE_RESPONSE, + result, + ), + payload, + } + } +} + +const _: () =3D assert!(size_of::>() =3D=3D size_of::()); + +module! { + type: GreybusSoftSvc, + name: "gb_softsvc", + authors: ["Ayush Singh "], + description: "Greybus software SVC implementation", + license: "GPL", +} + +kernel::sync::global_lock! { + unsafe(uninit) static GLOBAL_STATE: Mutex> =3D Non= e; +} + +struct GlobalState { + svc: Arc, + gb_hd: ARef, +} + +impl GlobalState { + fn new(svc: Arc, gb_hd: ARef) -> Self { + Self { svc, gb_hd } + } +} + +#[pin_data] +struct Svc { + #[pin] + svc_operation_id: SpinLock, + // Pos 0 =3D INTF_ID_START + #[pin] + intf_map: Mutex<[Option>; INTF_MAP_LEN]>, +} + +impl Svc { + fn new() -> impl PinInit { + pin_init!(Self { + intf_map <- new_mutex!(init_array_from_fn(|_| None)), + svc_operation_id <- new_spinlock!(IdPool::with_capacity(u16::M= AX.into(), GFP_KERNEL)?) + }? Error) + } + + fn new_operation_id(&self) -> Result { + let mut ida =3D self.svc_operation_id.lock(); + let res =3D ida.find_unused_id(1).ok_or(code::EOVERFLOW)?.acquire(= ) as u16; + + Ok(res) + } + + fn release_operation_id(&self, id: u16) { + let mut ida =3D self.svc_operation_id.lock(); + ida.release_id(id as usize); + } + + fn map_insert(&self, intfs: &[Arc]) -> Result { + fn inner( + intf_map: &[Option>; INTF_MAP_LEN], + count: usize, + ) -> Result { + for (id, window) in intf_map.windows(count).enumerate() { + if window.iter().all(|x| x.is_none()) { + return Ok(id as u8); + } + } + + Err(code::EOVERFLOW) + } + + let mut guard =3D self.intf_map.lock(); + + let pos =3D inner(&guard, intfs.len())?; + for (i, intf) in intfs.iter().cloned().enumerate() { + guard[usize::from(pos) + i] =3D Some(intf); + } + + Ok(pos + INTF_ID_START) + } + + fn map_remove(&self, primary_id: u8, intf_count: u8) { + let id =3D primary_id - INTF_ID_START; + let mut guard =3D self.intf_map.lock(); + + for i in 0..intf_count { + let _ =3D guard[usize::from(id + i)].take(); + } + } + + fn intf_by_id(&self, id: u8) -> Result> { + let id =3D id - INTF_ID_START; + let guard =3D self.intf_map.lock(); + + guard + .get(usize::from(id)) + .ok_or(code::ENODEV)? + .as_ref() + .ok_or(code::ENODEV) + .cloned() + } + + fn send_request

(&self, hd: &hd::Device, ty: u8, payload: P) -> Resu= lt<()> { + let msg =3D Msg::request(self.new_operation_id()?, ty, payload); + hd.data_rcvd(protocols::GB_SVC_CPORT_ID, msg.as_bytes()); + Ok(()) + } + + fn module_insert(&self, hd: &hd::Device, intfs: &[Arc]) -> Result { + let intf_id =3D self.map_insert(intfs)?; + let payload =3D protocols::GbSvcModuleInsertedRequest::new(intf_id= , 1, 0); + self.send_request(hd, protocols::GB_SVC_TYPE_MODULE_INSERTED, payl= oad)?; + + Ok(intf_id) + } + + fn module_remove(&self, hd: &hd::Device, intf_id: u8, intf_count: u8) = -> Result<()> { + self.map_remove(intf_id, intf_count); + let payload =3D protocols::GbSvcModuleRemovedRequest::new(intf_id); + self.send_request(hd, protocols::GB_SVC_TYPE_MODULE_REMOVED, paylo= ad)?; + + Ok(()) + } + + fn send_version(&self, hd: &hd::Device) -> Result<()> { + dev_info!(hd.as_ref(), "Sending SVC version request"); + + let payload =3D protocols::GbSvcVersionRequest::new(SVC_VERSION_MA= JOR, SVC_VERSION_MINOR); + self.send_request(hd, protocols::GB_SVC_TYPE_PROTOCOL_VERSION, pay= load)?; + + Ok(()) + } + + fn send_svc_hello(&self, hd: &hd::Device) -> Result<()> { + dev_info!(hd.as_ref(), "Sending SVC Hello request"); + + let payload =3D protocols::GbSvcHelloRequest::new(ENDO_ID, AP_INF_= ID); + self.send_request(hd, protocols::GB_SVC_TYPE_SVC_HELLO, payload)?; + + Ok(()) + } + + fn send_response

(&self, hd: &hd::Device, msg: &protocols::GbOperati= onMsgHdr, payload: P) { + let msg =3D Msg::response(msg, 0, payload); + hd.data_rcvd(protocols::GB_SVC_CPORT_ID, msg.as_bytes()); + } + + fn intf_set_pwrm(&self, hd: &hd::Device, msg: &greybus::Message) -> Re= sult<()> { + let req_msg: &protocols::GbSvcIntfSetPwrmRequest =3D msg.payload()= .ok_or(code::EINVAL)?; + let result_code =3D if req_msg.tx_mode() =3D=3D protocols::GB_SVC_= UNIPRO_HIBERNATE_MODE + && req_msg.rx_mode() =3D=3D protocols::GB_SVC_UNIPRO_HIBERNATE= _MODE + { + protocols::GB_SVC_SETPWRM_PWR_OK + } else { + protocols::GB_SVC_SETPWRM_PWR_LOCAL + }; + + let payload =3D protocols::GbSvcIntfSetPwrmResponse::new(result_co= de); + self.send_response(hd, msg.header(), payload); + + Ok(()) + } + + fn dme_peer_get(&self, hd: &hd::Device, hdr: &protocols::GbOperationMs= gHdr) { + let payload =3D protocols::GbSvcDmePeerGetResponse::new(0, u32::fr= om_le(0x0126)); + self.send_response(hd, hdr, payload); + } + + fn dme_peer_set(&self, hd: &hd::Device, hdr: &protocols::GbOperationMs= gHdr) { + let payload =3D protocols::GbSvcDmePeerSetResponse::new(0); + self.send_response(hd, hdr, payload); + } + + fn pwrmon_rail_count_get(&self, hd: &hd::Device, hdr: &protocols::GbOp= erationMsgHdr) { + let payload =3D protocols::GbSvcPwrmonRailCountGetResponse::new(0); + self.send_response(hd, hdr, payload); + } + + fn intf_vsys_enable_disable(&self, hd: &hd::Device, hdr: &protocols::G= bOperationMsgHdr) { + let payload =3D protocols::GbSvcIntfVsysResponse::new(protocols::G= B_SVC_INTF_VSYS_OK); + self.send_response(hd, hdr, payload); + } + + fn intf_refclk_enable_disable(&self, hd: &hd::Device, hdr: &protocols:= :GbOperationMsgHdr) { + let payload =3D protocols::GbSvcIntfRefclkResponse::new(protocols:= :GB_SVC_INTF_VSYS_OK); + self.send_response(hd, hdr, payload); + } + + fn intf_unipro_enable_disable(&self, hd: &hd::Device, hdr: &protocols:= :GbOperationMsgHdr) { + let payload =3D protocols::GbSvcIntfUniproResponse::new(protocols:= :GB_SVC_INTF_UNIPRO_OK); + self.send_response(hd, hdr, payload); + } + + fn intf_activate(&self, hd: &hd::Device, msg: &greybus::Message) { + let payload =3D protocols::GbSvcIntfActivateResponse::new( + protocols::GB_SVC_OP_SUCCESS, + protocols::GB_SVC_INTF_TYPE_GREYBUS, + ); + + // TODO: Maybe call a callback? + + self.send_response(hd, msg.header(), payload); + } + + fn intf_resume(&self, hd: &hd::Device, msg: &greybus::Message) { + let payload =3D protocols::GbSvcIntfResumeResponse::new(protocols:= :GB_SVC_OP_SUCCESS); + + // TODO: Maybe call a callback? + + self.send_response(hd, msg.header(), payload); + } + + fn conn_create(&self, hd: &hd::Device, msg: &greybus::Message) -> Resu= lt<()> { + // TODO: Evaluate if we need to add callback to NodeOps + self.send_response(hd, msg.header(), ()); + + Ok(()) + } + + fn conn_destroy(&self, hd: &hd::Device, msg: &greybus::Message) -> Res= ult<()> { + // TODO: Evaluate if we need to add callback to NodeOps + self.send_response(hd, msg.header(), ()); + + Ok(()) + } + + fn handler(&self, msg: &greybus::Message) -> Result<()> { + let hdr =3D msg.header(); + let hd =3D msg.operation().connection().host_device(); + + if hdr.is_response() { + self.release_operation_id(hdr.operation_id()); + } + + match (hdr.is_response(), hdr.request_type()) { + ( + false, + protocols::GB_SVC_TYPE_INTF_DEVICE_ID + | protocols::GB_SVC_TYPE_ROUTE_CREATE + | protocols::GB_SVC_TYPE_ROUTE_DESTROY + | protocols::GB_SVC_TYPE_PING, + ) =3D> self.send_response(hd, hdr, ()), + (false, protocols::GB_SVC_TYPE_CONN_CREATE) =3D> self.conn_cre= ate(hd, msg)?, + (false, protocols::GB_SVC_TYPE_CONN_DESTROY) =3D> self.conn_de= stroy(hd, msg)?, + (false, protocols::GB_SVC_TYPE_DME_PEER_GET) =3D> self.dme_pee= r_get(hd, hdr), + (false, protocols::GB_SVC_TYPE_DME_PEER_SET) =3D> self.dme_pee= r_set(hd, hdr), + (false, protocols::GB_SVC_TYPE_INTF_SET_PWRM) =3D> self.intf_s= et_pwrm(hd, msg)?, + (false, protocols::GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET) =3D> { + self.pwrmon_rail_count_get(hd, hdr) + } + ( + false, + protocols::GB_SVC_TYPE_INTF_VSYS_ENABLE | protocols::GB_SV= C_TYPE_INTF_VSYS_DISABLE, + ) =3D> self.intf_vsys_enable_disable(hd, hdr), + ( + false, + protocols::GB_SVC_TYPE_INTF_REFCLK_ENABLE + | protocols::GB_SVC_TYPE_INTF_REFCLK_DISABLE, + ) =3D> self.intf_refclk_enable_disable(hd, hdr), + ( + false, + protocols::GB_SVC_TYPE_INTF_UNIPRO_ENABLE + | protocols::GB_SVC_TYPE_INTF_UNIPRO_DISABLE, + ) =3D> self.intf_unipro_enable_disable(hd, hdr), + (false, protocols::GB_SVC_TYPE_INTF_ACTIVATE) =3D> self.intf_a= ctivate(hd, msg), + (false, protocols::GB_SVC_TYPE_INTF_RESUME) =3D> self.intf_res= ume(hd, msg), + (true, protocols::GB_SVC_TYPE_PROTOCOL_VERSION) =3D> self.send= _svc_hello(hd)?, + ( + true, + protocols::GB_SVC_TYPE_MODULE_INSERTED + | protocols::GB_SVC_TYPE_SVC_HELLO + | protocols::GB_SVC_TYPE_MODULE_REMOVED, + ) =3D> {} + _ =3D> return Err(code::ENOTSUPP), + }; + + Ok(()) + } +} + +struct GbHdDriver(Arc); + +impl GbHdDriver { + fn message_send_inner(&self, dest_cport_id: u16, msg: &greybus::Messag= e) -> Result { + if dest_cport_id =3D=3D protocols::GB_SVC_CPORT_ID { + self.0.handler(msg) + } else { + let conn =3D msg.operation().connection(); + let intf =3D self.0.intf_by_id(conn.interface().unwrap().id())= ?; + + let mut buf =3D KVec::with_capacity(msg.header().size().into()= , GFP_KERNEL)?; + + buf.extend_from_slice(msg.header().as_bytes(), GFP_KERNEL)?; + buf.extend_from_slice(msg.payload_bytes(), GFP_KERNEL)?; + + intf.write(&buf, conn.intf_cport_id()) + } + } +} + +#[vtable] +impl hd::HdDriver for GbHdDriver { + fn message_send(data: &Self, dest_cport_id: u16, msg: greybus::Message= ) -> Result { + let res =3D data.message_send_inner(dest_cport_id, &msg); + msg.sent(0); + + res + } + + fn message_cancel(_msg: greybus::Message) {} +} + +struct GreybusSoftSvc { + _hd: hd::Registration, + _faux: faux::Registration, +} + +impl kernel::Module for GreybusSoftSvc { + fn init(_module: &'static ThisModule) -> Result { + pr_info!("gb_softsvc (init)\n"); + + // SAFETY: This runs once at module init, before anything else can= reach `GLOBAL_STATE`. + unsafe { GLOBAL_STATE.init() }; + + let faux =3D faux::Registration::new(c_str!("gb-softsvc"), None)?; + let svc =3D Arc::pin_init(Svc::new(), GFP_KERNEL)?; + let data =3D GbHdDriver(svc.clone()); + + let dev =3D faux.as_ref().as_ref(); + let hd =3D hd::Registration::new(dev, GB_OPERATION_SIZE_MAX, CPORT= _ID_MAX + 1, Ok(data))?; + + let global_state =3D GlobalState::new(svc.clone(), hd.as_ref().int= o()); + let _ =3D GLOBAL_STATE.lock().replace(global_state); + + svc.send_version(hd.as_ref())?; + + Ok(GreybusSoftSvc { + _hd: hd, + _faux: faux, + }) + } +} + +impl Drop for GreybusSoftSvc { + fn drop(&mut self) { + let _ =3D GLOBAL_STATE.lock().take(); + pr_info!("gb_softsvc (exit)\n"); + } +} + +/// The operations a Greybus interface provides. +/// +/// A node is whatever sits behind an interface =E2=80=94 a real transport= , an in-kernel emulation, or +/// anything else that can accept Greybus traffic. This module does not ca= re which. +pub trait InterfaceOps: Send + Sync { + /// Delivers `data` to the node's `cport`. + fn write(&self, data: &[u8], cport: u16) -> Result<()>; +} + +/// A module attached to the Greybus network. +pub struct Module { + id: u8, + intf_count: u8, + gb_hd: ARef, + svc: Arc, +} + +impl Module { + /// Attaches `node` as a new module and returns the interface id assig= ned to it. + pub fn new(intfs: &[Arc]) -> Result { + let Ok(intf_count) =3D u8::try_from(intfs.len()) else { + return Err(code::E2BIG); + }; + + let guard =3D GLOBAL_STATE.lock(); + let state =3D guard.as_ref().ok_or(code::EAGAIN)?; + let id =3D state.svc.module_insert(&state.gb_hd, intfs)?; + + Ok(Self { + id, + intf_count, + gb_hd: state.gb_hd.clone(), + svc: state.svc.clone(), + }) + } + + /// Delivers `msg`, received from interface `id` on its `cport`, to th= e Greybus core. + /// + /// `cport` is the interface-side CPort id. + /// + /// Fails with `EINVAL` if no connection is bound to that pair, or `EA= GAIN` if the + /// host device has not been brought up yet. + pub fn submit_message(&self, cport: u16, msg: &[u8]) -> Result<()> { + let intf =3D self + .gb_hd + .find_connection_by_intf(self.id, cport) + .ok_or(code::EINVAL)?; + self.gb_hd.data_rcvd(intf.hd_cport_id(), msg); + + Ok(()) + } +} + +impl Drop for Module { + fn drop(&mut self) { + let _ =3D self + .svc + .module_remove(&self.gb_hd, self.id, self.intf_count); + } +} diff --git a/drivers/greybus/gb_softsvc_exports.c b/drivers/greybus/gb_soft= svc_exports.c new file mode 100644 index 000000000000..38b99c4de6ee --- /dev/null +++ b/drivers/greybus/gb_softsvc_exports.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIA= TES. All rights reserved. + +/* + * Exports Rust symbols from the `nova_core` crate for use by dependent mo= dules. + * + * This is a workaround until the build system supports Rust cross-module + * dependencies natively. + */ + +#include + +#define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym) + +#include "exports_gb_softsvc_generated.h" --=20 2.55.0 From nobody Mon Sep 28 16:22:44 2026 Received: from mail-pj1-f42.google.com (mail-pj1-f42.google.com [209.85.216.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 088BB3F1ABE for ; Thu, 20 Aug 2026 09:26:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218021; cv=none; b=G0AwC3jn2QidHmneWsJGhAaIksfXUcn4M32HbIt+txrplXWsvA3vOB1tFofRCzkbc7PevLjYFDKKsyX1GaMHocOE6U+znoTZ3/j/cc8jPabN2AteSEnMMRTJWF9kLWflINJxV908vJVJri3pQYO5X7MW/POdTEGgM0jcfGRjNh4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218021; c=relaxed/simple; bh=UuyGoF4kmMy8N8Cu2tekiMDft2rlXAE3u99nVrxSo9k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mWPlZQszkuHerAXVg8jW79/Ujv9pQJS4z61t0zlFcp3FOAEKx1uYd9W7uDdJvy+VkzYq1650ZDE7ogGkSKlFmrzepa0B2wXaPk4coeJC/d49898tP14AkfKCuF4qsVaL0ygPkPeUyNnJ90xULsjj/dxJyzYswHnJ6KEg0aXk6Rg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=wPQFewcE; arc=none smtp.client-ip=209.85.216.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="wPQFewcE" Received: by mail-pj1-f42.google.com with SMTP id 98e67ed59e1d1-38e08baf860so2062295a91.2 for ; Thu, 20 Aug 2026 02:26:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787218008; x=1787822808; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=U7XYavdSPIoY2fWb3V2p0Qog33AFOGvZrGdj1YOTpO4=; b=wPQFewcE+NOEkERuX9Z0+SlXXqKdnOax03cQGNYe3xsvSFkZ2q+xO0BFy7wpp+IRgJ soL85IE0aJCVAqRrfa8y3z9xcliIvWDjkriHWJHxIbhW6u9hL7e/aF5Cw5UPOl5E4a6B xhwDw2RsYHorhZxd1afX+r7ofmgZi7qR6hoh3SujQ7l7Bge8do6uLldhjEe/z6R8z5IL kNF1KIO0tjOWjBWFk+BAgU9BxI++F5t/HWesQWT3uikdinh7nrStmCy3uPJ4oLjrAoX9 gNJtxOEZthfJqI+339vGB9ipOi04IfiLVUkVl7wc6w2UV80TNb3SwwzZH8fQX1AQODwE atiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787218008; x=1787822808; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=U7XYavdSPIoY2fWb3V2p0Qog33AFOGvZrGdj1YOTpO4=; b=hXkEGe0SbvuR9mydSSuTpkN6Ckvoee/UhgX+oBC0jmQUM0w3NqS6EK40TT1XORiHFs v0pCmz1WU8yimVICTaBfrxLqGo6LKHxVNKnaFUESgcd/6mAgw9AihGyn81qFf2a+k9kK 7vKNehYsZdMma7WOWVqcIsungWzjVPPC+9EwAfeypwb0GhLMNXhhV8E8MJaB/mwnBDed L9R6i36jX5DlOwxz1wHm5NF7qFUoXIPYosDd97xKboyAEIdIHbUVnxigcHC7i0ySjyvO rE+WoB2DJARkLUECP7eTNox7tpdl1qzDgYXQ72dZu2bnBggQlwiSinxPE710SpG7mZHG OwUg== X-Forwarded-Encrypted: i=1; AHgh+Ro475S58ijrQS73rDImrDbAr9O0iBEx0NzUw5HvknmUn3aw+q2Ye/mXZhnkJZi8mQ5Dpc8ziUW8zPdcz+w=@vger.kernel.org X-Gm-Message-State: AFuF++nZQY1N2ArRoLo7mevG5SRtorcG1HUOcpnziGr9Tv7mrEk0Wl5b eEXxmjCJKM4ANRVhM3VLK4WkLLqex6VLaFTVHtV7Eks6AfY22RenErPfZ6aQstLzmw== X-Gm-Gg: AR+sD12tzZNeI4q4Tis+W7eW0n/iysAYFnxExAVy4HGpmQzKK1kACvJ8ComRalixdtX ClD+BbdERSVey5cnA7kohSkKrwxvDFaKqKng0Vjd6bVDA6j646YOUnFu20v0+LDahV9GklFKPj0 9RFcrpQE8Zqsj1dkJ7QMYmgi7MQ73VpArH7y6aAoRpHsllCstna+2AT6qSxakPseTz58NLR0pGP ArN9H+kYsEYDmpIbI6ReBCOjNerhdtBJqGq9KaV9RT1UfztzSW3e0Kyz/X7KPowyd2Y6OEQ54Kr tcpU6pttMjdtD88GydH5RHxmMPcqWI223uc0zN/7Lj0szZNN1A8ggGa93VHGWWNaFltgS36ui01 7E9py5LtUBzN/wqlzkjWuAFevuhwj1iPIoj90Cfnv7gFWlS312iyy+yx1PGiFYBrrGkYupOzKTc HJcsvaDOvWdjbO57yLWUOJ5iMBoIwUS2sMVHCp5mkf8GLAvAfFp3estp1knPLMN43LYWmkxdI= X-Received: by 2002:a17:90b:2d8d:b0:392:e5b1:d833 with SMTP id 98e67ed59e1d1-39581252d0fmr21049772a91.13.1787218008393; Thu, 20 Aug 2026 02:26:48 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.26.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:47 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:48 +0530 Subject: [PATCH 6/7] greybus: Add Rust UART node driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-6-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=12132; i=ayush@beagleboard.org; h=from:subject:message-id; bh=UuyGoF4kmMy8N8Cu2tekiMDft2rlXAE3u99nVrxSo9k=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgcmcx5fQh2qYflEPpgEjhJIEc+eJYImU/T+ pxxsFxMhtKJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHAAKCRAFzvXHieVa dPemD/9b3IKtiGh4p4NLG6UoaiRrIA0kMg9nAqiLgYCSqP4I7a99CxMaFCc9nmpzvkq8v31Tmov 6kxSPylmQMBcCOasM76NAIWHIQEWUVkhJz7EUgfVwrRAiZXj9IPwRtxgue2GQ7jjAS4qV3LbFbN hJlN0NU9uT1yAize9W8jdn0yxu6D+5iGK2W/Y5qYcm0283seTnphnIS9X7dr85ZEqa6JBCYJjhs l2q10hTg97dHAusY1GOch0JG10QV3H/IxDt9zX4FZXnPfj6QVD6G8feu/EQ701UjzoIjshl1xOJ 2MFLKpNcxX29bvPm5GgfUgzoNzEhDy7NFH+sQmBmSY3QA97RQ/uNE5QvP8XIhyYzIFRszFl0S7V cJeelFGx62CIBwlTfy/wgrDIiAmYqPrl1NmsQbBi7IyRgVZgSTM6Tio/8Md5gCm4BXBw5eNOnF7 JQS0KZc0lBahablpIk41cY3vkwHAdkVqLkTYBY5WZay3liWdwmIyq62haZDaLWUEkK3Wl4PAkZK mJYTTpICNSHMeksrpnQ/6Rsh4/pIE3yBYWEF+x8aW7AMuFouyPO3Rw8RStc1ARuPT8vg3x7qqiT mr02PqoZ7fcPbWeF6bmV+JChfZ8vkK5WWbOIUvBaMz9Qkve5TqLKmgB4CjlXNpEfQc73k61atgX R7oclwSxexixVEg== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 Add a driver for Greybus nodes attached over a plain serial port. The node is registered with the software SVC (gb-softsvc), which handles the SVC protocol on behalf of the AP, so no dedicated coprocessor running SVC firmware is needed. Greybus messages are carried over HDLC framing on the wire. Each frame carries a one-byte address (0x01 for Greybus) and control byte, followed by the 16-bit CPort ID and the Greybus message itself. Port parameters are taken from the firmware node: "baudrate" if present, otherwise 115200, with flow control and parity disabled. Since gb-uart-node imports types from gb-softsvc, Rust to Rust calling setup from nova-core [0] is being used. [0]: https://lore.kernel.org/all/20260622-nova-exports-v5-0-6191773fc977@nv= idia.com/ Signed-off-by: Ayush Singh --- MAINTAINERS | 6 ++ drivers/greybus/.gitignore | 1 + drivers/greybus/Kconfig | 15 +++ drivers/greybus/Makefile | 48 +++++++++ drivers/greybus/gb_uart_node.rs | 231 ++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 301 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3ba56cdbf056..037a87b74800 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11334,6 +11334,12 @@ L: greybus-dev@lists.linaro.org (moderated for non= -subscribers) S: Maintained F: drivers/greybus/gb_softsvc.rs =20 +GREYBUS UART NODE DRIVERS +M: Ayush Singh +L: greybus-dev@lists.linaro.org (moderated for non-subscribers) +S: Maintained +F: drivers/greybus/gb_uart_node.rs + GREYBUS SUBSYSTEM M: Johan Hovold M: Alex Elder diff --git a/drivers/greybus/.gitignore b/drivers/greybus/.gitignore new file mode 100644 index 000000000000..ff9c4a3539b4 --- /dev/null +++ b/drivers/greybus/.gitignore @@ -0,0 +1 @@ +exports_gb_softsvc_generated.h diff --git a/drivers/greybus/Kconfig b/drivers/greybus/Kconfig index 30bc491841e1..b6f687e6da1a 100644 --- a/drivers/greybus/Kconfig +++ b/drivers/greybus/Kconfig @@ -53,5 +53,20 @@ config GREYBUS_SOFTSVC To compile this code as a module, choose M here: the module will be called gb-softsvc.ko =20 +config GREYBUS_UART_NODE + tristate "Greybus UART node transport" + depends on RUST + depends on GREYBUS_SOFTSVC + depends on RUST_SERIAL_DEV_BUS_ABSTRACTIONS + select RUST_CRC_CCITT_ABSTRACTIONS + help + Select this option if you have a Greybus node connected over a + serial port. The node is registered with the software SVC, which + handles the SVC protocol on behalf of the AP, so no dedicated + coprocessor running SVC firmware is required. + + To compile this code as a module, choose M here: the module + will be called gb-uart-node.ko + endif # GREYBUS =20 diff --git a/drivers/greybus/Makefile b/drivers/greybus/Makefile index e6f594128802..81151963c01e 100644 --- a/drivers/greybus/Makefile +++ b/drivers/greybus/Makefile @@ -28,3 +28,51 @@ obj-$(CONFIG_GREYBUS_ES2) +=3D gb-es2.o obj-$(CONFIG_GREYBUS_SOFTSVC) +=3D gb-softsvc.o gb-softsvc-y +=3D gb_softsvc.o gb_softsvc_exports.o =20 +obj-$(CONFIG_GREYBUS_UART_NODE) +=3D gb-uart-node.o +gb-uart-node-y +=3D gb_uart_node.o + +# Export Rust symbols from gb-softsvc only if gb-uart-node actually refere= nces them. +gb-softsvc-export-deps :=3D $(if $(CONFIG_GREYBUS_UART_NODE),$(obj)/gb_uar= t_node.o) + +rust_needed_exports =3D \ + { $(if $(strip $(2)),$(NM) -u $(2);,) echo "__DEFINED_RUST_SYMBOLS__"; \ + $(NM) -p --defined-only $(1); } | \ + awk -v fmt=3D'$(3)' ' \ + /^__DEFINED_RUST_SYMBOLS__$$/ { defs =3D 1; next } \ + !defs { if ($$NF ~ /^_R/) needed[$$NF] =3D 1; next } \ + defs && $$2 ~ /(T|R|D|B)/ && $$3 ~ /^_R/ && \ + $$3 !~ /_(init|cleanup)_module$$/ && \ + $$3 !~ /__(pfx|cfi|odr_asan)/ && \ + $$3 in needed { printf fmt, $$3 } \ + ' + +quiet_cmd_exports =3D EXPORTS $@ + cmd_exports =3D \ + $(call rust_needed_exports,$<,$(gb-softsvc-export-deps),EXPORT_SYMBOL_RUS= T_GPL(%s);\n) > $@ + +$(obj)/exports_gb_softsvc_generated.h: $(obj)/gb_softsvc.o $(gb-softsvc-ex= port-deps) FORCE + $(call if_changed,exports) + +targets +=3D exports_gb_softsvc_generated.h + +$(obj)/gb_softsvc_exports.o: $(obj)/exports_gb_softsvc_generated.h +CFLAGS_gb_softsvc_exports.o :=3D -I $(objtree)/$(obj) + +ifdef CONFIG_MODVERSIONS +# The C export shim declares Rust symbols as `extern int`, so reuse its ex= port +# list but generate symbol CRCs from the Rust object instead of the shim's= DWARF. +$(obj)/gb_softsvc_exports.o: private cmd_gensymtypes_c =3D \ + $(call getexportsymbols,\1) | \ + $(objtree)/scripts/gendwarfksyms/gendwarfksyms \ + $(if $(KBUILD_GENDWARFKSYMS_STABLE), --stable) \ + $(if $(KBUILD_SYMTYPES), --symtypes $(@:.o=3D.symtypes),) \ + $(obj)/gb_softsvc.o +endif + +# Output nova-core's crate metadata for use by nova-drm at compile time. +RUSTFLAGS_gb_softsvc.o +=3D \ + --emit=3Dmetadata=3D$(objtree)/$(obj)/libgb_softsvc.rmeta + +# Allow nova-drm to import nova-core's types. +$(obj)/gb_uart_node.o: $(obj)/gb_softsvc.o +RUSTFLAGS_gb_uart_node.o :=3D -L $(objtree)/$(obj) --extern gb_softsvc diff --git a/drivers/greybus/gb_uart_node.rs b/drivers/greybus/gb_uart_node= .rs new file mode 100644 index 000000000000..125812246758 --- /dev/null +++ b/drivers/greybus/gb_uart_node.rs @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Greybus UART Node driver + +use kernel::crc_ccitt::crc_ccitt; +use kernel::device::AsBusDevice; +use kernel::device::{Bound, Core}; +use kernel::error::code; +use kernel::sync::aref::ARef; +use kernel::sync::{Arc, SpinLock}; +use kernel::{new_spinlock, of, prelude::*, serdev}; + +use zerocopy::little_endian; +use zerocopy_derive::{FromBytes, Immutable, KnownLayout}; + +const HDLC_MAX_FRAME_LEN: usize =3D 256; + +const HDLC_FRAME: u8 =3D 0x7E; +const HDLC_ESC: u8 =3D 0x7D; +const HDLC_XOR: u8 =3D 0x20; +const HDLC_EXPECTED_CRC: u16 =3D 0xf0b8; + +const ADDRESS_GREYBUS: u8 =3D 0x01; + +#[repr(C, packed)] +#[derive(FromBytes, Immutable, KnownLayout)] +struct GreybusFrame { + cport: little_endian::U16, + msg: [u8], +} + +struct HdlcRx { + rx_buf: KVec, + rx_in_esc: bool, + sdev: ARef, + node: gb_softsvc::Module, +} + +impl HdlcRx { + fn new(sdev: ARef, node: gb_softsvc::Module) -> Result= { + Ok(Self { + node, + sdev, + rx_buf: KVec::with_capacity(HDLC_MAX_FRAME_LEN, GFP_KERNEL)?, + rx_in_esc: false, + }) + } + + fn frame_finish(&self) -> Result<()> { + if self.rx_buf.len() < 4 { + return Err(code::EFAULT); + } + + let crc =3D crc_ccitt(0xffff, &self.rx_buf); + if crc !=3D HDLC_EXPECTED_CRC { + dev_warn!(self.sdev.as_ref(), "CRC failed {}", crc); + return Ok(()); + } + + let addr =3D self.rx_buf[0]; + let _ctrl =3D self.rx_buf[1]; + let payload =3D &self.rx_buf[2..self.rx_buf.len() - size_of::(= )]; + + match addr { + ADDRESS_GREYBUS =3D> { + let frame =3D GreybusFrame::ref_from_bytes(payload).map_er= r(|_| code::EINVAL)?; + self.node.submit_message(frame.cport.into(), &frame.msg) + } + _ =3D> Err(code::EINVAL), + } + } + + fn rx(&mut self, data: &[u8]) -> usize { + for (count, i) in data.iter().enumerate() { + match *i { + HDLC_FRAME =3D> { + if !self.rx_buf.is_empty() { + if let Err(e) =3D self.frame_finish() { + dev_warn!(self.sdev.as_ref(), "bad frame: {e:?= }\n"); + } + } + + self.rx_buf.clear(); + self.rx_in_esc =3D false; + } + HDLC_ESC =3D> self.rx_in_esc =3D true, + _ =3D> { + let c =3D if self.rx_in_esc { *i ^ HDLC_XOR } else { *= i }; + self.rx_in_esc =3D false; + + if self.rx_buf.push(c, GFP_KERNEL).is_err() { + return count; + } + } + } + } + + data.len() + } +} + +struct GbNode { + sdev: ARef, +} + +impl GbNode { + const fn new(sdev: ARef) -> Self { + Self { sdev } + } + + fn write_all(mut crc: u16, bound: &serdev::Device, data: &[u8])= -> Result { + for i in data { + if *i =3D=3D HDLC_ESC || *i =3D=3D HDLC_FRAME { + let buf =3D &[HDLC_ESC, i ^ HDLC_XOR]; + bound.write_all(buf, 0)?; + crc =3D crc_ccitt(crc, buf); + } else { + bound.write_all(&[*i], 0)?; + crc =3D crc_ccitt(crc, &[*i]); + } + } + + Ok(crc) + } +} + +impl gb_softsvc::InterfaceOps for GbNode { + fn write(&self, data: &[u8], cport: u16) -> Result<()> { + // SAFETY: `GbNode` only exists while its serdev driver is bound, = so the device is in the + // `Bound` state for the duration of this call. + let bound: &serdev::Device =3D + unsafe { serdev::Device::from_device(self.sdev.as_ref().as_bou= nd()) }; + + let mut crc =3D 0xffff; + + bound.write_all(&[HDLC_FRAME], 0)?; + + crc =3D Self::write_all(crc, bound, &[ADDRESS_GREYBUS, 0x03])?; + crc =3D Self::write_all(crc, bound, &cport.to_le_bytes())?; + crc =3D Self::write_all(crc, bound, data)?; + + crc ^=3D 0xffff; + Self::write_all(crc, bound, &crc.to_le_bytes())?; + + bound.write_all(&[HDLC_FRAME], 0)?; + + Ok(()) + } +} + +#[pin_data(PinnedDrop)] +struct GbUartNode { + sdev: ARef, + #[pin] + rx: SpinLock, +} + +impl GbUartNode { + fn init(sdev: &serdev::Device>) -> Result { + if sdev + .set_baudrate( + sdev.as_ref() + .fwnode() + .and_then(|fwnode| fwnode.property_read(c"baudrate").o= ptional()) + .unwrap_or(115200), + ) + .is_err() + { + return Err(EINVAL); + } + sdev.set_flow_control(false); + sdev.set_parity(serdev::Parity::None)?; + + let node =3D gb_softsvc::Module::new(&[Arc::new(GbNode::new(sdev.i= nto()), GFP_KERNEL)?])?; + + HdlcRx::new(sdev.into(), node) + } +} + +kernel::of_device_table!( + OF_TABLE, + ::IdInfo, + [(of::DeviceId::new(c"beagle,beagleconnect-freedom"), ())] +); + +#[vtable] +impl serdev::Driver for GbUartNode { + type IdInfo =3D (); + type Data<'bound> =3D Self; + const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); + + fn probe<'bound>( + sdev: &'bound serdev::Device>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { + dev_dbg!(sdev.as_ref(), "Probe gb_uart_node.\n"); + let rx =3D Self::init(sdev); + + try_pin_init!(Self { + sdev: sdev.into(), + rx <- new_spinlock!(rx?, "gb_uart_node::rx"), + }? Error) + } + + fn receive<'bound>( + _sdev: &'bound serdev::Device, + this: Pin<&Self>, + data: &[u8], + ) -> usize { + let Some(mut guard) =3D this.rx.try_lock() else { + return 0; + }; + + guard.rx(data) + } +} + +#[pinned_drop] +impl PinnedDrop for GbUartNode { + fn drop(self: Pin<&mut Self>) { + dev_dbg!(self.sdev.as_ref(), "Remove gb_uart_node.\n"); + } +} + +kernel::module_serdev_device_driver! { + type: GbUartNode, + name: "gb_uart_node", + authors: ["Ayush Singh "], + description: "Greybus node connected over UART", + license: "GPL v2", +} --=20 2.55.0 From nobody Mon Sep 28 16:22:44 2026 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EA7E13EAC84 for ; Thu, 20 Aug 2026 09:27:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218026; cv=none; b=Vcx2KL54XpU/1P21SIKzr+1pZXwURUsM++6IvxgKl9VW2VStzbTYcd+CqZvawZ+LwQrmUoHOWZvpHXWtZ4vN17G2ACO7cq36kFHBX1hhxHDF2smrqMVPM1dEP3gapXdAsUv/tMkKYUnSjvwzwGHeprLmqLUNteBH9DWNmrCNUhc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787218026; c=relaxed/simple; bh=w79yUOdI2hQLJL4IbCf3z4kqwz8B5oITUq/IrpAqPBg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GMWbdYivEBLvBXmhG8hIPe6KX7nFP/FPTMXVCK12Lhspktxjbwjem1FZrETuMae++8wkNG51Nl3TjavgBSvfobED4CyNkFniBNliu52JxBppffWSZ5XZaMMSNsc4HVZMXCPcIA7mcXlCpe60MgrDn+OElaXnfQZC8hz4MmR2WuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b=vazgPwZ1; arc=none smtp.client-ip=209.85.214.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=beagleboard.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=beagleboard-org.20251104.gappssmtp.com header.i=@beagleboard-org.20251104.gappssmtp.com header.b="vazgPwZ1" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2cf27856f9cso19340675ad.2 for ; Thu, 20 Aug 2026 02:26:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard-org.20251104.gappssmtp.com; s=20251104; t=1787218017; x=1787822817; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=R1AhOQzF6qMwl/x9fl17N+mSr6gwpeCsEPQzUK1y+w4=; b=vazgPwZ1tR7UJPV5aWqeYb+rMt4DTIeMonvazbNChyGUIHfJMthoJMtSPZTXZxaHIh t3NcD2LWZLMLdJl970JNAbz/yr1nYDvuTKKBi8bGmUqrUtYMGhQTic2eadIxlcghvyNc KDF3T9kqiyAwDYOV1g+CPbMz2DDLmcAjgXL4pYx04oR/f+RptKed90ZkV4bf53mcZfDc 4DF0EIgwIzNi4L0zpATJB7dfFLfr/X16dKuGEB/9ThRgFaq4/r8ZyOJQN/vbhLQ02BIP sCoCCoJ6la+8ouBZsUqIU1mOQdPP4XXDpiYum6W0IuPNi3AIgeyYOnjECiZtDoPr3sUS Y2OA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787218017; x=1787822817; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=R1AhOQzF6qMwl/x9fl17N+mSr6gwpeCsEPQzUK1y+w4=; b=Id3mix23ZdeAupaxNSL8Wil/ytRb07qsQzJ2wxN+fb6wLSk/FlQAIlnmrtaxRpCtsP oxCYsf6y0Vud1AoSPLnLuZ+nEpJyxOOMhCANyXpEP/4TQbnc6Bnhc4bGpqgmCzuoC5XE SG0W9AI5xmFaIHF/7+JPGoAEIfm7AdTSPCDd/JOzo1xJqQDrzecN+udj9DMKsZgzdNqO efYL7XAxb37064JVUn1GcyrPHgiE1zM+r7PrXRePbCGRNw4/kO9r9L5wpQLLsN7znlY3 6wyJyZlayUkmn+CZPLkZ/aNQV72aqQjlgvuKZD6utzp9omHLQfjIF19V6G5LAotOl8eR z+lw== X-Forwarded-Encrypted: i=1; AHgh+Rrr1wye7oGCFscJrt3I5JW30GmggzZpwyG9UtH3i9aFqgdf0OwUJQnZFzG1i0+U7VVNOBcmHtnSsRhI3O0=@vger.kernel.org X-Gm-Message-State: AFuF++kjLMION74WF7MZSGPSiY0OnlwU2JspHehsCjzzBffuuMlYSx0K X17IqadZfw81bCtV6Bw3/IhtN9zTBD3mXR3pqzJp6+9CV8NCUgN8rVgiNJKHeExh5w== X-Gm-Gg: AR+sD10jDpVOIZS9ZBC3WerkOllE7Gde9Sl18RhKES1KPsFw97j1O6eO+F5dgeUED8V ciTLoJSOMLRwMYdxPduqcHCFLv7GMtnAuKGCvgo97NxcKqscOkw+08ZSNLbR+if51S/pH/4xLYz iiwOA/dXnYHIJbR3wOaENGFYCnnmrrNEWpegr+V+CCtPhvD5HtJ1Go4x26sAQkICW7d2gVUTvPL vAM7oWMTT1KogfdTCqGy8pePKTky5OM8yE4m+AUrq9wMvuU5Gi3U61052u9LNJTaKHz/+ckrDC4 AdQaBTBnqBMn3Q3jgxpToLqwiBDoL+d8+8QJJqsax23tpanDvVHOuQUxJup7wTzD6zImjqtZ+GR xY084ic9UJqukZ8/HRsXd5RvGPeUzGrA1OrDVJAt+8ppbIoXyj/aAMdT/Kq4J8q7KGbidVOepRx MX7dkqjF14ftJODJRTD+F4ZTmjnjsVnO8zzVFZ4LFiOBC2biJztRlxlq+sW6x2wLjtp9T1QhI= X-Received: by 2002:a17:90a:f94f:b0:37f:fdc8:71b4 with SMTP id 98e67ed59e1d1-39580840397mr21463129a91.2.1787218016816; Thu, 20 Aug 2026 02:26:56 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-1416ad6060asm25903254c88.6.2026.08.20.02.26.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 02:26:56 -0700 (PDT) From: Ayush Singh Date: Thu, 20 Aug 2026 14:55:49 +0530 Subject: [PATCH 7/7] dt-bindings: beagle: Add BeagleConnect Freedom Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-gb-uart-transport-v1-7-282da14ab7b7@beagleboard.org> References: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> In-Reply-To: <20260820-gb-uart-transport-v1-0-282da14ab7b7@beagleboard.org> To: Jason Kridner , robertcnelson@gmail.com, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Eric Biggers , Ard Biesheuvel , Ayush Singh , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: greybus-dev@lists.linaro.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-crypto@vger.kernel.org, devicetree@vger.kernel.org, Ayush Singh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1989; i=ayush@beagleboard.org; h=from:subject:message-id; bh=w79yUOdI2hQLJL4IbCf3z4kqwz8B5oITUq/IrpAqPBg=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqhsgdk+2/YoCnAykJc4VseJbyp9e2JuEppqzLM dOwze3SfKaJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCaobIHQAKCRAFzvXHieVa dIydEACs+TOA7byKJIBq0ZJy9AhQD9KKPx8TPCq3IFCyu+RhFza/NuLVOW/hlxGBt872nBLOmGE g29SbEJ+IZPUE2kylIK0T2c42AwlEVuqFcGo3avVQFnuoytZZiLP/pualcCBE0ARsiFsLfTdYLV IV34kfl/Xq0hZLPPbjZrfE0VRrNCbZ8MhqHnoC+N4oyyop99U3KVOm6AMAEg3f/x59S0n06wFS5 R2d+tV0YtGmnlL8mNYdKmFTlkdpN3CHbuSJbiq31XuxD1kAKJ8FqoIOMdWVbsKHP0FkFL7e6iYY DHeUcsYgBGrsrJhSbC+pncFA96kf+YxK8+KJN1co9oakx5K6BuX6X0ynOyzVIHY+IKLjHjIn8gI i2fOBiqjmH08Om+QiLzT+33bY+MvHpghAie8h19jrJvmkOYzxJNjccqUB2iKXiPUb4MqkLJYuZE pmi4CvQ/rY7bLZq3H+HirrPuQNY1I6VE1QNQscJ4vsNjQyJg8DaIJ5mxENKxrIZp2MG3dILDgm7 Znyzz1+quLi8SmIy0Hc3kOvqCHTNJ5WTNjltYE9ZHdeN9mtue231kIhlz3pBtuclduahHIfa86t e23ZAvsQqM3gFUiDR/0m6moQhTPNJx5r6rK5mb4N8JDqAJgtGo2tG0qAhgvZdFC+ZhJ0zfRYOMK N68ke+r7bFWexAA== X-Developer-Key: i=ayush@beagleboard.org; a=openpgp; fpr=DFCC131EF24F2D656FA504D605CEF5C789E55A74 Add devicetree bindings for the BeagleBoard.org BeagleConnect Freedom, a wireless-enabled board based on the TI CC1352P7. The board exposes an MCU that can be attached to a host over USB, UART, SPI or I2C, and is described as a child node of the corresponding bus. Signed-off-by: Ayush Singh --- .../beagle/beagle,beagleconnect-freedom.yaml | 30 ++++++++++++++++++= ++++ MAINTAINERS | 1 + 2 files changed, 31 insertions(+) diff --git a/Documentation/devicetree/bindings/beagle/beagle,beagleconnect-= freedom.yaml b/Documentation/devicetree/bindings/beagle/beagle,beagleconnec= t-freedom.yaml new file mode 100644 index 000000000000..5a246f81261e --- /dev/null +++ b/Documentation/devicetree/bindings/beagle/beagle,beagleconnect-freedom= .yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/beagle/beagle,beagleconnect-freedom.yam= l# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: BeagleBoard.org BeagleConnect Freedom + +description: + The BeagleBoard.org BeagleConnect Freedom board connected over USB, UART= , SPI or I2C. + +maintainers: + - Ayush Singh + +properties: + compatible: + const: beagle,beagleconnect-freedom + +required: + - compatible + +additionalProperties: false + +examples: + - | + serial { + mcu { + compatible =3D "beagle,beagleconnect-freedom"; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 037a87b74800..49c6dac72748 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11338,6 +11338,7 @@ GREYBUS UART NODE DRIVERS M: Ayush Singh L: greybus-dev@lists.linaro.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/beagle/beagle,beagleconnect-freedom.y= aml F: drivers/greybus/gb_uart_node.rs =20 GREYBUS SUBSYSTEM --=20 2.55.0