From nobody Mon Sep 28 03:43:38 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (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 8B9023A168E for ; Thu, 27 Aug 2026 07:55:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817304; cv=none; b=uy5B9aZ+6fLbzwI1zekoNCtKnUI7DuoWlDEedvX7cqNS5k3nL3tqn6DVk0E9zpgKG4/bvDJYQ9tlsyRh9uu2FBIdAMKrnb61FGVd4dMUfpjvt83Z3293mlm9BmEF+izjVk1eKW1UhSrqNOZ/5p8Q93VpqbxiWzMLZ2ei9B544j4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817304; c=relaxed/simple; bh=3v8CbSbKdFVV/RjS8CpC/g5rvbPZ6MrtTulOIvBnDLU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ICRhkllR0gUwrIMWxWfbPMfsyuyHLnwJMnKi1mBzrfpRzw4j54Haw3D4tV4IU1X5qrRZqfbQm/0+JqPkh3m6lkHd9GHAiuT5gtVFTSOQg1iVcGtB/IAv/ELQbDI+xVaAdrX+elFDftJgXFM1wM92915cZhrj4wysVYfc8YJKR5w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=hC03qcdH; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="hC03qcdH" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2cace91f112so21184385ad.0 for ; Thu, 27 Aug 2026 00:55:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817302; x=1788422102; 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=hC03qcdHPnN7GGM8AAhRHWXJuNCMZ6N1z91v/OOP1moqDBOntZmrbwppqXyBUe8gF1 rzjvbpSuEM/IcbLtoKMHkuPt33RwNScCQrAMBYlJ24oBKltgq92BYwCt42+F6ShqIr9T umxskpEyI496G/Wel1k12zYIOUDW6rlXcKBQdPHZSIFnPgzknAk8R46HSutaF+LypoLC tkGymW7P1uBOIjgvR/jX4RTi6nKjGTPKRXJE+ZbV/A/XHyZTYaBFj58a/CL9lLCdT0ro /TztXl2NWG9tzkMfLh4DuucNXDJSoZEPYeYYkTEyr2G55WycG6IqeYInaSHe2B4q5sAE kanA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817302; x=1788422102; 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=Poq4Fd7oqMvOfZD2CsF3LWXKTZNeCjxTyPtPNAEIcYRtv/f/5oIHf9kPqIyFaVEMJa KcMqmUVRtEdvOlHStWtNKkTtab9l9p7rYP62sru3FwynC3AouKAdkIG0JpHeCOzifmA5 a+TG8fmyy1QUCsNPJxlKE1+qD2vzwL4QxsGWE64RXqqeAlP/AJs7vM5HIWEM1KErCN6k kA1pEXuVeLo9mVvaDqjg7FnSCGcR1HAGUh2o1m2mYttLebFIaajq/2kJYAAmnlvcsx9i UsNF5jTjgeHcCuvfAKOML2YVSUvcbVImUGR623IKRnbi/kNXNmQpavP0tYOenTSUGvVV FgeA== X-Forwarded-Encrypted: i=1; AHgh+Rr35V4ZmjbeOCL97oSk4LgYgoZdmEyUG8dgZzleBilPIh2efaGQdekvjQj6ELUMMkYEb+EppVtCWRFE61M=@vger.kernel.org X-Gm-Message-State: AFuF++kqv0LzAdhieaMF/phSvw8Jk9dD0V6uuv4gqiG/Y0yNVYU/p0Un yHtTdHlWllEtmSCD0Vfb7qRPt7Y3ohn1G4ZqjQ/xkAP/hVMxLV2ujVI5tgwrn/j3Yw== X-Gm-Gg: AR+sD13dA5fePnaZddAxDNDISh7vSJ7eyWmExOEzXjWapp6bzRWLWt9Z2s/DSrY2Zhy 2r9Bk+eD41mFr8SaWGwXuxacZua5FU6TDKE2VLmx3vXtdLKN2UdU4RzKWVdguFU7PRuw1nrbg2k FXJ5+ZAyrYEv/2z6dOFtsMRRBPcqYfURN6RJjNdQT8n9aG7rMqCi+Aw8Wm2IIzXcrG863qJwgAc 04MzTbzhrYjTV7QpvJu8yiIGbdQ3RmW8Y/Tc60rijwt4mm62885vzhbvcwmbNFa2qG2A8s6Vr2A XUxt+5x1iajZGGQJ0dfSHwDAIPuGrkWr/bphYps3UgOz/eDagO2rSem1HSV+EDLj5DG5SnSTzJH M6bSPxxzwnP36i+9yzlpiKYIAGUGLNbcgOgFXq0rY6MVk35VVODW07UZtPysk2cnv04Cr6P3Y9p bbeMskeUWfFfIIuvboFzhXSwEsNtxvVbbEJPWvTfsVwHX3PD2oasSOSfcYEFJtFtjX6MvfeSM= X-Received: by 2002:a17:903:1b08:b0:2d0:cc92:f7af with SMTP id d9443c01a7336-2d707b7f5bemr258746215ad.9.1787817302358; Thu, 27 Aug 2026 00:55:02 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.54.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:02 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:37 +0530 Subject: [PATCH v2 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: <20260827-gb-uart-transport-v2-1-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqj+1CLUFLerogpS5ZCSHvZw9AnT4KeCY/SKw9I Hl0M5621b6JAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCao/tQgAKCRAFzvXHieVa dBAQEADKlaLCEnodJOu85JwPawJP8k4rG1FjSXhM/P8a0Q3XYUmnlO5mKFPaLNF1wEUA/S2b6bc mtRVU4uhnqLtlz2kZ6un4YINZJzsCnFPw/dTitp8kUYJAPByepP6DgWc4dvtyVwmkl0Z7dZ7isl 9nwKdv7C/3xDaC8TT9auZV5Xr0LNseSkDjQrDbMAtq7k+ReyAAIvT8sNAIfmReFgg0814XheuLO apPS44AckJQTR4VyhiVOJQRG4VwC+A8gkPJdO3e90eUMmxgFnZRytv5VBy7/+Ps4RzV0Dx5dXsd /rP55KTbE16EMtuHlwdjRJq1omvCYrCtg14ouPphD5I6YsrCclByo5mMyLn5gjeNmZGh3q/i3Kg 65K/l2fqJi0pBjkJjus0C8wuTSwZGSY3B8ifEv/rD5WorBkxWdEPjzkTdX2kobq4023xdYHeWEm sTHu/ddXE0Dxur4/ckXjOiLsRtwFmocFh6m75rSkhmrqfCzYzMeiWJmM2+u7wOVgqwrABum9/Qe wqD2TLv1/QtGg02TdSTmUFnM3XR/ePE1MeSWCluV6K4X0vszIEruXz/Y1Un1jrEX/SHsFygeQj8 Fcg0WXo0UgEXvHG8+tbpAPOAXDLLBn9DkUsUvAb8q3denbl+E3kq1y7cNXkQfu8kM/0QvBu+Rcb uTjUmRqsJg4ntbA== 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 03:43:38 2026 Received: from mail-pf1-f175.google.com (mail-pf1-f175.google.com [209.85.210.175]) (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 AD64E2E7F25 for ; Thu, 27 Aug 2026 07:55:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817313; cv=none; b=H6oZo1XJ3Mbko3t3+h9H7JMCVMe3ScWa5eviy0TRMDQWOPHfJU/gIkQ54HW05FrDvgssRA3jglP055otOLbmW78RfUdsBeb8g5l28fWX80EBxDnOks95qxTP9YyiWnLk0RdDancGkEvXomLGpox9Frw87Unaqm/N1shSjH2Vvl4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817313; c=relaxed/simple; bh=chploxg01RCtkX+bkpeAfG8l7gk0FSv0pjMUj9gd69g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VwomxeFj4y3yMK0glmFdjHFtIF5DcLaYYbYi87Nt62TykntsyAX0VMzEJ4F0Sv0te+iKIbWHbFFRyQNSyaOhoxDHbYhdlEVY2LdMHq33gRUfIxGZGY5TE+RHCy3Q6VgHsMmlY8YIgCdpHevWSd4Gzdk0lTXaRnvxY2beSJEXofg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=QfHzokXE; arc=none smtp.client-ip=209.85.210.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="QfHzokXE" Received: by mail-pf1-f175.google.com with SMTP id d2e1a72fcca58-8548db7428aso912051b3a.1 for ; Thu, 27 Aug 2026 00:55:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817312; x=1788422112; 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=VgkBfW7YLSVyPZj/IxEMEbW8eMDtz2sSR2ELowijJwk=; b=QfHzokXE5dvVPTf1vFyeu929zZFeldrPt4r/MBfitTixGUgQBnGhgMuBVyfGcsnTvA NI3h8lrmuxG0P2AO5v00p6lwW69HupTXIg/IyoWdK94xO61FKI3SbPdIhGQjWpE5dt3V t99uIWuMuDTtDtpHcwp0DQFlQfvJ2rbw/jj6maN4Z5M2DFf06OpjGWNxaX08//3FBw1K Zq0CbS4XlL8O5jhJplo5Lcq8I4mvEKkipEUrmLZEHEdaoHveKN4OfUMxN7kHyUFXN2Ll 6ZSrt9XdUYuP3XhMvN6n5bAaAZDOSYh1Ki1FyQMwg44mtPG7YJQRW091zWodLzIa9ylq W3Bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817312; x=1788422112; 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=VgkBfW7YLSVyPZj/IxEMEbW8eMDtz2sSR2ELowijJwk=; b=LwLgUw5+3puuzYRGiGD5lQYkPqx+RHQClQTvkcG/s2+IdRzo7fr62ziONmgarjtN20 Hl8owFFBzvD8UcbFWO5XqMpYe7a0K2038NmnCDk5/7m6oCrpV/DdI1VcUgWEAvd1Yq+Q OSFPpNF6eAgPmadAKG8R/PCWw9fI3Ww47exouTZrobyL2FIC/WYu+Ka6cTvJYgpjDOvY xUYb8QkVODagLnq/cbHDrjA94jSg/f/lABX1K6hT6gO6Ummhmdjydw+OjBGJrXo8cipo t2nA1p8MrL63KgbUFadTuQf4ii5OkmVFSghGhGbbny78Ig7+0MeBG/CNCBwuStf9A7VE NlXg== X-Forwarded-Encrypted: i=1; AHgh+Rp0bnTj21UfXMAAwBw01eCMicsY3k+xBbp2tXde+s1Uq0YlniWBCdLVYFCZLrVeuNjloN1MFBFkQ8IKLaA=@vger.kernel.org X-Gm-Message-State: AFuF++ktEo2eRSiK/MBAzEnphdQtsYarAoKv2POfl+hrxqXdTuvlKoI1 mQG6VUwu9ZT/ObT8fDILyp5F18ZPPOwjnJXxWc3c5zbQGjJPtA8TQYzXUxaA4Um34Q== X-Gm-Gg: AR+sD12TAzT9wMiYtVw9MvHTJRU7VWXRczV/GX1MeOml3rI0wR9LKQLw9yP99kQzX8U agZ2/mmgvSbi9pzE1jQeb7rt3ocU1UO2lY18Tsv7jv9nal5sNTnFNHesYmT8Ie8XtvXm2e4XZqF mfDTbcArH7aei+yevxKHZ2kh52YTJ5+AsHLDh84C/bxKVQ93iw9XKwrWRUvMLFx58Snsc97phIR 2zEYaFAEkKjb1YIp7U4lu4zo0dqCVlpxSKHbCefbsz/ebdyyy7CD+xaqkTKER9x6ZvPjzzAp0kI WJJcVhJIzQpNSJcZU86A0eHavn+zvLJfBS/ADZUB9O4q9d4OUWc7JNAfBgJvEA46CEd4wjFYP/j dXBMSWBQZtgJfZY7I0r1wc56k2Yhr7PlCL1wesrTUMN66FmmsQBomCwqPmjzQ1cnqtur+Uy1Mhn IRw6tiWOZ/pX3S93ybpH0u6zOmA9EoKWNC4idX+7Y36nzfBJ35Q886U9hnyzg9DANwmqddQek= X-Received: by 2002:a05:6300:44:b0:3c3:9070:96b3 with SMTP id adf61e73a8af0-3cf74e42f9bmr29441364637.3.1787817312017; Thu, 27 Aug 2026 00:55:12 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.55.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:11 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:38 +0530 Subject: [PATCH v2 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: <20260827-gb-uart-transport-v2-2-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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=2419; i=ayush@beagleboard.org; h=from:subject:message-id; bh=chploxg01RCtkX+bkpeAfG8l7gk0FSv0pjMUj9gd69g=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqj+1D4HIi/qfHAW0aMKYXRP7y2AGUuKHmObZJT E23Cbs4qy6JAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCao/tQwAKCRAFzvXHieVa dANWEAC5nWXdzoG6bygb2RpHr1Gh6StNBR+RF4Sn4uvKCQbxGCOwAiDm8wKT8Y3r+5QFnVyJCgi xeD/NAquzS/EtXcDsxFPSnGYQsCXeEJ7wAiooLdNswj80XhSFEuG3/YjPgGuKKaXJ2HYXDmtv4c M/mgx1bZMiVl+IbZmTKVHqGm5Mx8GJ1aOH4cjwbbKD4xIjAQZDFU0LYT3zDVUJ3/BkfaR3hELc5 RKVIhvcPYFpynhyS2Ig1C3ArwkgRhjc7FNji8HGuRSh1JqanKKOZPLqu28ZYHvX/GiEeNGnVCUI KCeVmzP/1jZ92zPB9xgujHvRHYnAQkRLg1sUSLhX1zZZxrFaKMIKlLoi9o777lGmXN12luYrUQ8 TE3aDhWU8ou+LeDm/t496WXCZqILPiR4kH1O2uYzhrr331ApsxGqyd8e0se/g6xSWT4DPd7g96t +Lb2aKsJM9Pg8bKvBfH77I5RvqTavLz9Oh0/TB48fHyS+CnWZdFlUp7GDyQayP+oTr+BC3eV6Mj 09af16eyuHwpSJu3/p3Awsb/sYziCaI/luebQabthzaEZMipbM7M+mvNPwaKuAUJO7VeDTXaoVN pEMJIx1DB1lOfz20ohu51fcsqarpwsWuE1SyaVhj6z9SCYx2xXFjDHbEuYxHW+XtYDavmbsck6A kZshFvHyqRpLPLA== 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 | 23 +++++++++++++++++++++++ include/linux/greybus/connection.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/drivers/greybus/connection.c b/drivers/greybus/connection.c index f8fda22bc466..dc9eb49a69bc 100644 --- a/drivers/greybus/connection.c +++ b/drivers/greybus/connection.c @@ -71,6 +71,29 @@ 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 && + 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 03:43:38 2026 Received: from mail-pg1-f178.google.com (mail-pg1-f178.google.com [209.85.215.178]) (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 EA0683A4521 for ; Thu, 27 Aug 2026 07:55:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817324; cv=none; b=dMWNrbOjvv3nY963sYuQ8yyVrEMW18L+/KCSYTJCKdqhXD4Am04CWclfFsdk5+qBZgULrFf/HGqO5mmKseBf68sUzKuJq61pBYI9x/xcGR3z1hMxb8spfc4fQMSADEM6+FQiR2q3eefB3ngJRPHE64/pvOwDTq2tlfM5w3pEbOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817324; c=relaxed/simple; bh=ClTBzeMLVCZZPvnEKAOlUe0dkGyo1RTW3U1pB0pM7aw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=t/vVF4NiFoP2OH8ir1YpRqZutHmlIYh2PjnTFSTr7XOnbliQYx1RvsHkCV/WIBjQj8CN3z0sDOh9AekZfhOn6FUldmy3bDXFl4BMEdfcF4REV3wnnCCxclyr0IyyfSjnxy1hADThEjSg9yoM/UDihw0WnYGBi6alw1rLPmXAYqg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=wL8h6XDK; arc=none smtp.client-ip=209.85.215.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="wL8h6XDK" Received: by mail-pg1-f178.google.com with SMTP id 41be03b00d2f7-cc1cb472b76so1284820a12.0 for ; Thu, 27 Aug 2026 00:55:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817321; x=1788422121; 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=uSYOQNfZf8FcKNI6R1tceCkpsnl5HzfVK78BAtVvR3Y=; b=wL8h6XDKBAWEcczp0cx1y/Jd+hXsEI/LfGpX2IsWJBzyh9kOMwYcIkkNrqtSH0k8OI oZKpgXegMTZDQ8MREU5jRiPXlcSn/UeqYVswvdnOegDTRbmjuR2sZgg1EUKv2+ZuTtbN 4C3RnT1G+ePUi9IJvNj/pM9OY7WVOyrNpD2y0LA5tM2MRUUyge86dOE2JdQxRDkgTUd6 2VEZ/dq2vMaAptVRjO+g4NUiw+fmUJy4RyqtWeGAgnvCZmLvBfUHycICXKi8KKbdj8S4 0O8oSLY3VVOMJuHENm3y9xVcdS05X0MDk7vsWOSKu9icN6YdNANq1ID3TcNMM7oTKs+t Qq2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817321; x=1788422121; 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=uSYOQNfZf8FcKNI6R1tceCkpsnl5HzfVK78BAtVvR3Y=; b=kXk7oAadx0oRRSl0u3uqRb+gW74SL30CFnh1G1rcssqC5RxYWOMEuX/RBhtLTLAu2T eKfiQ47lkz2mslJMA6rX5fQpFb+xvkVFxVpM4hJSKEm3QcZ3Vsip9dstbSmv+afFlbey zC292ZYeo6ris7KndsF5QAVr7kEbHCf5eu9RpzszK9X3sCM7njU+ut7Jkps0/2yt0OLi wx2EKKRTEhG36U/cj02LWIGza5mQe0hl0nphQ00ueICyGqj9S5ImMVFu8Cl8k4qJbemZ YC02GsAZowzIny7NPHiy/GEzLm6FiGLNKpHjgQ5DxYMM6bOhl9Vss1p+cTfOTeZ/LaFu mE0Q== X-Forwarded-Encrypted: i=1; AHgh+RobAHFl/hTPukSm1jjBKHFC6y1HJdxzvhdJgWOh+Too5YOqzLSlg4Ra8/wyv1D0kCGAFFox2IxRzdQ8KGo=@vger.kernel.org X-Gm-Message-State: AFuF++ktwQizp4WGfNQ7m9BoYZsog+3NoGEaiI55tX0MnWjyg22bJ9vF 1+qAcUQHD2/aP7rw8I8PyJzqG3dUUDIiPKRmOlaXMc8zHtQeuF3Zk80CbBea8UpCkg== X-Gm-Gg: AR+sD11orvFI9jP6oxtL3+zL9LhvzqwaqCWLmZMNXdiCPv+h/xD6+kJicyldTv55mbw 3U6wXwRkF44ihKfNUJJP9AloiY7Hix7mzuvb2FUGWqiuXb43P+P9k0SHO7q3vHdkjsgLIX6N/eJ qVryvhWiQdVk3ihHntVZ6OrhKnxkQFWIclszbtScB8KqLkm+mTTcYuE0bb0tX8+TOfqCqw0I+qa 2d8/h917sqCgA19WFOGwAfbVAkCGNEw6Uj6WU6v//XjP56xB8shy5uiEaHtQ7E/KEvpIb5p1Qe+ WPTXYrqbt/HgiyqW2f0auNzCKUbVp37L+/LAA0v6u7410lXza/jZZQxEQIYfvuvh8qbBE/THXDQ 1ulJq1wUYy7Q3Yslp64VJlsd/Bij8HKY1k5fy1WZiL3uw2CTuxWtv5dwFgaFleHgYogIi9kgCtg kjLL/TvrLCgJI9AK3WZP77WeOYUQiJxcZI4o2DmGd2tQ5P2zE+TeHlSYp+i6fnbBvb2IXkwhY= X-Received: by 2002:a05:6a20:9c87:b0:3c4:46ca:3347 with SMTP id adf61e73a8af0-3cf7596a8cfmr28568140637.2.1787817321526; Thu, 27 Aug 2026 00:55:21 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.55.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:21 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:39 +0530 Subject: [PATCH v2 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: <20260827-gb-uart-transport-v2-3-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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=3228; i=ayush@beagleboard.org; h=from:subject:message-id; bh=ClTBzeMLVCZZPvnEKAOlUe0dkGyo1RTW3U1pB0pM7aw=; b=kA0DAAoBBc71x4nlWnQByyZiAGqP7UOhwafQsl81AShgnTC0QQHWk3xXv4lXvWV77VaHiIEbu 4kCMwQAAQoAHRYhBN/MEx7yTy1lb6UE1gXO9ceJ5Vp0BQJqj+1DAAoJEAXO9ceJ5Vp0TI0QALMs iFSdhuNe+KI8MHO+ig1BHNI6WRGwm37HdprL49lEK8+5+BOPXTdaLckb0j245p3EQkufrBcI3ah AOni+iXZJcrWicUCIXI69D0m1kqWNOXYGpRP8tmBVNk4C2UOAq+U9dEOXzitxkIWr+8rxxZGkqb EoLFrXr80iu+nfpAvpJDfV7s7lNawH3s7wXn3YtmykATL3QPT5FHi/N5vfeN799lRlNmp825gRS vVMjrYK5mYADkRBr8rrRPsBzlRKVBb7g+aplq4jYMcCrQUQiGFRIiCuBPB2PfbAp78jjforyV/y HPTLPKvDZq57oPIVlsxM5kCefzczxYrSXq0KlwBas5+R7HSlvUjcFOMgq6750dpogEcJUPKt2NR xvfwVwrHmdp3gOFbQqXoI15iwB1voXw8mrNJ4NhAL2bIKYfQ0Hv8w2lg0i8RnWJbP9QEKnG56lm IWmAzv0wq/CQPwkxrhvgDHnhg+liKmsPJp/1PyV/Dpk42w6EZkmWxL7uPxRiC1o8THNTFO0Jf2r QEtCIvhErE0PhmHxM9zEeWn/pS4AO7vxWLs8kbayZ570VH8NIsmtVKZdoY99KAduvdn0nxrXQax moU5dgoj/c0UrBOfHdYzN8KZI/nwPg2TShgY2U5yGTycIrF7CCtIPL8YtyGN7Y7En1CH1mZHA7b OtGPC 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..628da2d30fc8 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 + 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 03:43:38 2026 Received: from mail-pf1-f180.google.com (mail-pf1-f180.google.com [209.85.210.180]) (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 35B603A2E36 for ; Thu, 27 Aug 2026 07:55:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817334; cv=none; b=hwj4eRi+OfQZyD6rhMlOmGr96PgN9/vy0dOGMm+NtmzvEkT30RW5Jc192TFSf028HuuwS3mWuhps6i4tjewvbW5+alVZ3DLhusDF9ZqE0vFkbmIBmWb6dmiynNphbAi0YMgUqZUGXde3ou+tVNwISF8d0nzujwLY96ONxgW99x0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817334; c=relaxed/simple; bh=OWYSTHt6TJbWJ48lLoRkYMfUlB6/ZHksNW68FuNNnEI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ouPsLu9NPkkDdf7ucNVP3eYv7POpMl29sooWWPcsPfLKQFP8cdr/6A0kshLb6jkMcquEQmP2dUFRkYz8GucLRAC6WPh2O0wHL7nmRGLkx0m/i1v+eV2UtIdxKvJ57JoXk1ICKoarYE1cp2HTu+mSSnva1QM73ttMtOLk5rf0DEo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=prtR/gcd; arc=none smtp.client-ip=209.85.210.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="prtR/gcd" Received: by mail-pf1-f180.google.com with SMTP id d2e1a72fcca58-85590c5aeabso113027b3a.3 for ; Thu, 27 Aug 2026 00:55:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817331; x=1788422131; 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=8t9G20fcrBNzhH4FpOffTnYklz5l8YqDis2NUbHSyHA=; b=prtR/gcdZjYV1ayXxFDcYwpJsrKfJAeqsMTrGeLGaAkLABFGrfWmbJlpXS1+LnUAet 7usa3KlZ/h7K8yfz588iLyNKRoTfrmW2c421P27NWSRvKEn1FlhvU7fps/sMEVIx9lrh TtbEvEaYSiI2/+FhljoNa0qLWj08UxdlJvdnRuIqHoR3M3WdTIDGjhYX6P2IfNWNiwEo fXDg9AFGvhlL3j+FRXANjAq7AX6Ti8ZHP/fRqAl3DQlNjJi/MRk59KGM2y3TBbPFmnGu 5sDSjcn52ARMh8ibo9ITr3cKMGOZgl+6XZN33GjC0SRGs0MsMc0aDKjnH5ptSQ2kC2r0 43Mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817331; x=1788422131; 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=8t9G20fcrBNzhH4FpOffTnYklz5l8YqDis2NUbHSyHA=; b=Bxt7DzQLtw+bMs1sa35gI1AbFjUg3Ju1GaS8rbN++UqBuG76XItoTKV9TYxPYe5J/v 2VVvtn/O7UTn1TvZm6oyjc7ch68EQAIqtqlFRXmbP6niyPyIa9osXwQlWNwIEUYjh9+Y YClGYTAoWCkUS3WwidP0b1MtL7ldE9k/1CS7CbfQjQf7lEIEIasC+S8luZgmzZg7+Ucc t8jqTuW5qlrvVTxb9c38Bf/VjtzckY8LM1zhThEeq6+nsgfz9HZQjymXraiBSBlrR3wX uS7UVMjDUOi6QfJ4FC6uWJTRnFPspe8MCA600qtgiNBvj2EQi4r01g3tul3HjF9YduAX s2ng== X-Forwarded-Encrypted: i=1; AHgh+RpZp4eLXv7eOZPl8ijAf8v7y/Qxfy/LIXlebnh+2MGSahkfW/jDHr0Z5bNW5/TDivwdcwY6vPbYKXgtJ9Q=@vger.kernel.org X-Gm-Message-State: AFuF++neq1nl9O1S24XWHI8oa58n+NlYgaxLBaWPGEgLJX14aQ9dScVO ziRCYZxeYm7NciPQvG0Tkio5GU4cG/Mm8gpzVhnb8QUWGVW7BkmrDWs1h+Fvgm+hgg== X-Gm-Gg: AR+sD125ZdL6G/x9HjmUbGbwB5PNtWdBjW+0/bDgluJzoBbMQes8b0VgO6AzPnmxfF3 Y1Cl7/cjt44EP4XvShfGbR5c06IDSI5mctz8ZL6LpjtAnTEl5iDR71vgZzYn5th+q3g4rQNLcV8 DtFBPFK0tD7QuUGfD12KcAtlNQ8YtH/Lwu044K2p9l1nbHqm5VLbbnHC/wWLom2TZU28t6Thsr0 rOjpL693NvMQ0nTVqYjzdRyt2atFcc22qeFm4uIF11B8pAk8sBKIQBOLsUmoxS7Jj/VcuTvP/MS v9++50wpEeJBQcAO8UTvaw78O/s8lB0IKRJ2N/O6aagVDv7C7Q9ocHASBkawR5op6qEpoVhCKyw lAPZsyAgfYFMOW+yU9ucCJ1kgsfnBwSv1y0Wpg2Jevtp3lI46GA5vyJiDMykwv/K7sHtwvUvViV i5V7ZEMV8NXOTiieg/G5i+Csw7zNWvR+3V6dBhnQ4faIRlYOXS5pFGabVy57cECMcyAkqEU0wcT yjCcEPaJGU= X-Received: by 2002:a05:6a21:6190:b0:3c3:a31b:3949 with SMTP id adf61e73a8af0-3cf83c17574mr27718415637.11.1787817331072; Thu, 27 Aug 2026 00:55:31 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.55.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:30 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:40 +0530 Subject: [PATCH v2 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: <20260827-gb-uart-transport-v2-4-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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=39708; i=ayush@beagleboard.org; h=from:subject:message-id; bh=OWYSTHt6TJbWJ48lLoRkYMfUlB6/ZHksNW68FuNNnEI=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqj+1DEpDjLIfyoTS7GYUs9Im22Mfiu+raJPqwM iG8/aWl8aSJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCao/tQwAKCRAFzvXHieVa dM72D/0RxiZkc9R+ttiDDZZ+l02H1nS6INEk+vmLoRQ6HYh3407e7eRjbetbeqVdz4nytqb64cR 8CtHTt3pgyBYXvppI2+yvT6GQFmQg+v0yPtT6yN42hp8bTZGjtxFZlahxFYiUD9YxdYeEr+WUmX 0frI02/j38bC1I/YBIAGdRPwkseLbqT7inQN3DZnNVNs9PT9CDKe858iwGCWDU6ceU+UQ1cuzn6 7QyT4duqYbLwuLFG+k4FLFBh2QusEpPjxgekHICkvS47tpUQ6+n/4ICyTdTsJ9sVYBA/AOrmtxl X/ffZGE+k6KwZqkgWkcIbqq87eNHLrgVw1360akif1A807TtmVaafl6s6SnG226InJjIFmA7mvH hkLUPmf7pMh0piBnKV0ONx9gYWtWw4vcWUBCxrfbDpvF69hO4Txyngy/Zd1dqidJi/rjLaaNYrU A/jci/aaBCd4McpwIUZbELrTE1x1zlbo6p+YRrUf1m+e4QY1r6N9ougyb+tFzJJ7lf2QUs2OOWT u/aDCPsoKxoOy+l0SwdEaozSQmDGme1bIE4o+RYp2TQdCe7KyfdrRBQkXT/1WgEE959mubtE67l xIbhsgIED8SOLKt/eknhVXwdjbc5maYrB0eUwflES/hi4+cg7PwxGUlIN4XBex7D2VB349VcE7H IQ65b0mghHt/1tg== 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. HdDriver Note ************** In C message_send callback, it is possible for the caller to defer calling gb_message_sent. This is used in es2 driver. However, looking at the internals, it does not seem like the message owenership is actually transferred to the caller in real terms. Instead, it is more like the caller is shared ownership. This is evident ny the fact that message_cancel can be called at any point, and depending on wheather the message is request or response, the message can become invalid after the message_cancel callback. Thus the driver is expected to ensure that no dangling references to that message exist. Since gb_message is not an internally ref counted structure in true terms (it does seem to use the ref counting in the internal operation), and since double calls to gb_message_sent are not really allowed, I have made the decision to call gb_message_sent on a message in the abstractions rather than making the driver call it. This means the driver only gets a reference to the message, and never owns it. This does prevent a driver to use it in the way es2 currently does, but seems much less of a footgun. Another possibility would be to implement AlwaysRefCounted on Message and pass the calls to gb_operation_get/put, but I have not gone through the internals enough to figure out if this is correct in all cases. Signed-off-by: Ayush Singh --- MAINTAINERS | 1 + drivers/greybus/Kconfig | 7 + rust/bindings/bindings_helper.h | 1 + rust/kernel/alloc.rs | 5 + rust/kernel/greybus/hd.rs | 333 +++++++++++++++++++++++++++++++++ rust/kernel/greybus/mod.rs | 232 +++++++++++++++++++++++ rust/kernel/greybus/protocols.rs | 392 +++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 2 + 8 files changed, 973 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/drivers/greybus/Kconfig b/drivers/greybus/Kconfig index c3f056d28b01..3bf3b8691442 100644 --- a/drivers/greybus/Kconfig +++ b/drivers/greybus/Kconfig @@ -15,6 +15,13 @@ menuconfig GREYBUS To compile this code as a module, choose M here: the module will be called greybus.ko =20 +config RUST_GREYBUS_ABSTRACTIONS + bool "Rust greybus abstractions" + depends on RUST + select GREYBUS + help + This enables the Rust abstraction for the Greybus API. + if GREYBUS =20 config GREYBUS_BEAGLEPLAY 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/alloc.rs b/rust/kernel/alloc.rs index 21067bde6860..d0ba4d91b3d3 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -38,6 +38,11 @@ pub struct Flags(u32); =20 impl Flags { + /// Create from gfp_t + pub(crate) fn new(v: bindings::gfp_t) -> Self { + Self(v) + } + /// Get the raw representation of this flag. pub(crate) fn as_raw(self) -> u32 { self.0 diff --git a/rust/kernel/greybus/hd.rs b/rust/kernel/greybus/hd.rs new file mode 100644 index 000000000000..ee2a4930ff2e --- /dev/null +++ b/rust/kernel/greybus/hd.rs @@ -0,0 +1,333 @@ +// 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::{ + marker::PhantomData, + ptr::{ + addr_of_mut, + NonNull, // + }, +}; + +use crate::{ + alloc::Flags, + device, + error::{ + code, + from_err_ptr, + to_result, // + }, + greybus::{ + Connection, + Message, // + }, + prelude::*, + sync::aref::{ + ARef, + AlwaysRefCounted, // + }, + 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, gfp_ma= sk: Flags) -> Result; + + /// 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, Flags::new(gfp_ma= sk)) { + Ok(()) =3D> { + // SAFETY: `msg` is still valid since `sent` is not called= anywhere else. + unsafe { msg.sent(0) }; + 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: `hd` is a valid pointer to `gb_host_device`. + let hd_dev: &Device> =3D unsafe { Device:= :from_raw(hd) }; + hd_dev.as_ref().set_drvdata(data)?; + + // SAFETY: By the type invariant the host device is valid, and it = has not been added yet. + to_result(unsafe { bindings::gb_hd_add(hd) })?; + + // INVARIANT: `gb_hd_create()` returns a valid `gb_host_device` on= success, + // and we own the reference it returns until `Drop`. + Ok(Self { + ptr: NonNull::new(hd).ok_or(code::ENOMEM)?, + _data: PhantomData, + }) + } +} + +impl Registration { + 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) { + // 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: `hd` is a valid pointer to `gb_host_device`. + let hd_dev =3D unsafe { Device::>::fr= om_raw(self.as_raw()) }; + // 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. + drop(unsafe { hd_dev.as_ref().drvdata_obtain::() }); + } + + // 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_put(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..791aac38ec29 --- /dev/null +++ b/rust/kernel/greybus/mod.rs @@ -0,0 +1,232 @@ +// 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 crate::{ + sync::aref::AlwaysRefCounted, + transmute::FromBytes, + 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(Opaque); + +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<'a>(ptr: *mut bindings::gb_message= ) -> &'a Self { + // SAFETY: `Message` is a transparent wrapper of `Opaque`. + unsafe { &*ptr.cast() } + } + + /// Returns the operation header at the start of the message. + #[inline] + pub const fn header(&self) -> &protocols::GbOperationMsgHdr { + // 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 { &*(*self.0.get()).header.cast() } + } + + /// # Safety + /// + /// `Message` is not valid after this call. + #[inline] + pub(crate) unsafe 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.get(), + 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 payload =3D unsafe { (*self.0.get()).payload }; + // SAFETY: By the type invariant the message is valid. + let payload_size =3D unsafe { (*self.0.get()).payload_size }; + + if payload.is_null() || payload_size =3D=3D 0 { + return &[]; + } + + // SAFETY: A non-null `payload` points at `payload_size` initializ= ed bytes. + unsafe { core::slice::from_raw_parts(payload.cast::(), 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.get()).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..fca4f1795fea 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_RUST_GREYBUS_ABSTRACTIONS)] +pub mod greybus; #[cfg(CONFIG_I2C =3D "y")] pub mod i2c; pub mod id_pool; --=20 2.55.0 From nobody Mon Sep 28 03:43:38 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 8BA393A3E67 for ; Thu, 27 Aug 2026 07:55:41 +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=1787817344; cv=none; b=ZVdntbdWH4KyHxxrWjyHXS2LoLLKxfu3QQfnKXTDNKPO2JPd+Wen06LeThsx/MUG/YQpUwsFlq3J0f3zDzMx/lMOkwWsMiHMsUpbqEMJboQavGckXPomdZO7yTcECQ5ClqbsXfyVLNE9XRRi3a0AIcYdzwe8akx4grTXZYXLEVs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817344; c=relaxed/simple; bh=5+g1es8ujcbaJ+DeAnz49JBmYw1EJz2CqI7iFe1ijrA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AaviV2FP7+RhLZrgV4+tDr1d3eQqoKY7bj5dm/+OOt1KthrrmE0WcAZ3iqLzVqd3i1naeiCOID7rTcXCVPE094n/oPKw3EMGp0Twql9UUwO/nwDNcLzBh5DSj2Hn/TpVplxnrsnNzg63fMyPehsZCIFvSTNIX8kZDMcqXtUtm+g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=Sr7mE+73; arc=none smtp.client-ip=209.85.216.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="Sr7mE+73" Received: by mail-pj1-f42.google.com with SMTP id 98e67ed59e1d1-38e7109321dso1431447a91.3 for ; Thu, 27 Aug 2026 00:55:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817341; x=1788422141; 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=Ywd5ymW5Sqwc3yq9XUINVOaEavB26DXvRJFclpGXEBQ=; b=Sr7mE+73xZBiIzOfnbBWZaV2ajLlrUsgLKM/o2w2TNGKY2ChtZEAwPDXWGUKF+Bohm qlKrlIrFLdapgK+AFNWcOIru3QE2fT0yxqBPO4PICA4A08dPbOwPsSIEDu+xs8Q3SRXr W2nUepoarC0G/JmnXVXosRq7zdaOCM1eXybFICqrr4gNH6ID6quv0iGO4gMql7DFiHO1 7o9S152hhpxj8V+FxHvOCxiQ4l7hmzeIUpXvt0jS2Gyx735X+2bE8Cr2ClCHFAVKCn7H +AGut4hXnOwH2q7m0UBpE32Tc0oM8qEN2imSaF+YZCP+hwm+ICFGR0vB2UOg5+i8tEk6 fvuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817341; x=1788422141; 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=Ywd5ymW5Sqwc3yq9XUINVOaEavB26DXvRJFclpGXEBQ=; b=GQRRUpiVXVeRrtj1DnlIuKO4/98pgamBVH9ZnjDHLalHmNZwdxL1hhyXGZO1XgEslp mhn7+1sbdZg7wnwlt0kXkEJQlNBCHnqKN7u1PA15KlskDuul0I2021pRTsj0I3VzMGvU W6g4u/T0uonRSqyQ8iKrluAqoL5sNyChIfGDD8GXE2BQL2CogU99DNS+1oJKJU10dD3W pQ2deXVjxdv9ZSFQkdbf+JbjefyZnkwYPxGEH6/EPBFZoxmXiAwEEQtyKQnLjnGTeclO +wqfLPLLrj9bnRrZWCLrnNQ7ICoVjHIbIf5RddtuUx1zJPgYgX3e1B8L2qmeHFXDiDrS V+Cw== X-Forwarded-Encrypted: i=1; AHgh+RoZjEpVXiXD8V+MmLJlxP15XWc3dDE/VVMJx9orpf6k4TUVAtktW1jReh35CaZxROXJndBoI11aSg3deeI=@vger.kernel.org X-Gm-Message-State: AFuF++ksDAHqZMubhLioD7f52PwvitfdcsTIhN5FBtQl7p7f5LETurWa TSM0HYQhR+vFDTz10UJdsJsi2OoR6h6AB0qwt5UYxDNsGyGmcD0tar9frePjALB5Cw== X-Gm-Gg: AR+sD139s8OWdKV6Yw0iMC2inbHetNX1ohOUL0XwyciuU7QaiiLc4/YMN7WbCORkWL/ XGgForyCAqPhx7Tx6weKNIu75TuJyVdiYbN8KONFVVCxWY0uT/9cffBTNgXdkLK3ytOZfrLcXbU 5ojg8zp6g7rRcqOsl2UxBn8ANVQrrG4t2ono2YwYx8LJf2uP19V5Md/JmDyfkzTFbouLQdi8KA0 ocVgLYvpEFTF10nqYq7AJs7qrsVCT4Z8hLgdRU6P+jqUgfKm8DXRKtxLKfwjaMQEYItIvNdCMz0 QIDAJxaLyLG7If8FGba+yifMfOZFLMySk7iMvP7j6ksy51ECFnYO9FP/gau158Y5fqVTdEBAbaQ 1QG4dJb1lDV+TJvcMRRLF5Lk1sifB4zddZyHqVDoo7R+9dpO6+Lw/myZWm65On/B5pAeh9JhYu/ 2Hi8kFNaqt4haaWJv2X6IbVBvT5b30KTc/AdI8t72ih3AXdJK06HE2epsjRKMWeo1EbDVK9DE= X-Received: by 2002:a17:90b:5291:b0:396:673f:fe56 with SMTP id 98e67ed59e1d1-3966d3d89e6mr28236162a91.9.1787817340607; Thu, 27 Aug 2026 00:55:40 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.55.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:40 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:41 +0530 Subject: [PATCH v2 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: <20260827-gb-uart-transport-v2-5-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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=21766; i=ayush@beagleboard.org; h=from:subject:message-id; bh=5+g1es8ujcbaJ+DeAnz49JBmYw1EJz2CqI7iFe1ijrA=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqj+1DyYo3hFaElotqb4eS0O2BVsm/x80xPO+Td mgrHHHduFGJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCao/tQwAKCRAFzvXHieVa dCFCD/49kLdjzLGC44Lu5iz4WEURITkqwfPhzNyxfXNO/7EenX5j57SdvF3wiVNNcwd2oT+iatW 9HK+h8fjV7i1EQw+XFllUdydduUzKetsdBjyHiAKrWldbX4GOLkB7xu0oeRYIUXRhte45iahO1h 3s4fMOUNXX6Xq5EKnj7FH8gqSWAnlTGqejzxxrP3SLh8OxALEPzMvZ3PipuHOXBqtQgZF/fTdVj PEw0VBKX1kMrh/4qyl2hwrL+2AQu430z+5uoJ+BF9Ty1tGVaPtJyPO3/evdnmt3YMffFwSbEoci tQEvStHemmA1Yc3LRBYv0Hehb+wjS6jWydUXgFnfUXbQ3b/pAed3oG2enbOuAkMGYNqFETexcGD DQNZhRycf0dbatetvZ0V94h0DRHKdBKFrSD4U1PZlCbMDk3BNqavYSoOQCSq1O1PmKnNefTZj1N 4KFLrW2ox0MsvKttDlP/W9JcNDZ6/QxmKIS/a8VD+yk/iHYyJKk8fLbJbfsIPACOsw71nBGXu7R WtHzuyoEx26Zk7OBj9u54Mf/qgtDotYDc++8on/k1h0qV5FUUB2wAyH7JEXb+b9po6Zh+ysgoeM Tkz42pWq9DWD2pk1+Z1m8xP2SdDkHx8hIEUjo+kqXm8/5DMX5SR5E7Md28g3eFxRdJLR60gFvR7 A3YwxIkue41SZag== 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 | 504 +++++++++++++++++++++++++++++++= ++++ drivers/greybus/gb_softsvc_exports.c | 15 ++ 5 files changed, 539 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 3bf3b8691442..381d1a6ee135 100644 --- a/drivers/greybus/Kconfig +++ b/drivers/greybus/Kconfig @@ -48,5 +48,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..79e2752e42ba --- /dev/null +++ b/drivers/greybus/gb_softsvc.rs @@ -0,0 +1,504 @@ +// 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::{ + alloc::Flags, + c_str, + error::code, + faux, + greybus::{ + self, + hd, + protocols, + CPORT_ID_MAX, + GB_OPERATION_SIZE_MAX, // + }, + id_pool::IdPool, + new_mutex, new_spinlock, + prelude::*, + sync::{ + aref::ARef, + Arc, + Mutex, + SpinLock, // + }, + transmute::AsBytes, +}; +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 0; +const AP_INF_ID: u8 =3D 0; + +const TOSHIBA_DMID: u32 =3D 0x0126; + +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)?; + // map_insert already checks that intf len fits in u8 + let intf_count =3D intfs.len() as u8; + + let payload =3D protocols::GbSvcModuleInsertedRequest::new(intf_id= , intf_count, 0); + let res =3D self.send_request(hd, protocols::GB_SVC_TYPE_MODULE_IN= SERTED, payload); + + if res.is_err() { + self.map_remove(intf_id, intf_count); + } + + res.map(|()| 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, TOSHIBA= _DMID); + 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); + +#[vtable] +impl hd::HdDriver for GbHdDriver { + fn message_send( + data: &Self, + dest_cport_id: u16, + msg: &greybus::Message, + gfp_mask: Flags, + ) -> Result { + if dest_cport_id =3D=3D protocols::GB_SVC_CPORT_ID { + data.0.handler(msg) + } else { + let conn =3D msg.operation().connection(); + let intf =3D data.0.intf_by_id(conn.interface().unwrap().id())= ?; + + let mut buf =3D KVec::with_capacity(msg.header().size().into()= , gfp_mask)?; + + buf.extend_from_slice(msg.header().as_bytes(), gfp_mask)?; + buf.extend_from_slice(msg.payload_bytes(), gfp_mask)?; + + intf.write(&buf, conn.intf_cport_id(), gfp_mask) + } + } + + 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))?; + + svc.send_version(hd.as_ref())?; + + let global_state =3D GlobalState::new(svc.clone(), hd.as_ref().int= o()); + let _ =3D GLOBAL_STATE.lock().replace(global_state); + + 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, gfp_mask: Flags) -> 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); + }; + + if intf_count =3D=3D 0 { + return Err(code::EINVAL); + } + + 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. + /// + /// `intf_id_rel` is the id relative to the actual interface. Eq, if a= n Module has 3 interfaces + /// then the relative id will be 0 or 1 or 2 + /// `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, intf_id_rel: u8, cport: u16, msg: &[u8]) = -> Result<()> { + if intf_id_rel >=3D self.intf_count { + return Err(code::EINVAL); + } + + let intf =3D self + .gb_hd + .find_connection_by_intf(self.id + intf_id_rel, 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..a0e360c4d137 --- /dev/null +++ b/drivers/greybus/gb_softsvc_exports.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2026 BeagleBoard.org. All rights = reserved. + +/* + * Exports Rust symbols from the `gb_softsvc` crate for use by dependent m= odules. + * + * 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 03:43:38 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (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 A78D43A168E for ; Thu, 27 Aug 2026 07:55:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817352; cv=none; b=WyKDxNVfxdsX81Fl4C2jMPSzQWbRdc9Z2upx7uAD/iIR+peecudqoVv1DPskDybtLzl2BuILKHPDK6SJBfAZGSl5CjEzR0Oz12PHO0+JRv7Xy0PNTTa+Gj+LMG/lO8XmWB+qa7R8HRlc9E5NB0SHUqdaM2uuW8TCO8ht+h87eGs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817352; c=relaxed/simple; bh=t4/SR8SWQmaZ5WztW+CHvg/QC5M34jhKztRXj5DMFzw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MKgr8PsLFsIioTVW0sET4Yn2wNeC1foe2tR7RZlk1fihJXns5aE02yVsTWq9FkWqrvdKcTiqmjENx/f8GtwVZ2KrkQ+FOkLYQWJFyv4qtiecqDBIRcDBt6l9EYp/ZItS/q2o9SMAEsveT+Ztm5ia50mCFlv0DS70pLFPOiysIUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=tQggt716; arc=none smtp.client-ip=209.85.214.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="tQggt716" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2d5cad1a6baso5044555ad.3 for ; Thu, 27 Aug 2026 00:55:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817350; x=1788422150; 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=vj8h83cNWEkfF8w29lRmAWs8Ge/MzQCuHu+NZTz6F+o=; b=tQggt716SVGx8C7jywRVtAm9cJxP04Xwt4qonOqre1trhG2kGNyRaxGUv5S/yNeB7Z hKn3gLJa/7l+HB2PCjpLYjTMl76WF6HuGae4QzT4jNUX+DdEcr97x+pP8LyVNPn4ir+n RhF6xs0tv3g3mA5t2UoEvxeyvZkYrKFjTyWSqf+7iYxMT0/8b4JReDe2Y84s4Q1dUtzo /gG5OB0RBKn+8sYqQvWnoO3ls+/fpAdrhG3eO1oEL6sBbE2UhIfDavp5N+rzi7dHMGnv DL4UbWIcxoNg0DL3gB0kF5FPx6ILTTOYeIhOuBFhaqaZT8K1cY9iN1KYZb5BkrLuyBSu PJyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817350; x=1788422150; 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=vj8h83cNWEkfF8w29lRmAWs8Ge/MzQCuHu+NZTz6F+o=; b=H/eoIAn7LUll0Wgyq1NQ4fhEqPEsC7ejGLEI6HqTa08jwbe8h4I+CDkVtCtWUH22gf 8OmvrAptCdhnSU4wGvka+U21GAc9jjAHaM/EwIYphJ1zusNqGhdZu52azjl5HrutqcvR H32psjowjt0RIQ0tj+sdTFhNUT+eEnkrvnJIrCjGWYlZ86L+HW75jkcctKMu7ssmh1UG ogwuHubnyZZ9FlNZaOET+UE9Er/I6ChMtOfjzqOX6q+kxKZHok8/6/QlADJo/YvpFjQT qn4FHhDwX7TZ6TmikXAsbY3hYtqbprHOx9/ZuJCfeMZxsehfaSS1JnzL9LD8yrLVE+wV +smQ== X-Forwarded-Encrypted: i=1; AHgh+RoicJOXjxtqrTVod+oPLuV61d+MpIVvI+jBLJpneX7vSUY+rPLI4A0nw/4nr7tt5pGgzWJmcmQa1javg1g=@vger.kernel.org X-Gm-Message-State: AFuF++lMeVUj9Ib3EYAHU4FGEzcDV8OPHn7NtgDxdRNtw0ktSVrEJkQt mSaCpPjeLj6NDNx+fBZGY80j6NgQAY703O2P7ssk9TKFS21Q7O/2lItkEOJaqwxvJw== X-Gm-Gg: AR+sD10qrXG8wXocEbTImW9iHOk43lp3xTVmH+Iv1uwkTxFEEyDrSKdQJaNjTprdXu8 R/PDQXGL7sHr6CeS8D3dbP3EXju7ds5TYsu66JyowgulfWEhuK6YrejuXnFqLbbc4PopM8yAGXF x8+7uw/6k+1AGxqaa8r4ocC6pI2Rm3p64LCmrvAKxVswXq23DkBDG5F/n1gUlo1+j1fq6hDuGiB 8Vw8d6bNACDVwqeMhz9h9EzcpCo3B2rL6UsVc2G6YUTWz1r0087mn0oSDqsDdUBCA7VDve1haiM YZju7fIqrmHDCNpR420S5RV8/FV3gFoqgAL7F/52JOCjj1su4seEezfxPpgphiCZMaDObSJZTtd kvQ5IKSPugS12s+V8a817DXCkHq1wbv54aoXqdQ5Lb1Hie5d7s0JKAHMdNtpR58Se+oajcC6LA4 KZkNC+beNzPxAd4j1Y4jE15t9WqpSi5Q2YQiwweYUlw+JBWNm0QHuy4KL7jINbMMsuPc0EySk= X-Received: by 2002:a17:903:380b:b0:2d6:fec3:bd57 with SMTP id d9443c01a7336-2d707b6ca38mr268151405ad.14.1787817350050; Thu, 27 Aug 2026 00:55:50 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.55.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:49 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:42 +0530 Subject: [PATCH v2 6/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: <20260827-gb-uart-transport-v2-6-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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=2301; i=ayush@beagleboard.org; h=from:subject:message-id; bh=t4/SR8SWQmaZ5WztW+CHvg/QC5M34jhKztRXj5DMFzw=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqj+1DBpvxBrw6gBdnsE8wvudZhudc7tdhHKrtM d+ionZN1JmJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCao/tQwAKCRAFzvXHieVa dLcbEAC6bUVXSX32NXCQRkssEbDKvah2Wau0ZPIEkRI1pohKltxCcJ+J3gLeAEpqmfWoMh9XSUm 2Pd/ZQt/fEy31azAHIzO/axqtKGNag2/NAMd1cl8N5tcbN406xM2E2KnOUKqt84uKCwyCfcHuM6 wIU2QlsxGzVahCuy2WN7r6Rpgi7MU/Wfo/XIGUucg7Wo528MIJNh+Doz/ytrJ6lVv53ZCdHoAIt ezSnprvifKwMDsQoGLd0vsggeVkOcXIing6/4EgcDPqKv9CKnEf7Rz6g4N3xCWLXLooN8PEwkr2 5G//BAWasSbfFE9t5Zvxf5WxllIEDJfYn6Mx6Zca8RwSXtjAXHVl2BGCms/s7wScrgyEN4ydIfB L3LcZYu6VvPPSL2swqF/dI4DEHapg0EHc/PihXoZyQqQGGEUoe6TGpTk+7CGYA43gKxoDJFgMtg q5Psoq50HSpAO06AlWcwqZ/6zSwGSc8jvyIhEEU8Hf5lIQ4RLn9EZ/vKx/4AUw4xS2MzbSr75tz 82qbRWMJIbQ0YOM27IAGIEu3VczXQr5+LrELfzhSdCwv82Wu8F73v9LK62KosEbNEdmKSce3qGc SNjQlt6CArQ+m+Gc9WQaWl44SCxoM6y4lt6Cz3ar6TsksOb0fhj4AGoLnGYEW9JTkcoiLtgMWGF +reexnLazFuUAFw== 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 Acked-by: Conor Dooley --- .../beagle/beagle,beagleconnect-freedom.yaml | 39 ++++++++++++++++++= ++++ MAINTAINERS | 6 ++++ 2 files changed, 45 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..be051a39acdc --- /dev/null +++ b/Documentation/devicetree/bindings/beagle/beagle,beagleconnect-freedom= .yaml @@ -0,0 +1,39 @@ +# 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 + + reg: + maxItems: 1 + + vbat-supply: true + +required: + - compatible + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + serial { + mcu { + compatible =3D "beagle,beagleconnect-freedom"; + vbat-supply =3D <&vbat>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3ba56cdbf056..d047090be5f4 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: Documentation/devicetree/bindings/beagle/beagle,beagleconnect-freedom.y= aml + GREYBUS SUBSYSTEM M: Johan Hovold M: Alex Elder --=20 2.55.0 From nobody Mon Sep 28 03:43:38 2026 Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.176]) (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 571F93A383C for ; Thu, 27 Aug 2026 07:56:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817362; cv=none; b=lO5a4B4aqBh75vEfcAdbVGNK5UcSrqF3AOUtqQJXFF1JYEcHfdeDRZ+YMiE73Poa7M5DLEMLSnM7RldL1SuotksTGSQlX9b08WUTXIhxhQlxB2PksjZ1DT1i87YPeiP2MKeC1eCKn6sdTHBa6mHXHFI/z3+PGywijoFGtFONvvo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787817362; c=relaxed/simple; bh=woP4oknrV4W1iL3OCn7b6REW+reH59r7peTdThZwqZM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UyyYmNy/sUIySr5uDhY6tgqgcyqtHpiC+QalWv1uYZtmitNtiNy5eEGEC0nsYUN+4OzyrwskCCCe1vCGQC6goEPrHI3v7Ml4UuQjENqnvVsfK7lUKYj2t8nik1iKb6dJu9LWUFPbucssxG/PN0obp1EP3BohibRVf9i8IBYRLiA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=beagleboard.org; spf=fail smtp.mailfrom=beagleboard.org; dkim=pass (2048-bit key) header.d=beagleboard.org header.i=@beagleboard.org header.b=I0FMnEjg; arc=none smtp.client-ip=209.85.210.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (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 header.i=@beagleboard.org header.b="I0FMnEjg" Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-85590c5aeabso113328b3a.3 for ; Thu, 27 Aug 2026 00:56:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=beagleboard.org; s=google; t=1787817359; x=1788422159; 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=JpdW8dGYYPpvIZ3wUmof7nEJxVPBrHgTt9c2tEi6VgY=; b=I0FMnEjgPWha98m1uLU3Ft5aCB90BLzRlIU93dJ8ZC+czyqest1A0Ej4dA4vHNY4bj bOSviM7fEVlsyRO1gQxpjQ1kAEDHBopyGkr685tS4rVxdtVbse7Yys9g8jaZD0DyKpV4 cUqEqmxMQVOXhX1rQojMsdgVZao132PODNw/Cz7uFRyTnS4dM7ghC/BxYNmifXo6escD Zduf5xsDEdRoXzIOp6kUUXG8Jg4Fgm9TU72ACf/Cmk1nJdJ0u2FICBW+um4yuXOnwFfx CtoEar5pQwfTfHiMqAOA4suG2baFmLc9rT8YF6sKnFfZmoG4Zg/hP3HDvd+hkmhNeWO1 Ellg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787817359; x=1788422159; 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=JpdW8dGYYPpvIZ3wUmof7nEJxVPBrHgTt9c2tEi6VgY=; b=H5lccef1AgYMqW0G9R16OJUxFI+XOUob4wUJqLa2o8urhOBQxL1icG13X7wt65DWNs 7cLi4O+bqt2597KiT62r49QjTCBz7gPTypzQM3jRhu2r2nVFx6BM9ORJwQ9JIxeWB1QO KArUFZxhJfWOPS4lTBV3xdg6z+nvtI8x095yXKT61EWuRU8zMFZ3JlXGu9XOS/rVUv/e 3R5y/sdKpznrtN3gY5pa/2Gl/084Vpoe0T+jY6xOGbz202Ek+/CyDWBPNGjMjeHyzh55 xdVEn/gFVrd4LrJXtjNk9Mz6xDcYfjYhzyHimKgUyXrIdVDrugO6nVDENc4NULiilssq yJqw== X-Forwarded-Encrypted: i=1; AHgh+Roa2B5PkdN4CRzLKzBW1OTG12vzsYLIQufZWPy9hJkeKZ2beryABScHqW7MrZr+PenIjuSuWUCFRirSoyA=@vger.kernel.org X-Gm-Message-State: AFuF++mdIUyprFVWJ0MN6Zm6GHHD+HML+q+4ymseuGmj8Oea3qneXda+ OYsqFB3DpEJOlOzJxL1pZKFc2ql81PmL0jxD8hIMHQD+wsmkicQZi7HFUl8FqUlqCg== X-Gm-Gg: AR+sD112QQG/RRkxXysfNnaMd9Eks+uDrO4Jaqi74XTe4nYlAHI7A9aOLMyXnBRFNBK 9cpBUaQx70lW4Z+FwFPrS4q0Joo2xXCuZ70wnkjpts6ads/qZ88X+XvL6EWrQRO5IAYsLLXPRue +2+cQee67EIqBCB6wFeoqmgkbIxJZkXeMJVnWUkPiFzMQS7R1tVqMoZXof5IHmCSrj2utQpAa6A 7+AKuaR1HUA3xCHqMkFdmlMm+mrpSSIoG9Iee+pAo2745PwwgD4dYgEleF3qsWr/skoQaAh2whB 2ki64kJZyaDVqlkwFjFTmPwjI51YYErV5BBEOoN9KlP0jLkedAAB3geJv3xgHyb1Y59aMAIs+gg KENebYhEbb9J1AjZBnIictbooOjkuGkdAZhW+QQXAZBTqkgeE7FHydg0Jr5YtBSr5CIT+yDVeTM kYIuiINKLxkWa7xvRA3UN8hOtxlWxVQl11gU2XzpIvd5qpeVEZt3gHNUbLoNom26DzuNP01tM= X-Received: by 2002:a05:6a21:4593:b0:3bf:9b61:f7ae with SMTP id adf61e73a8af0-3cf8413dffdmr29525954637.14.1787817359500; Thu, 27 Aug 2026 00:55:59 -0700 (PDT) Received: from [192.168.29.54] ([2405:201:4019:32fc:3c55:6b24:5147:322b]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3283d60c2b4sm24641685eec.5.2026.08.27.00.55.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 00:55:59 -0700 (PDT) From: Ayush Singh Date: Thu, 27 Aug 2026 13:24:43 +0530 Subject: [PATCH v2 7/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: <20260827-gb-uart-transport-v2-7-a03bb1f5fbd1@beagleboard.org> References: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@beagleboard.org> In-Reply-To: <20260827-gb-uart-transport-v2-0-a03bb1f5fbd1@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 , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki 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=12372; i=ayush@beagleboard.org; h=from:subject:message-id; bh=woP4oknrV4W1iL3OCn7b6REW+reH59r7peTdThZwqZM=; b=owEBbQKS/ZANAwAKAQXO9ceJ5Vp0AcsmYgBqj+1DHhMiSIIYl82UcYte5S2h2+PWFqg5USgDK FvjTfvXr6qJAjMEAAEKAB0WIQTfzBMe8k8tZW+lBNYFzvXHieVadAUCao/tQwAKCRAFzvXHieVa dGPEEACt4vEA02o6w4DZrtBUPxYp9v36RhwEvIb8aKp8HZOwXi9lK4OvAxSRzRzIvhwGrcm+uul duNy2HaEyBdO/TfVgZUJrguaHpEfrxlC/I2P3vaooDOvxhG0yVEWmp0qzI5ehHtx0H1vzV4j+cF sDYyH5c3SIaFvc2GeGnkSjBHCFWdZzm37CoWNVnRvJdaiTb5rZEzPjf9anj8KWfcelySFDt5pyW JfRWLJIwBc5dDalyz0mkTio6EFuUYY0ZTiOv18OfVCQW14B3+gI2576DdEVuYIMtnFd4/wA2jJs C2NDO+6T70K7VvPAzJQAX6BuFg+a1jUDxONiLnJsa3m2RBYH+asmEpTVFpF2TOOZi90GxXcWnvx x8UFGF6o/omIYlLLB//pkwYiFDQi0XMWjDJxxt8zlLAGRHPO0T6tzzs3pP9sUcDkSzxkrBE9wS5 gCTWwl95IptjAbOm0bO5oO4b0b457CMumGB8NfxO4oyN7kyh2xZiqqTXFkZXqPlF15BNNBk0CWR 2IWNC0y0RjPxdbR2t3BRRfko03ejupGyNp/e2dgjFoTXU2vebwkOwNDdOnqJYOkbT13xzl0QOOX y7B/Geurl/J/oGJd8549H2AgHojtQhWcIk+XfrFNs/l7Mmixa+wqlMQIHdm7gZyHw1aECuLLOMb YxzlAsjoxTHlGpw== 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 | 1 + drivers/greybus/.gitignore | 1 + drivers/greybus/Kconfig | 15 +++ drivers/greybus/Makefile | 48 ++++++++ drivers/greybus/gb_uart_node.rs | 245 ++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 310 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d047090be5f4..49c6dac72748 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11339,6 +11339,7 @@ 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 M: Johan Hovold 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 381d1a6ee135..34de913af287 100644 --- a/drivers/greybus/Kconfig +++ b/drivers/greybus/Kconfig @@ -60,5 +60,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..3eb4f8ab3655 --- /dev/null +++ b/drivers/greybus/gb_uart_node.rs @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Greybus UART Node driver + +use kernel::{ + alloc::Flags, + crc_ccitt::crc_ccitt, + device::{ + AsBusDevice, + Bound, + Core, // + }, + error::code, + new_spinlock, of, + prelude::*, + serdev, + sync::{ + aref::ARef, + Arc, + SpinLock, // + }, +}; + +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(0, frame.cport.into(), &frame.msg) + } + _ =3D> Err(code::EINVAL), + } + } + + fn rx(&mut self, data: &[u8]) -> usize { + for i in data.iter() { + 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_within_capacity(c).is_err() { + dev_warn!(self.sdev.as_ref(), "buffer overflow. Dr= opping frame"); + + self.rx_buf.clear(); + self.rx_in_esc =3D false; + } + } + } + } + + data.len() + } +} + +struct GbNode { + sdev: ARef, +} + +impl GbNode { + const fn new(sdev: ARef) -> Self { + Self { sdev } + } + + fn fill_buf(mut crc: u16, data: &[u8], buf: &mut KVec) -> Result { + for i in data { + crc =3D crc_ccitt(crc, &[*i]); + if *i =3D=3D HDLC_ESC || *i =3D=3D HDLC_FRAME { + buf.push_within_capacity(HDLC_ESC)?; + buf.push_within_capacity(i ^ HDLC_XOR)?; + } else { + buf.push_within_capacity(*i)?; + } + } + + Ok(crc) + } +} + +impl gb_softsvc::InterfaceOps for GbNode { + fn write(&self, data: &[u8], cport: u16, gfp_mask: Flags) -> 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 buf =3D KVec::with_capacity(HDLC_MAX_FRAME_LEN, gfp_mask)?; + + let mut crc =3D 0xffff; + + buf.push_within_capacity(HDLC_FRAME)?; + + crc =3D Self::fill_buf(crc, &[ADDRESS_GREYBUS, 0x03], &mut buf)?; + crc =3D Self::fill_buf(crc, &cport.to_le_bytes(), &mut buf)?; + crc =3D Self::fill_buf(crc, data, &mut buf)?; + + crc ^=3D 0xffff; + Self::fill_buf(crc, &crc.to_le_bytes(), &mut buf)?; + + buf.push_within_capacity(HDLC_FRAME)?; + + bound.write_all(&buf, 0)?; + + Ok(()) + } +} + +#[pin_data] +struct GbUartNode { + #[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"); + + try_pin_init!(Self { + rx <- new_spinlock!(Some(Self::init(sdev)?), "gb_uart_node::rx= "), + }? Error) + } + + fn receive<'bound>( + _sdev: &'bound serdev::Device, + this: Pin<&Self>, + data: &[u8], + ) -> usize { + if let Some(mut guard) =3D this.rx.try_lock() { + if let Some(ref mut hdlc_rx) =3D *guard { + return hdlc_rx.rx(data); + } + } + + 0 + } + + fn unbind<'bound>(_: &'bound serdev::Device>, this: Pin<&Self= ::Data<'bound>>) { + // Getting a bound device is not possible after this point. So dro= p HdlcRx. + let _ =3D this.rx.lock().take(); + } +} + +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