From nobody Sun Oct 5 20:17:13 2025 Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) (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 32ACA27467B for ; Wed, 30 Jul 2025 09:30:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867803; cv=none; b=JMc5Wl4ekBt6K8NIp2xcjA4Rg8FDU1g63t4+9tBlV8rKD++fOFRUvxTTuC4iAi7xtoILeBFZv0T8afHHq8+WtJPfxsSCS2VQW8T5sp+CPb5azEYfyHNX5U2LeBABve43WDRScXFMA03OTGfU7IeQvWZB3BJHA5pDMCe4yYjPrMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867803; c=relaxed/simple; bh=5dgm8QJmb1y3lQDQkDPV0FaZsW33rfPUVwIw+yQAhQ0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ZS47DSm7eQdm1Yby6a6uCbKCmaR7UGPmrQ9osMPaFkfU9NurA2J3F1YX6vOs6HBJ3XDXZJuk0kMkavVDCD1dDy2pbdaETtWUoRksmBWE0w9sJq/b/l0zLcB+wGmLbOOSBIjlNFMmhpbUy6OWmK3hidRIsK6GKSh04Hd6pQ0vK0E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=UUHpzfkN; arc=none smtp.client-ip=209.85.210.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="UUHpzfkN" Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-75ce8f8a3a1so3817489b3a.3 for ; Wed, 30 Jul 2025 02:30:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753867801; x=1754472601; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=vu+M0/uIPWDSjTwSlyDMCHQ4E58hfAmwYKc2WXq227M=; b=UUHpzfkN4C0CGSHOMRQi5+vwTxxEQdIzWwJ6U/iAaOBV//sqglORdxidYIodBMq8Wo 0x/OjlyBJpdy0DvOWNha24ebMxU9Y6q+Q4ot8B6j6fAoXCnIBVbZBx6wLFGV55JxrXwK j//Xtc5QIQ01TG1FfdUTpNReaL5qC7vHAcWJ0GzY1QW3YOiCD/UgeIYZONy2TRZ3lhmt U8dGSnExQJi1IhlfatYRZyZoGKcOdW51rIOOT1CPEWddE4RUXq4KNNX2H9crbDRHO18t PfkIUW8k9c9LbPcHTKttwq3LZwaNrohJFL/dsY2333SS3AGFbtjF6r/s/AWgreeN/KKs pJNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753867801; x=1754472601; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vu+M0/uIPWDSjTwSlyDMCHQ4E58hfAmwYKc2WXq227M=; b=s3rJeOuR0x72t/0mCKHteu9oZD5GFEt/us06YhY8fwYbYfz2m03+KNfUqiDxVhCVOC wlMvmtxRaBj+gs6WZMPZQVP6RJlnAuB6UekScIppcjTE5PLQIbhg9rnt3eDRZN70T8YN 35Z86tLRg/fGoE/X+fuJfQuYQTrXIC/rySTwYCzD03sheh+S5qI0zUqYUjP5o+A/YBjk XhxZVFdd2kXfR6068rFh/21YXmjarI1gnyRLJv6ldYF3MILutY4C5v/kh12nwKtcmsPE x+wlOB0uvSAc04fDrC3aFpUGQ7Bg/ajbt/ld25/QUTg6NSAUbB3n/d982qlZVk68Her4 TYng== X-Gm-Message-State: AOJu0Yzk/eHQZc03i3kmSbdPedANKExQx4tFF6t6GqVz76sLCOa1DIh6 MIABXFFn5WW6uxZ5LnhzcjTVETseA5qCKaw5TokLqCW+d5U6DBHWA/SC/Z68WZIoYwKptfZ6giZ QaAoT X-Gm-Gg: ASbGncsktyXtjE+qPJa2CfZhbQRpC51pRqVWhwu7ehV7bWnsSGJgdq8vVpbIDKmMb6a fOQ8vrSDbn+6rsT0yqXUvlGZ5uEyPg/jquk0eGTRD68t2trESTi2mB4+kKipRJ19HYd/NJ+wuyp 4QnhpwKEHU6pTbUWnxEjKqvCifYIurCi1p/2fbltwQoWoqWvBcyQvFnaO+D1m1SlFJ2yMqiZr4n rwJWGCh4rhdgj/KL6qhJFR4KaPqwJ/ba4pROUSZrJ8TRK/C1d91AZxNgFBRBbjdbDIQ40mBgZAM KqypM6LFSvME0oDcxNmIlLk5ZY6WYkeLAA/vENigHhjUWduiuce2FzT4NAKt8L4tXPXBHyBI2xT osVdqk2k+YF5LyWkhDa/b658= X-Google-Smtp-Source: AGHT+IEaqMhp9wt/vc4KBbRw+vOpiZc3CbcTUS+/uPYT7mnw3RyDbEwb+0HDQqI/sNr/Say0lfIuDQ== X-Received: by 2002:a17:903:4b08:b0:240:3dea:b269 with SMTP id d9443c01a7336-24096b658a9mr39237495ad.48.1753867801249; Wed, 30 Jul 2025 02:30:01 -0700 (PDT) Received: from localhost ([122.172.85.40]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-24009e53876sm74902245ad.2.2025.07.30.02.30.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 02:30:00 -0700 (PDT) From: Viresh Kumar To: linux-kernel@vger.kernel.org, Rob Herring , Saravana Kannan Cc: Viresh Kumar , Arnd Bergmann , Vincent Guittot , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Bill Mills , "Michael S. Tsirkin" , Jason Wang , devicetree@vger.kernel.org, virtualization@lists.linux.dev, Sudeep Holla , Bertrand Marquis , "Edgar E . Iglesias" , Arnaud Pouliquen , Krzysztof Kozlowski , Conor Dooley Subject: [RFC PATCH 1/6] of: reserved-memory: Add reserved_mem_device_init() Date: Wed, 30 Jul 2025 14:59:30 +0530 Message-Id: <88dbf7486b820bd713598f20efd51e327b9ff755.1753865268.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This adds reserved_mem_device_init() helper to attach the specified reserved-memory region to the device. This is required to attach a reserved-memory region with a non-DT device. Signed-off-by: Viresh Kumar --- drivers/of/of_reserved_mem.c | 64 ++++++++++++++++++++------------- include/linux/of_reserved_mem.h | 7 ++++ 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 77016c0cc296..e0a86c3fa656 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -606,6 +606,45 @@ struct rmem_assigned_device { static LIST_HEAD(of_rmem_assigned_device_list); static DEFINE_MUTEX(of_rmem_assigned_device_mutex); =20 +/** + * reserved_mem_device_init() - assign reserved memory region to given dev= ice + * @dev: Pointer to the device to configure + * @rmem: Pointer to the reserved memory region + * + * This function assigns the @rmem reserved memory region to the @dev devi= ce. + * + * Returns error code or zero on success. + */ +int reserved_mem_device_init(struct device *dev, struct reserved_mem *rmem) +{ + struct rmem_assigned_device *rd; + int ret; + + if (!dev || !rmem || !rmem->ops || !rmem->ops->device_init) + return -EINVAL; + + rd =3D kmalloc(sizeof(*rd), GFP_KERNEL); + if (!rd) + return -ENOMEM; + + ret =3D rmem->ops->device_init(rmem, dev); + if (ret =3D=3D 0) { + rd->dev =3D dev; + rd->rmem =3D rmem; + + mutex_lock(&of_rmem_assigned_device_mutex); + list_add(&rd->list, &of_rmem_assigned_device_list); + mutex_unlock(&of_rmem_assigned_device_mutex); + + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } + + return ret; +} +EXPORT_SYMBOL_GPL(reserved_mem_device_init); + /** * of_reserved_mem_device_init_by_idx() - assign reserved memory region to * given device @@ -624,10 +663,8 @@ static DEFINE_MUTEX(of_rmem_assigned_device_mutex); int of_reserved_mem_device_init_by_idx(struct device *dev, struct device_node *np, int idx) { - struct rmem_assigned_device *rd; struct device_node *target; struct reserved_mem *rmem; - int ret; =20 if (!np || !dev) return -EINVAL; @@ -644,28 +681,7 @@ int of_reserved_mem_device_init_by_idx(struct device *= dev, rmem =3D of_reserved_mem_lookup(target); of_node_put(target); =20 - if (!rmem || !rmem->ops || !rmem->ops->device_init) - return -EINVAL; - - rd =3D kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); - if (!rd) - return -ENOMEM; - - ret =3D rmem->ops->device_init(rmem, dev); - if (ret =3D=3D 0) { - rd->dev =3D dev; - rd->rmem =3D rmem; - - mutex_lock(&of_rmem_assigned_device_mutex); - list_add(&rd->list, &of_rmem_assigned_device_list); - mutex_unlock(&of_rmem_assigned_device_mutex); - - dev_info(dev, "assigned reserved memory node %s\n", rmem->name); - } else { - kfree(rd); - } - - return ret; + return reserved_mem_device_init(dev, rmem); } EXPORT_SYMBOL_GPL(of_reserved_mem_device_init_by_idx); =20 diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_me= m.h index f573423359f4..3933f1d39e9a 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -37,6 +37,7 @@ int of_reserved_mem_device_init_by_idx(struct device *dev, int of_reserved_mem_device_init_by_name(struct device *dev, struct device_node *np, const char *name); +int reserved_mem_device_init(struct device *dev, struct reserved_mem *rmem= ); void of_reserved_mem_device_release(struct device *dev); =20 struct reserved_mem *of_reserved_mem_lookup(struct device_node *np); @@ -64,6 +65,12 @@ static inline int of_reserved_mem_device_init_by_name(st= ruct device *dev, return -ENOSYS; } =20 +static inline int reserved_mem_device_init(struct device *dev, + struct reserved_mem *rmem) +{ + return -ENOSYS; +} + static inline void of_reserved_mem_device_release(struct device *pdev) { } =20 static inline struct reserved_mem *of_reserved_mem_lookup(struct device_no= de *np) --=20 2.31.1.272.g89b43f80a514 From nobody Sun Oct 5 20:17:13 2025 Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) (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 969F6277036 for ; Wed, 30 Jul 2025 09:30:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867807; cv=none; b=MqL9NiCqBBi0tblv95tWfnBMQfDq7DZsxcqVkxHYvCdIrT8A6x0SM2+3/U8Z/wf7FCJmU+XrHC9bCoGUGp1dCNCmqho/n4rRRH21GD7kYkgCZhAO223rw4ntK+vvWLLEL5RO6Ba+LZqBMr8DcbGuRcFmmurAGXOYqcvl1RyMWb4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867807; c=relaxed/simple; bh=AMFrLsSdDLsWD6Yxv/Xp7y8nsNQ2tGUP+On1wCM+8Nc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Mrjtv0raYfEAaFfEZHo3SNWnDyqUIzhqH70eNMm2rAWqEXVIuDsrpk3VsECSyQCqeipXD6e633/scuwvv965kr7cz93nyvPDSrI37X50nELDxMO0NFzqISGxxkX0W4Z2CyEu8UJuKH5bcnPi4bclHW0zejHUr1NDxj1iIN8KT+g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=rQGCvexD; arc=none smtp.client-ip=209.85.210.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="rQGCvexD" Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-749248d06faso5601318b3a.2 for ; Wed, 30 Jul 2025 02:30:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753867805; x=1754472605; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=d4sv190EzN/L51InyJ6GGaDg9k7LvZRYe9Fp2o+cKoI=; b=rQGCvexDqtL77v5LZmfugAbQv5I96nUsvAvw8Z/pKYpMLObcMIOvlragYKp+UAH5sx Je771M8bpOEcO/NmefSj11XI50Ciqy6lzoMvO2srm7yV9KOynWMwh+UZoi2Bsu3xHrdw tw5BEt/9CMJEUkBolLJ/ibY+erPauKcvVyYBVcMI6yLFmR84kHYPBPQdiZw5FbJxA2k9 zqtPvkGUbUzwAtGlBVGksPP4ZZxVGK8nUvOX8qdfYLtLPb1LUoVTPZPsV/7hfI8eMyTu +JgRolkIMrq7itxUkt2eDKjYhjb3RpoYl88hZiZyJGq6UNVOsEksslGfJ6gbjMoCcWLm zjgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753867805; x=1754472605; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=d4sv190EzN/L51InyJ6GGaDg9k7LvZRYe9Fp2o+cKoI=; b=PX6w2G6OOa+wzKOJvVpi1S4MYURl4WFzWqkpNl1QxAI2zyBrXeOWiDCW/tKdX+ULa+ pSq0PBW7REHOezsySnNLcqMF/b7q5yRHB++aeM3YRjbYqczOWWLh5qyasl6pYYsKlAnv TshUr3g6eNWOXb2v8Pvg+8178UTB7w/H2LPZKXgF+edPnoI0Sfcl3bN1JBlL5yLdabcD 36tYzBNRVXyX4HQ6K5kuqi7yn+bol/mbYeBXaBKFQlAfi13fxiJI37S+oUnsCZ3DFide 0dVbTtFrbsoHJwnn5WC0Xz9X4oL0ZNoL7dIhzjqRzdvLW/XUGvWbKOpfon079tzA/+od ST8g== X-Gm-Message-State: AOJu0Yy51M/pd+hCu9FQa5pT8gQn7jxOt8Mo4Ct/c3oFxvobRFXiA7QY BDwvOoGqU6ONkjE5H88XFo20fz7xnbcHeUmXflPgpkVNnyUWmL6pgW0qnq+XldngKZa5O5hYOHK czkY/ X-Gm-Gg: ASbGncvJSohLKuQHtsrxmli6ZKtIIKoOoDSPXXIn46vvFJe1CWPBb9wO3hhydHCxNvy DSENzlAItNBDcP+W1k9RuBeOSBb5JP8qWHBA8pCvDifkTby0h4tIOvqimQCD8BF2avsyoGeH3W0 hw0o4+sH7UkaS6hSMhcT/6N+9KnP9k6UifdW820iYxt1pj6VbK5trW9YsOyNfDJoo2fMHUJjHdT cDjtC+pSG8rzj2g1KJsB9xv/bC8Y7i6lGqlAq33td0QQTV7gmQrTMO7ROG7cr2v6hbGwkCJXFZC m3sNDiAYtZf3E7wgYy96qebog7gA2vdlQj6b7KUG2I1sxAxKE+pUnm91uFQLrlsLus7gs0IV1kv x0du1xmKq1juY9MwUfmqXkiM= X-Google-Smtp-Source: AGHT+IHFAGP1HJe5a9qKM+/ZDWC7kbnIisWwtDj1bGJ4lHuGMD0cLNRjCqCmnmGMtsYPaHtgs9ZyQw== X-Received: by 2002:a05:6a00:ad6:b0:749:ad1:ac8a with SMTP id d2e1a72fcca58-76ab2b55c8dmr4076130b3a.11.1753867804853; Wed, 30 Jul 2025 02:30:04 -0700 (PDT) Received: from localhost ([122.172.85.40]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-769b53591f9sm3880810b3a.35.2025.07.30.02.30.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 02:30:04 -0700 (PDT) From: Viresh Kumar To: linux-kernel@vger.kernel.org, Rob Herring , Saravana Kannan Cc: Viresh Kumar , Arnd Bergmann , Vincent Guittot , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Bill Mills , "Michael S. Tsirkin" , Jason Wang , devicetree@vger.kernel.org, virtualization@lists.linux.dev, Sudeep Holla , Bertrand Marquis , "Edgar E . Iglesias" , Arnaud Pouliquen , Krzysztof Kozlowski , Conor Dooley Subject: [RFC PATCH 2/6] of: reserved-memory: Add of_reserved_mem_lookup_by_name Date: Wed, 30 Jul 2025 14:59:31 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This adds of_reserved_mem_lookup_by_name() helper to get a reserved-memory region based on the DT node name. Signed-off-by: Viresh Kumar --- drivers/of/of_reserved_mem.c | 27 +++++++++++++++++++++++++++ include/linux/of_reserved_mem.h | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index e0a86c3fa656..b94c3b1d14b6 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -758,6 +758,33 @@ struct reserved_mem *of_reserved_mem_lookup(struct dev= ice_node *np) } EXPORT_SYMBOL_GPL(of_reserved_mem_lookup); =20 +/** + * of_reserved_mem_lookup_by_name() - acquire reserved_mem from node name + * @name: node name + * + * This function allows drivers to acquire a reference to the reserved_mem + * struct based on a reserved-memory node name. + * + * Returns a reserved_mem reference, or NULL on error. + */ +struct reserved_mem *of_reserved_mem_lookup_by_name(const char *name) +{ + struct device_node *np __free(device_node) =3D + of_find_node_by_path("/reserved-memory"); + struct device_node *child __free(device_node) =3D NULL; + + if (!np) + return ERR_PTR(-ENODEV); + + for_each_child_of_node(np, child) { + if (of_node_name_eq(child, name)) + return of_reserved_mem_lookup(child); + } + + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(of_reserved_mem_lookup_by_name); + /** * of_reserved_mem_region_to_resource() - Get a reserved memory region as = a resource * @np: node containing 'memory-region' property diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_me= m.h index 3933f1d39e9a..d6d187597b7f 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -41,6 +41,7 @@ int reserved_mem_device_init(struct device *dev, struct r= eserved_mem *rmem); void of_reserved_mem_device_release(struct device *dev); =20 struct reserved_mem *of_reserved_mem_lookup(struct device_node *np); +struct reserved_mem *of_reserved_mem_lookup_by_name(const char *name); int of_reserved_mem_region_to_resource(const struct device_node *np, unsigned int idx, struct resource *res); int of_reserved_mem_region_to_resource_byname(const struct device_node *np, @@ -78,6 +79,11 @@ static inline struct reserved_mem *of_reserved_mem_looku= p(struct device_node *np return NULL; } =20 +static inline struct reserved_mem *of_reserved_mem_lookup_by_name(const ch= ar *name) +{ + return NULL; +} + static inline int of_reserved_mem_region_to_resource(const struct device_n= ode *np, unsigned int idx, struct resource *res) --=20 2.31.1.272.g89b43f80a514 From nobody Sun Oct 5 20:17:13 2025 Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) (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 728F4292B42 for ; Wed, 30 Jul 2025 09:30:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867813; cv=none; b=AYTrPvC0GA3bTu0A+NrPQE2HsebJEu+ImYyr0gUjDJceh9knHkt82AkCQEAbb7U5fM7fdGcvNLdn6clnZgfJtk6ixf+znE/tg4r2E4xTGpNipSGVorohQbswg3tg6oI68NUSSaTHZMvZC+gUNEycd2eQ7IpEVTvDrllLHH812EQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867813; c=relaxed/simple; bh=28YY79GFjl+hM8HZrdmjJDLd2cqTsYSp+YdjB06PAas=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iknjkEH11iPnhcgJqysfHYgbvjQE6bv4N24xzWdFYl2DG0pDGIgqCvLgHZ/jBxf9ZTQkHDGSmiF73X3WuOKRLHKCFIR8uzoD/2NKn7YRKZOdUSCpyYBYR7Sf+K8TwUYYf8R1ubF2hVYILwqKMUN3PjbagQM1M87fZYhGaPfP7Rk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=FWsUuHvh; arc=none smtp.client-ip=209.85.210.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="FWsUuHvh" Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-76a3818eb9bso1158105b3a.3 for ; Wed, 30 Jul 2025 02:30:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753867811; x=1754472611; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zIAaZo+AqJKeIQbQL2TV8b2KKjEOk6DoCk5oJX1a0a8=; b=FWsUuHvhPd0gD5F9OQMglbl/2w8H3IekFleLAaEwnPGxKg4+mMh6glUsjSHfCrn1fH 1rb7kXqpbhIzJc8p3B4ekUMlEV+TFz7Ni3bh9Bi36ZvN4h8ZCjSP+OkQoLbWXLg2IhKP rIPyMNdG8EXD9Av82K85moRBnE/QvCEoD+x33pXgd9NxU4QgAZYJtfbIAU6JrCCvgD8u wC2YbzPkOhbGfQCYaMlHKYcERwkz8KyceJQgqUh++SZFranlYwX7zqlZlPh8yfLLHDcT 3EtAgqbni0hPssV33X7lDr/s9PY3vyurb/Y6fvgXeqB5aNB3U8pziJitfQqgCMiuAeXH 6bFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753867811; x=1754472611; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zIAaZo+AqJKeIQbQL2TV8b2KKjEOk6DoCk5oJX1a0a8=; b=pfDtN1qs6H2xmVW7N2gjdeZxCKgiRza5CRWMDFw1czLFqQQkC5MhT8NvHgD5k381+P X9bXItaaanoCq+6u/h9zKOJsRaYUYVC+30Lj1BH9aZbYymItuovebrVATkWpWQR2v8lU a1KqfDv7oxLEwbTJRvRdkNiBeqo2jyfh5JiL06VkoSSRCtB8UImipcyHJt9wENG+bsaR bZ33ziA3nvUUm6lCMKpdr9St6YlN/rf6GDk94rJMGh7AmlWL2vX/ISPP1x161nnNOGHY MSjjUkXrSeFPGUrm6mPDVjNK5UpovRI64jPXxLTBZgQ3B1U47VuFaxt2xlDO5qi+n9Dk ansA== X-Gm-Message-State: AOJu0YxFJe3tW7knR1cHXEpjfao0lKMhPz7AREDwPXIRvI5MWU6sQHBi BVR38OA6srs5OXiyDtq8EKp5kIVTsuk7tERdkkgb0BPsNu4kKLLgCICICV5sKVVDzusjZNMjgyF t1At6 X-Gm-Gg: ASbGncsGSkzX9Ol7P5CF3E5NWzTx40keMi32kqWok55zGsWG4db3rzjRNgc0MNbfUfB myKx0WYbM0xuUA6YOY2jixJQd8Mb+hp0X0+79zcC9oNlBTqiaadK83A615sjyiYtTS/EFubuexx jr7rqY38KxOuQR62j2TurkDsrv92CEeV1o8x/gZ2tB+ubp+3XnXuhT/pPFzRQJpTvoVfYpQqMRJ kuidjflr1kP7ALeupM/e7zJPhovvP82fnPFKhgqPZcwRQ939lfvNc3mkrex0IyKAgyU+LLNUAdn DnPWmi5AbRdZyO6fcGUIGtPfSv2LH5MpMnDPdbvbfegCfblufnnrr171kxpRoeZom31wFneAMfJ kRq6AX38BnYY9H6gpbv/E8yM= X-Google-Smtp-Source: AGHT+IGoQYRgE/xCt11HlKmjHJ6BWta8RG1iAWKjGhUYUuslzxH8eST83YTCzDSFHb5yqiGXLYNVGQ== X-Received: by 2002:aa7:888a:0:b0:742:a77b:8c4 with SMTP id d2e1a72fcca58-76ab0f1787fmr4602205b3a.3.1753867810602; Wed, 30 Jul 2025 02:30:10 -0700 (PDT) Received: from localhost ([122.172.85.40]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7640ad0688asm9499455b3a.73.2025.07.30.02.30.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 02:30:09 -0700 (PDT) From: Viresh Kumar To: linux-kernel@vger.kernel.org, "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?UTF-8?q?Eugenio=20P=C3=A9rez?= , Viresh Kumar Cc: Arnd Bergmann , Vincent Guittot , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Bill Mills , Rob Herring , Saravana Kannan , devicetree@vger.kernel.org, virtualization@lists.linux.dev, Sudeep Holla , Bertrand Marquis , "Edgar E . Iglesias" , Arnaud Pouliquen , Krzysztof Kozlowski , Conor Dooley Subject: [RFC PATCH 3/6] virtio: Add support for virtio-msg transport Date: Wed, 30 Jul 2025 14:59:32 +0530 Message-Id: <9238de42e22678fdd7c483f407720c9272a56428.1753865268.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This introduces support for a new Virtio transport type: "virtio-msg". Unlike existing transport types like virtio-mmio or virtio-pci which rely on memory-mapped registers, virtio-msg implements transport operations via structured message exchanges using standard virtqueues. It separates bus-level functionality (e.g., device enumeration, hotplug events) from device-specific operations (e.g., feature negotiation, virtqueue setup), ensuring that a single, generic transport layer can be reused across multiple bus implementations (like ARM Firmware Framework (FF-A), IPC, etc.). Signed-off-by: Viresh Kumar --- MAINTAINERS | 7 + drivers/virtio/Kconfig | 7 + drivers/virtio/Makefile | 1 + drivers/virtio/virtio_msg.c | 655 +++++++++++++++++++++++++++ drivers/virtio/virtio_msg_internal.h | 56 +++ include/uapi/linux/virtio_msg.h | 213 +++++++++ 6 files changed, 939 insertions(+) create mode 100644 drivers/virtio/virtio_msg.c create mode 100644 drivers/virtio/virtio_msg_internal.h create mode 100644 include/uapi/linux/virtio_msg.h diff --git a/MAINTAINERS b/MAINTAINERS index c0b444e5fd5a..7d9ecac4fdbd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26358,6 +26358,13 @@ W: https://virtio-mem.gitlab.io/ F: drivers/virtio/virtio_mem.c F: include/uapi/linux/virtio_mem.h =20 +VIRTIO MSG TRANSPORT +M: Viresh Kumar +L: virtualization@lists.linux.dev +S: Maintained +F: drivers/virtio/virtio_msg* +F: include/uapi/linux/virtio_msg* + VIRTIO PMEM DRIVER M: Pankaj Gupta L: virtualization@lists.linux.dev diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 6db5235a7693..690ac98850b6 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -171,6 +171,13 @@ config VIRTIO_MMIO_CMDLINE_DEVICES =20 If unsure, say 'N'. =20 +config VIRTIO_MSG + tristate + select VIRTIO + help + This enables support for Virtio message transport. This option is + selected by any driver which implements the virtio message bus. + config VIRTIO_DMA_SHARED_BUFFER tristate depends on DMA_SHARED_BUFFER diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index eefcfe90d6b8..3eff8ca72446 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_VIRTIO_ANCHOR) +=3D virtio_anchor.o obj-$(CONFIG_VIRTIO_PCI_LIB) +=3D virtio_pci_modern_dev.o obj-$(CONFIG_VIRTIO_PCI_LIB_LEGACY) +=3D virtio_pci_legacy_dev.o obj-$(CONFIG_VIRTIO_MMIO) +=3D virtio_mmio.o +obj-$(CONFIG_VIRTIO_MSG) +=3D virtio_msg.o obj-$(CONFIG_VIRTIO_PCI) +=3D virtio_pci.o virtio_pci-y :=3D virtio_pci_modern.o virtio_pci_common.o virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) +=3D virtio_pci_legacy.o diff --git a/drivers/virtio/virtio_msg.c b/drivers/virtio/virtio_msg.c new file mode 100644 index 000000000000..7034818475ab --- /dev/null +++ b/drivers/virtio/virtio_msg.c @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Virtio message transport. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + * + * The virtio-msg transport encapsulates virtio operations as discrete mes= sage + * exchanges rather than relying on PCI or memory-mapped I/O regions. It + * separates bus-level functionality (e.g., device enumeration, hotplug ev= ents) + * from device-specific operations (e.g., feature negotiation, virtqueue s= etup), + * ensuring that a single, generic transport layer can be reused across mu= ltiple + * bus implementations (like ARM Firmware Framework (FF-A), IPC, etc.). + * + * This file implements the generic Virtio message transport layer. + */ + +#define pr_fmt(fmt) "virtio-msg: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "virtio_msg_internal.h" + +#define to_virtio_msg_device(_dev) \ + container_of(_dev, struct virtio_msg_device, vdev) + +static void msg_prepare(struct virtio_msg *vmsg, bool bus, u8 msg_id, + u16 dev_id, u16 payload_size) +{ + u16 size =3D sizeof(*vmsg) + payload_size; + + memset(vmsg, 0, size); + + if (bus) { + vmsg->type =3D VIRTIO_MSG_TYPE_BUS; + } else { + vmsg->type =3D VIRTIO_MSG_TYPE_TRANSPORT; + vmsg->dev_id =3D cpu_to_le16(dev_id); + } + + vmsg->msg_id =3D msg_id; + vmsg->msg_size =3D cpu_to_le16(size); +} + +static void transport_msg_prepare(struct virtio_msg_device *vmdev, u8 msg_= id, + u16 payload_size) +{ + msg_prepare(vmdev->request, false, msg_id, vmdev->dev_id, payload_size); +} + +/** + * virtio_msg_prepare - Initialize a virtio message for bus transfer + * @vmsg: Pointer to the virtio message structure to initialize + * @msg_id: Message ID to set in the message header + * @payload_size: Size of the payload (in bytes) + * + * Prepares a virtio_msg structure for transmission over the bus transport + * (VIRTIO_MSG_TYPE_BUS). The payload buffer follows the header. + */ +void virtio_msg_prepare(struct virtio_msg *vmsg, u8 msg_id, u16 payload_si= ze) +{ + msg_prepare(vmsg, true, msg_id, 0, payload_size); +} +EXPORT_SYMBOL_GPL(virtio_msg_prepare); + +static int virtio_msg_xfer(struct virtio_msg_device *vmdev) +{ + int ret; + + memset(vmdev->response, 0, vmdev->msg_size); + + ret =3D vmdev->ops->transfer(vmdev, vmdev->request, vmdev->response); + if (ret) + dev_err(&vmdev->vdev.dev, "Transfer request failed (%d)\n", ret); + + return ret; +} + +static inline int virtio_msg_send(struct virtio_msg_device *vmdev) +{ + int ret; + + ret =3D vmdev->ops->transfer(vmdev, vmdev->request, NULL); + if (ret) + dev_err(&vmdev->vdev.dev, "Send request failed (%d)\n", ret); + + return ret; +} + +static int virtio_msg_get_device_info(struct virtio_msg_device *vmdev) +{ + struct get_device_info_resp *payload =3D virtio_msg_payload(vmdev->respon= se); + struct virtio_device *vdev =3D &vmdev->vdev; + u32 num_feature_bits; + int ret; + + static_assert(sizeof(*vmdev->response) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_DEVICE_INFO, 0); + + ret =3D virtio_msg_xfer(vmdev); + if (ret) + return ret; + + vdev->id.device =3D le32_to_cpu(payload->device_id); + if (vdev->id.device =3D=3D 0) { + /* + * A virtio device with ID 0 is a placeholder and indicates no + * valid device function is present. + */ + return -ENODEV; + } + + vdev->id.vendor =3D le32_to_cpu(payload->vendor_id); + vmdev->config_size =3D le32_to_cpu(payload->config_size); + num_feature_bits =3D le32_to_cpu(payload->num_feature_bits); + + /* Linux supports 64 feature bits */ + if (num_feature_bits !=3D 64) { + dev_err(&vdev->dev, "Incompatible num_feature_bits (%u)\n", + num_feature_bits); + return -EINVAL; + } + + return 0; +} + +static u64 virtio_msg_get_features(struct virtio_device *vdev) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct get_features *req_payload =3D virtio_msg_payload(vmdev->request); + struct get_features_resp *res_payload =3D virtio_msg_payload(vmdev->respo= nse); + __le32 *features; + int ret; + + static_assert(sizeof(*vmdev->request) + sizeof(*req_payload) < + VIRTIO_MSG_MIN_SIZE); + static_assert(sizeof(*vmdev->response) + sizeof(*res_payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_GET_DEV_FEATURES, + sizeof(*req_payload)); + + /* Linux supports 64 feature bits */ + req_payload->num =3D cpu_to_le32(2); + req_payload->index =3D 0; + + ret =3D virtio_msg_xfer(vmdev); + if (ret) + return 0; + + features =3D (__le32 *)res_payload->features; + return ((u64)(le32_to_cpu(features[1])) << 32) | le32_to_cpu(features[0]); +} + +static int virtio_msg_finalize_features(struct virtio_device *vdev) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct set_features *payload =3D virtio_msg_payload(vmdev->request); + __le32 *features =3D (__le32 *)payload->features; + + static_assert(sizeof(*vmdev->request) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + /* Give virtio_ring a chance to accept features */ + vring_transport_features(vdev); + + transport_msg_prepare(vmdev, VIRTIO_MSG_SET_DRV_FEATURES, sizeof(*payload= )); + + /* Linux supports 64 feature bits */ + payload->num =3D cpu_to_le32(2); + payload->index =3D 0; + + features[0] =3D cpu_to_le32((u32)vmdev->vdev.features); + features[1] =3D cpu_to_le32(vmdev->vdev.features >> 32); + + return virtio_msg_xfer(vmdev); +} + +static void virtio_msg_get(struct virtio_device *vdev, unsigned int offset, + void *buf, unsigned int len) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct get_config *req_payload =3D virtio_msg_payload(vmdev->request); + struct get_config_resp *res_payload =3D virtio_msg_payload(vmdev->respons= e); + u32 i =3D 0, max; + + static_assert(sizeof(*vmdev->request) + sizeof(*req_payload) < + VIRTIO_MSG_MIN_SIZE); + static_assert(sizeof(*vmdev->response) + sizeof(*res_payload) < + VIRTIO_MSG_MIN_SIZE); + + if (offset + len > vmdev->config_size) { + dev_err(&vmdev->vdev.dev, + "Invalid config read operation: %u: %u: %u\n", offset, + len, vmdev->config_size); + return; + } + + /* Maximum payload size available in the response message buffer */ + max =3D vmdev->msg_size - sizeof(*vmdev->response) - sizeof(*res_payload); + + transport_msg_prepare(vmdev, VIRTIO_MSG_GET_CONFIG, sizeof(*req_payload)); + + while (i !=3D len) { + u32 size =3D min(max, len - i); + + req_payload->offset =3D cpu_to_le32(offset + i); + req_payload->size =3D cpu_to_le32(size); + + if (virtio_msg_xfer(vmdev)) + return; + + /* Buffer holds the data in little endian */ + memcpy(buf + i, res_payload->config, size); + i +=3D size; + } + + vmdev->generation_count =3D le32_to_cpu(res_payload->generation); +} + +static void virtio_msg_set(struct virtio_device *vdev, unsigned int offset, + const void *buf, unsigned int len) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct set_config *payload =3D virtio_msg_payload(vmdev->request); + u32 i =3D 0, max; + + static_assert(sizeof(*vmdev->request) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + if (offset + len > vmdev->config_size) { + dev_err(&vmdev->vdev.dev, + "Invalid config write operation: %u: %u: %u\n", offset, + len, vmdev->config_size); + return; + } + + /* Maximum payload size available in the request message buffer */ + max =3D vmdev->msg_size - sizeof(*vmdev->request) - sizeof(*payload); + + transport_msg_prepare(vmdev, VIRTIO_MSG_SET_CONFIG, sizeof(*payload)); + payload->generation =3D cpu_to_le32(vmdev->generation_count); + + while (i !=3D len) { + u32 size =3D min(max, len - i); + + payload->offset =3D cpu_to_le32(offset + i); + payload->size =3D cpu_to_le32(size); + + /* Buffer holds the data in little endian */ + memcpy(payload->config, buf + i, size); + i +=3D size; + + if (virtio_msg_xfer(vmdev)) + return; + } +} + +static u32 virtio_msg_generation(struct virtio_device *vdev) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct get_config *req_payload =3D virtio_msg_payload(vmdev->request); + struct get_config_resp *res_payload =3D virtio_msg_payload(vmdev->respons= e); + + transport_msg_prepare(vmdev, VIRTIO_MSG_GET_CONFIG, sizeof(*req_payload)); + req_payload->offset =3D cpu_to_le32(0); + req_payload->size =3D cpu_to_le32(0); + + if (virtio_msg_xfer(vmdev)) + return 0; + + vmdev->generation_count =3D le32_to_cpu(res_payload->generation); + return vmdev->generation_count; +} + +static u8 virtio_msg_get_status(struct virtio_device *vdev) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct get_device_status_resp *payload =3D virtio_msg_payload(vmdev->resp= onse); + + static_assert(sizeof(*vmdev->response) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_GET_DEVICE_STATUS, 0); + + if (virtio_msg_xfer(vmdev)) + return 0; + + return (u8)le32_to_cpu(payload->status); +} + +static void virtio_msg_set_status(struct virtio_device *vdev, u8 status) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + struct set_device_status *payload =3D virtio_msg_payload(vmdev->request); + + static_assert(sizeof(*vmdev->request) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_SET_DEVICE_STATUS, sizeof(*payloa= d)); + payload->status =3D cpu_to_le32(status); + + if (virtio_msg_xfer(vmdev)) + dev_warn(&vmdev->vdev.dev, "Set status %u failed\n", status); +} + +static void virtio_msg_vq_reset(struct virtqueue *vq) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vq->vdev); + struct reset_vqueue *payload =3D virtio_msg_payload(vmdev->request); + + static_assert(sizeof(*vmdev->request) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_RESET_VQUEUE, sizeof(*payload)); + payload->index =3D cpu_to_le32(vq->index); + + if (virtio_msg_xfer(vmdev)) + dev_warn(&vmdev->vdev.dev, "Virtqueue reset failed\n"); +} + +static void virtio_msg_reset(struct virtio_device *vdev) +{ + /* Setting status to 0 initiates a device reset */ + virtio_msg_set_status(vdev, 0); +} + +static bool _vmsg_notify(struct virtqueue *vq, u32 index, u32 offset, u32 = wrap) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vq->vdev); + struct event_avail *payload =3D virtio_msg_payload(vmdev->request); + u32 val; + + static_assert(sizeof(*vmdev->request) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_EVENT_AVAIL, sizeof(*payload)); + payload->index =3D cpu_to_le32(index); + + val =3D offset & ((1U << VIRTIO_MSG_EVENT_AVAIL_WRAP_SHIFT) - 1); + val |=3D wrap & (1U << VIRTIO_MSG_EVENT_AVAIL_WRAP_SHIFT); + payload->next_offset_wrap =3D cpu_to_le32(val); + + return !virtio_msg_send(vmdev); +} + +static bool virtio_msg_notify(struct virtqueue *vq) +{ + return _vmsg_notify(vq, vq->index, 0, 0); +} + +static bool virtio_msg_notify_with_data(struct virtqueue *vq) +{ + u32 index, offset, wrap, data =3D vring_notification_data(vq); + + index =3D data | 0xFFFF; + data >>=3D 16; + offset =3D data | 0x7FFF; + wrap =3D data >> 15; + + return _vmsg_notify(vq, index, offset, wrap); +} + +/** + * virtio_msg_event - Handle an incoming event message for a virtio messag= e device. + * @vmdev: Pointer to the virtio message device. + * @vmsg: Pointer to the incoming virtio message containing the event. + * + * Processes an event message received from the bus layer for the given + * virtio message device. Depending on the message type, this function eit= her: + * + * - Triggers the device configuration change handler if the message is o= f type + * VIRTIO_MSG_EVENT_CONFIG. + * + * - Delivers a used-buffer notification to the corresponding virtqueue i= f the + * message is of type VIRTIO_MSG_EVENT_USED. + * + * Return: 0 on success, -EIO if the interrupt handler fails, -EINVAL for + * unknown message types or invalid virtqueue indices. + */ +int virtio_msg_event(struct virtio_msg_device *vmdev, struct virtio_msg *v= msg) +{ + struct event_used *payload =3D virtio_msg_payload(vmsg); + struct device *dev =3D &vmdev->vdev.dev; + struct virtqueue *vq; + unsigned int index; + + if (vmsg->msg_id =3D=3D VIRTIO_MSG_EVENT_CONFIG) { + virtio_config_changed(&vmdev->vdev); + return 0; + } + + if (vmsg->msg_id =3D=3D VIRTIO_MSG_EVENT_USED) { + index =3D le32_to_cpu(payload->index); + + virtio_device_for_each_vq(&vmdev->vdev, vq) { + if (index =3D=3D vq->index) { + if (vring_interrupt(0, vq) !=3D IRQ_HANDLED) + return -EIO; + + return 0; + } + } + + dev_err(dev, "Failed to find virtqueue (%u)", index); + } else { + dev_err(dev, "Unexpected message id: (%u)\n", vmsg->msg_id); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(virtio_msg_event); + +static void virtio_msg_del_vqs(struct virtio_device *vdev) +{ + struct virtqueue *vq, *n; + + list_for_each_entry_safe(vq, n, &vdev->vqs, list) { + virtio_msg_vq_reset(vq); + vring_del_virtqueue(vq); + } +} + +static int virtio_msg_vq_get(struct virtio_msg_device *vmdev, unsigned int= *num, + unsigned int index) +{ + struct get_vqueue *req_payload =3D virtio_msg_payload(vmdev->request); + struct get_vqueue_resp *res_payload =3D virtio_msg_payload(vmdev->respons= e); + int ret; + + static_assert(sizeof(*vmdev->request) + sizeof(*req_payload) < + VIRTIO_MSG_MIN_SIZE); + static_assert(sizeof(*vmdev->response) + sizeof(*res_payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_GET_VQUEUE, sizeof(*req_payload)); + req_payload->index =3D cpu_to_le32(index); + + ret =3D virtio_msg_xfer(vmdev); + if (ret) + return ret; + + *num =3D le32_to_cpu(res_payload->max_size); + if (!*num) + return -ENOENT; + + return 0; +} + +static int virtio_msg_vq_set(struct virtio_msg_device *vmdev, + struct virtqueue *vq, unsigned int index) +{ + struct set_vqueue *payload =3D virtio_msg_payload(vmdev->request); + + static_assert(sizeof(*vmdev->request) + sizeof(*payload) < + VIRTIO_MSG_MIN_SIZE); + + transport_msg_prepare(vmdev, VIRTIO_MSG_SET_VQUEUE, sizeof(*payload)); + payload->index =3D cpu_to_le32(index); + payload->size =3D cpu_to_le32(virtqueue_get_vring_size(vq)); + payload->descriptor_addr =3D cpu_to_le64(virtqueue_get_desc_addr(vq)); + payload->driver_addr =3D cpu_to_le64(virtqueue_get_avail_addr(vq)); + payload->device_addr =3D cpu_to_le64(virtqueue_get_used_addr(vq)); + + return virtio_msg_xfer(vmdev); +} + +static struct virtqueue * +virtio_msg_setup_vq(struct virtio_msg_device *vmdev, unsigned int index, + void (*callback)(struct virtqueue *vq), const char *name, + bool ctx) +{ + bool (*notify)(struct virtqueue *vq); + struct virtqueue *vq; + unsigned int num; + int ret; + + if (__virtio_test_bit(&vmdev->vdev, VIRTIO_F_NOTIFICATION_DATA)) + notify =3D virtio_msg_notify_with_data; + else + notify =3D virtio_msg_notify; + + ret =3D virtio_msg_vq_get(vmdev, &num, index); + if (ret) + return ERR_PTR(ret); + + vq =3D vring_create_virtqueue(index, num, PAGE_SIZE, &vmdev->vdev, true, + true, ctx, notify, callback, name); + if (!vq) + return ERR_PTR(-ENOMEM); + + vq->num_max =3D num; + + ret =3D virtio_msg_vq_set(vmdev, vq, index); + if (ret) { + vring_del_virtqueue(vq); + return ERR_PTR(ret); + } + + return vq; +} + +static int virtio_msg_find_vqs(struct virtio_device *vdev, unsigned int nv= qs, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + struct irq_affinity *desc) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + int i, queue_idx =3D 0; + + for (i =3D 0; i < nvqs; ++i) { + struct virtqueue_info *vqi =3D &vqs_info[i]; + + if (!vqi->name) { + vqs[i] =3D NULL; + continue; + } + + vqs[i] =3D virtio_msg_setup_vq(vmdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx); + if (IS_ERR(vqs[i])) { + virtio_msg_del_vqs(vdev); + return PTR_ERR(vqs[i]); + } + } + + return 0; +} + +static const char *virtio_msg_bus_name(struct virtio_device *vdev) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + + return vmdev->bus_name; +} + +static void virtio_msg_synchronize_cbs(struct virtio_device *vdev) +{ + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + + vmdev->ops->synchronize_cbs(vmdev); +} + +static void virtio_msg_release_dev(struct device *_d) +{ + struct virtio_device *vdev =3D + container_of(_d, struct virtio_device, dev); + struct virtio_msg_device *vmdev =3D to_virtio_msg_device(vdev); + + if (vmdev->ops->release) + vmdev->ops->release(vmdev); +} + +static struct virtio_config_ops virtio_msg_config_ops =3D { + .get =3D virtio_msg_get, + .set =3D virtio_msg_set, + .generation =3D virtio_msg_generation, + .get_status =3D virtio_msg_get_status, + .set_status =3D virtio_msg_set_status, + .reset =3D virtio_msg_reset, + .find_vqs =3D virtio_msg_find_vqs, + .del_vqs =3D virtio_msg_del_vqs, + .get_features =3D virtio_msg_get_features, + .finalize_features =3D virtio_msg_finalize_features, + .bus_name =3D virtio_msg_bus_name, +}; + +/** + * virtio_msg_register - Register a virtio message device with the virtio = core + * @vmdev: Pointer to the virtio message device to register + * + * Initializes and registers a virtio message device. + * + * Return: 0 on success, or a negative error code on failure. + */ +int virtio_msg_register(struct virtio_msg_device *vmdev) +{ + u32 version; + int ret; + + if (!vmdev || !vmdev->ops || !vmdev->ops->bus_info || + !vmdev->ops->transfer) + return -EINVAL; + + vmdev->bus_name =3D vmdev->ops->bus_info(vmdev, &vmdev->msg_size, + &version); + if (version !=3D VIRTIO_MSG_REVISION_1 || + vmdev->msg_size < VIRTIO_MSG_MIN_SIZE) + return -EINVAL; + + /* + * Allocate per-device request and response buffers, each of size + * `msg_size`. + * + * Since requests are serialized per device, one pair of buffers + * suffices. + */ + vmdev->request =3D kzalloc(2 * vmdev->msg_size, GFP_KERNEL); + if (!vmdev->request) + return -ENOMEM; + + vmdev->response =3D (void *)vmdev->request + vmdev->msg_size; + + vmdev->vdev.config =3D &virtio_msg_config_ops; + vmdev->vdev.dev.release =3D virtio_msg_release_dev; + + if (vmdev->ops->synchronize_cbs) + virtio_msg_config_ops.synchronize_cbs =3D virtio_msg_synchronize_cbs; + + ret =3D virtio_msg_get_device_info(vmdev); + if (ret) { + if (vmdev->ops->release) + vmdev->ops->release(vmdev); + goto free; + } + + ret =3D register_virtio_device(&vmdev->vdev); + if (ret) { + put_device(&vmdev->vdev.dev); + goto free; + } + + return 0; + +free: + kfree(vmdev->request); + return ret; +} +EXPORT_SYMBOL_GPL(virtio_msg_register); + +/** + * virtio_msg_unregister - Unregister a virtio message device + * @vmdev: Pointer to the virtio message device to unregister + * + * Unregisters a previously registered virtio message device from the virt= io + * core and releases associated resources. + */ +void virtio_msg_unregister(struct virtio_msg_device *vmdev) +{ + unregister_virtio_device(&vmdev->vdev); + kfree(vmdev->request); +} +EXPORT_SYMBOL_GPL(virtio_msg_unregister); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("Virtio message transport"); +MODULE_LICENSE("GPL"); diff --git a/drivers/virtio/virtio_msg_internal.h b/drivers/virtio/virtio_m= sg_internal.h new file mode 100644 index 000000000000..b7c2cb44b67b --- /dev/null +++ b/drivers/virtio/virtio_msg_internal.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) */ +/* + * Virtio message transport header. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + */ + +#ifndef _DRIVERS_VIRTIO_MSG_INTERNAL_H +#define _DRIVERS_VIRTIO_MSG_INTERNAL_H + +#include +#include + +struct virtio_msg_device; + +/* + * struct virtio_msg_ops - Virtio message bus operations. + * @bus_info: Return bus information. + * @transfer: Transfer a message. + * @synchronize_cbs: Synchronize with the virtqueue callbacks (optional). + * @release: Release the resources corresponding to the device (optional). + */ +struct virtio_msg_ops { + const char *(*bus_info)(struct virtio_msg_device *vmdev, u16 *msg_size, u= 32 *rev); + int (*transfer)(struct virtio_msg_device *vmdev, struct virtio_msg *reque= st, + struct virtio_msg *response); + void (*synchronize_cbs)(struct virtio_msg_device *vmdev); + void (*release)(struct virtio_msg_device *vmdev); +}; + +/* + * Representation of a device using virtio message + * transport. + */ +struct virtio_msg_device { + struct virtio_device vdev; + struct virtio_msg_ops *ops; + const char *bus_name; + void *bus_data; + u32 generation_count; + u32 config_size; + u16 msg_size; + u16 dev_id; + + struct virtio_msg *request; + struct virtio_msg *response; +}; + +int virtio_msg_register(struct virtio_msg_device *vmdev); +void virtio_msg_unregister(struct virtio_msg_device *vmdev); + +void virtio_msg_prepare(struct virtio_msg *vmsg, u8 msg_id, u16 payload_si= ze); +int virtio_msg_event(struct virtio_msg_device *vmdev, struct virtio_msg *v= msg); + +#endif /* _DRIVERS_VIRTIO_MSG_INTERNAL_H */ diff --git a/include/uapi/linux/virtio_msg.h b/include/uapi/linux/virtio_ms= g.h new file mode 100644 index 000000000000..4f619906015b --- /dev/null +++ b/include/uapi/linux/virtio_msg.h @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) */ +/* + * Virtio message transport header. + * + * Copyright (c) 2025 Advanced Micro Devices, Inc. + * Written by Edgar E. Iglesias + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + */ + +#ifndef _LINUX_VIRTIO_MSG_H +#define _LINUX_VIRTIO_MSG_H + +#include + +/* Virtio message transport definitions */ + +/* Message types */ +#define VIRTIO_MSG_DEVICE_INFO 0x02 +#define VIRTIO_MSG_GET_DEV_FEATURES 0x03 +#define VIRTIO_MSG_SET_DRV_FEATURES 0x04 +#define VIRTIO_MSG_GET_CONFIG 0x05 +#define VIRTIO_MSG_SET_CONFIG 0x06 +#define VIRTIO_MSG_GET_DEVICE_STATUS 0x07 +#define VIRTIO_MSG_SET_DEVICE_STATUS 0x08 +#define VIRTIO_MSG_GET_VQUEUE 0x09 +#define VIRTIO_MSG_SET_VQUEUE 0x0a +#define VIRTIO_MSG_RESET_VQUEUE 0x0b +#define VIRTIO_MSG_GET_SHM 0x0c +#define VIRTIO_MSG_EVENT_CONFIG 0x40 +#define VIRTIO_MSG_EVENT_AVAIL 0x41 +#define VIRTIO_MSG_EVENT_USED 0x42 +#define VIRTIO_MSG_MAX VIRTIO_MSG_EVENT_USED + +#define VIRTIO_MSG_MIN_SIZE 44 +#define VIRTIO_MSG_MAX_SIZE 65536 +#define VIRTIO_MSG_REVISION_1 0x1 + +/* Message payload format */ + +struct get_device_info_resp { + __le32 device_id; + __le32 vendor_id; + __le32 num_feature_bits; + __le32 config_size; + __le32 max_vq_count; + __le16 admin_vq_start_idx; + __le16 admin_vq_count; +} __attribute__((packed)); + +struct get_features { + __le32 index; + __le32 num; +} __attribute__((packed)); + +struct get_features_resp { + __le32 index; + __le32 num; + __u8 features[]; +} __attribute__((packed)); + +struct set_features { + __le32 index; + __le32 num; + __u8 features[]; +} __attribute__((packed)); + +struct get_config { + __le32 offset; + __le32 size; +} __attribute__((packed)); + +struct get_config_resp { + __le32 generation; + __le32 offset; + __le32 size; + __u8 config[]; +} __attribute__((packed)); + +struct set_config { + __le32 generation; + __le32 offset; + __le32 size; + __u8 config[]; +} __attribute__((packed)); + +struct set_config_resp { + __le32 generation; + __le32 offset; + __le32 size; + __u8 config[]; +} __attribute__((packed)); + +struct get_device_status_resp { + __le32 status; +} __attribute__((packed)); + +struct set_device_status { + __le32 status; +} __attribute__((packed)); + +struct set_device_status_resp { + __le32 status; +} __attribute__((packed)); + +struct get_vqueue { + __le32 index; +} __attribute__((packed)); + +struct get_vqueue_resp { + __le32 index; + __le32 max_size; + __le32 size; + __le64 descriptor_addr; + __le64 driver_addr; + __le64 device_addr; +} __attribute__((packed)); + +struct set_vqueue { + __le32 index; + __le32 unused; + __le32 size; + __le64 descriptor_addr; + __le64 driver_addr; + __le64 device_addr; +} __attribute__((packed)); + +struct reset_vqueue { + __le32 index; +} __attribute__((packed)); + +struct get_shm { + __le32 index; +} __attribute__((packed)); + +struct get_shm_resp { + __le32 index; + __le32 count; + __le32 addr; +} __attribute__((packed)); + +struct event_config { + __le32 status; + __le32 generation; + __le32 offset; + __le32 size; + __u8 config[]; +} __attribute__((packed)); + +struct event_avail { + __le32 index; + #define VIRTIO_MSG_EVENT_AVAIL_WRAP_SHIFT 31 + __le32 next_offset_wrap; +} __attribute__((packed)); + +struct event_used { + __le32 index; +} __attribute__((packed)); + +struct virtio_msg { + #define VIRTIO_MSG_TYPE_REQUEST (0 << 0) + #define VIRTIO_MSG_TYPE_RESPONSE (1 << 0) + #define VIRTIO_MSG_TYPE_TRANSPORT (0 << 1) + #define VIRTIO_MSG_TYPE_BUS (1 << 1) + __u8 type; + + __u8 msg_id; + __le16 dev_id; + __le16 msg_size; + __u8 payload[]; +} __attribute__((packed)); + +static inline void *virtio_msg_payload(struct virtio_msg *vmsg) +{ + return &vmsg->payload; +} + +/* Virtio message bus definitions */ + +/* Message types */ +#define VIRTIO_MSG_BUS_GET_DEVICES 0x02 +#define VIRTIO_MSG_BUS_PING 0x03 +#define VIRTIO_MSG_BUS_EVENT_DEVICE 0x40 + +struct bus_get_devices { + __le16 offset; + __le16 num; +} __attribute__((packed)); + +struct bus_get_devices_resp { + __le16 offset; + __le16 num; + __le16 next_offset; + __u8 devices[]; +} __attribute__((packed)); + +struct bus_event_device { + __le16 dev_num; + #define VIRTIO_MSG_BUS_EVENT_DEV_STATE_READY 0x1 + #define VIRTIO_MSG_BUS_EVENT_DEV_STATE_REMOVED 0x2 + __le16 dev_state; +} __attribute__((packed)); + +struct bus_ping { + __le32 data; +} __attribute__((packed)); + +struct bus_ping_resp { + __le32 data; +} __attribute__((packed)); + +#endif /* _LINUX_VIRTIO_MSG_H */ --=20 2.31.1.272.g89b43f80a514 From nobody Sun Oct 5 20:17:13 2025 Received: from mail-pf1-f169.google.com (mail-pf1-f169.google.com [209.85.210.169]) (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 DD35027603B for ; Wed, 30 Jul 2025 09:30:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867817; cv=none; b=oxIuu+IUpiQX5V4EDg7c4oOH9ou0TGjrooE+F7kFGZqSa6yIKbbhcgw24zJt4wxQhMqYYBbuVdxBimpquC7yhQ33kwxOqYyHq080QypoCeHbyXm5p0WFOPs2HEnASmIlSAzL3LNjcNCrvi5I/gGQyivg4eKnPAVCj3gF802YhEg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867817; c=relaxed/simple; bh=6f8fR5oGU3uBFsY6EzBrs3St+X+QZ3T82ZZgrxz65Vg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rN84NcYRcnhY81NYBMgcnqiOEdXJ4pDuG25cKJj6xUrkQpMOU2rrtGIKhP/XKxMBYQsUllob0WLs2nvc3isPl2x8K87maO0kS7wVH41haH4yQPcJ6GY/Oavh+QzH1L9nhewM+6RjZdt8lwPIukHXyFBCaSz90sZt/nV9tNbThHo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=KAonyiCo; arc=none smtp.client-ip=209.85.210.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="KAonyiCo" Received: by mail-pf1-f169.google.com with SMTP id d2e1a72fcca58-7425bd5a83aso6235026b3a.0 for ; Wed, 30 Jul 2025 02:30:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753867815; x=1754472615; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TEy7nkqd60biSBMPI8mV+T/3vRYKIkBFSmMXiXvTu5Q=; b=KAonyiConlnxTL1dKyGhv3U33EisCQMJBpCLKP/1fSGAyxD9f3gQrGv0+VfafZx7z/ gBlZjbJt8eYjlmo5o4AEWiomUgwQJYQHNPToYB5AyMRafvkxXCmofnzbQdNqFlDw5Ix7 bRYvWPsa3poMTKBO6N5FayTcE21WUhwtc7JxXQVxRQOU/nMq2AaedFrtrvltaHg+ynY/ DTFSA5J+jKLHKHRrZDUU20496LE6xoKiEr7d2/aUuc/ZBoCoHXNTKMJeFjouTJD+C/Mb p0Z9MW+isuLzapkxw08Ou1qZFBTucVhtmBXs2Di6dhEOusqWWDlhn8bJSEE3LT0s9f34 4y/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753867815; x=1754472615; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TEy7nkqd60biSBMPI8mV+T/3vRYKIkBFSmMXiXvTu5Q=; b=gQYlOzhvgI3qdb8NuWTuf+0iYSO5bTkl68BeK4VQWtVUG5SpkEnyeUwd5jQZ4vptId E5UUHJaHr/3mYxbggZFNIGbLRLfW2R06DOf6swD3drm5XxISyp1zu30qSbT45dW+U2Jn fqWUdt5CL99S/T0YNoSUbTVyVdNSnRRYR1ZEVqEEFOT40X1IIwa65OnaISNCePTd5lmO f6b6G2OU2xqiiC3r3Sg53q7RwjbIc6uuqzX6suDjm47ezOrKK4exz8Xinu3IOTQGq5yN +7gcmXJdxSYoHrGQ6ss2334vDBzUp81KelQ6qXbbZsXl0jO9xGIeqo6EuA+ABBXPU1n7 kZyw== X-Gm-Message-State: AOJu0YwtJAG6oq5CKiVS52zRUGTkxgeldAojuv4F5krJ7fP/YfnOcix7 HMn9/lgATievq9OhyW7TV2kA5IzptxzV7/sxGqgJg8QdVnJclCX6VhWIGb4VnR6O3jO3fj+sjgH eDoVg X-Gm-Gg: ASbGncvwKLUkkvsmuAsjM6OTp+mrE5lck5lsSS4FL+gVB/EIyElrNMZqI2eIwtPSNpK W8yDExuuxOQz9AKO7q9o9x3vaoRewSlHK09r7FIz57Uie1JuMnmQG//Cil5f5iVNMye206rS2CG yz+hQZj9ijKKZZpyzgqYlcDlUqrYYlR4dWif2+/DAHj72ZN4y0dSJtd+HBFVOOxi6GppDX270vD UfsHT8beBz7h6m+xcZMSgKXLL6jkD6SyOLcxO06kyT1TGKAsMBCYixqZ3NrIMFmpjCb3tgjp3ep YhpHreub6LWRGVWC5VkSvp19By1l/IhRsa3cW9kWJxEgwKVIW6vKA/LZtHcQCCqqGfVjvyMSeb7 FU3K/VkPlV3wfJ2yULTEMnHg= X-Google-Smtp-Source: AGHT+IEBL0ir8PS5GKTv6LcN3fEFv6jphsgvwEpAmbEVl0EK6WXhOEQBi3VfOVeY0YtPPql5u2NErA== X-Received: by 2002:a05:6a00:2347:b0:74e:a560:dd23 with SMTP id d2e1a72fcca58-76ab30c553dmr4723064b3a.21.1753867815053; Wed, 30 Jul 2025 02:30:15 -0700 (PDT) Received: from localhost ([122.172.85.40]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7640872a209sm10182952b3a.4.2025.07.30.02.30.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 02:30:14 -0700 (PDT) From: Viresh Kumar To: linux-kernel@vger.kernel.org, "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?UTF-8?q?Eugenio=20P=C3=A9rez?= , Viresh Kumar Cc: Arnd Bergmann , Vincent Guittot , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Bill Mills , Rob Herring , Saravana Kannan , devicetree@vger.kernel.org, virtualization@lists.linux.dev, Sudeep Holla , Bertrand Marquis , "Edgar E . Iglesias" , Arnaud Pouliquen , Krzysztof Kozlowski , Conor Dooley Subject: [RFC PATCH 4/6] virtio-msg: Add optional userspace interface for message I/O Date: Wed, 30 Jul 2025 14:59:33 +0530 Message-Id: <97ae7b7bea8a22108aaebdfd9330de93ecc91333.1753865268.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for an optional userspace interface to the virtio-msg transport via a per-bus miscdevice. When enabled by a bus implementation, this interface allows userspace to send and receive virtio messages through a character device node. A separate device node is created for each bus that registers for userspace access, e.g., /dev/virtio-msg-N. This enables backend-side components or test tools to interact with the transport layer directly from userspace. Bus implementations that do not require userspace interaction can omit this interface entirely. Signed-off-by: Viresh Kumar --- drivers/virtio/Kconfig | 8 ++ drivers/virtio/Makefile | 4 +- drivers/virtio/virtio_msg_internal.h | 32 ++++++ drivers/virtio/virtio_msg_user.c | 140 +++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 drivers/virtio/virtio_msg_user.c diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 690ac98850b6..a86025c9e008 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -178,6 +178,14 @@ config VIRTIO_MSG This enables support for Virtio message transport. This option is selected by any driver which implements the virtio message bus. =20 +config VIRTIO_MSG_USER + tristate "Userspace interface for virtio message transport" + depends on VIRTIO_MSG + help + This enables userspace interface for Virtio message transport. This + can be used to read / write messages over virtio-msg transport from + userspace. + config VIRTIO_DMA_SHARED_BUFFER tristate depends on DMA_SHARED_BUFFER diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 3eff8ca72446..5b664c5f5f25 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -4,7 +4,9 @@ obj-$(CONFIG_VIRTIO_ANCHOR) +=3D virtio_anchor.o obj-$(CONFIG_VIRTIO_PCI_LIB) +=3D virtio_pci_modern_dev.o obj-$(CONFIG_VIRTIO_PCI_LIB_LEGACY) +=3D virtio_pci_legacy_dev.o obj-$(CONFIG_VIRTIO_MMIO) +=3D virtio_mmio.o -obj-$(CONFIG_VIRTIO_MSG) +=3D virtio_msg.o +virtio_msg_transport-y :=3D virtio_msg.o +virtio_msg_transport-$(CONFIG_VIRTIO_MSG_USER) +=3D virtio_msg_user.o +obj-$(CONFIG_VIRTIO_MSG) +=3D virtio_msg_transport.o obj-$(CONFIG_VIRTIO_PCI) +=3D virtio_pci.o virtio_pci-y :=3D virtio_pci_modern.o virtio_pci_common.o virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) +=3D virtio_pci_legacy.o diff --git a/drivers/virtio/virtio_msg_internal.h b/drivers/virtio/virtio_m= sg_internal.h index b7c2cb44b67b..0d13d73507eb 100644 --- a/drivers/virtio/virtio_msg_internal.h +++ b/drivers/virtio/virtio_msg_internal.h @@ -9,6 +9,8 @@ #ifndef _DRIVERS_VIRTIO_MSG_INTERNAL_H #define _DRIVERS_VIRTIO_MSG_INTERNAL_H =20 +#include +#include #include #include =20 @@ -53,4 +55,34 @@ void virtio_msg_unregister(struct virtio_msg_device *vmd= ev); void virtio_msg_prepare(struct virtio_msg *vmsg, u8 msg_id, u16 payload_si= ze); int virtio_msg_event(struct virtio_msg_device *vmdev, struct virtio_msg *v= msg); =20 +/* Virtio msg userspace interface */ +struct virtio_msg_user_device; + +struct virtio_msg_user_ops { + int (*handle)(struct virtio_msg_user_device *vmudev, struct virtio_msg *v= msg); +}; + +/* Host side device using virtio message */ +struct virtio_msg_user_device { + struct virtio_msg_user_ops *ops; + struct miscdevice misc; + struct completion r_completion; + struct completion w_completion; + struct virtio_msg *vmsg; + struct device *parent; + char name[15]; +}; + +#if IS_REACHABLE(CONFIG_VIRTIO_MSG_USER) +int virtio_msg_user_register(struct virtio_msg_user_device *vmudev); +void virtio_msg_user_unregister(struct virtio_msg_user_device *vmudev); +#else +static inline int virtio_msg_user_register(struct virtio_msg_user_device *= vmudev) +{ + return -EOPNOTSUPP; +} + +static inline void virtio_msg_user_unregister(struct virtio_msg_user_devic= e *vmudev) {} +#endif /* CONFIG_VIRTIO_MSG_USER */ + #endif /* _DRIVERS_VIRTIO_MSG_INTERNAL_H */ diff --git a/drivers/virtio/virtio_msg_user.c b/drivers/virtio/virtio_msg_u= ser.c new file mode 100644 index 000000000000..cf7286b3a311 --- /dev/null +++ b/drivers/virtio/virtio_msg_user.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Virtio message transport user API. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + */ + +#define pr_fmt(fmt) "virtio-msg: " fmt + +#include +#include +#include +#include +#include + +#include "virtio_msg_internal.h" + +#define to_virtio_msg_user_device(_misc) \ + container_of(_misc, struct virtio_msg_user_device, misc) + +static ssize_t vmsg_miscdev_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct miscdevice *misc =3D file->private_data; + struct virtio_msg_user_device *vmudev =3D to_virtio_msg_user_device(misc); + struct device *dev =3D vmudev->parent; + int ret; + + if (count < VIRTIO_MSG_MIN_SIZE) { + dev_err(dev, "Trying to read message of incorrect size: %zu\n", + count); + return 0; + } + + /* Wait for the message */ + ret =3D wait_for_completion_interruptible(&vmudev->r_completion); + if (ret < 0) { + dev_err(dev, "Interrupted while waiting for response: %d\n", ret); + return 0; + } + + WARN_ON(!vmudev->vmsg); + + /* The "vmsg" pointer is filled by the bus driver before waking up */ + if (copy_to_user(buf, vmudev->vmsg, count) !=3D 0) + return 0; + + vmudev->vmsg =3D NULL; + + return count; +} + +static ssize_t vmsg_miscdev_write(struct file *file, const char __user *bu= f, + size_t count, loff_t *pos) +{ + struct miscdevice *misc =3D file->private_data; + struct virtio_msg_user_device *vmudev =3D to_virtio_msg_user_device(misc); + struct virtio_msg *vmsg __free(kfree) =3D NULL; + + if (count < VIRTIO_MSG_MIN_SIZE) { + dev_err(vmudev->parent, "Trying to write message of incorrect size: %zu\= n", + count); + return 0; + } + + vmsg =3D kzalloc(count, GFP_KERNEL); + if (!vmsg) + return 0; + + if (copy_from_user(vmsg, buf, count) !=3D 0) + return 0; + + vmudev->ops->handle(vmudev, vmsg); + + /* Wake up the handler only for responses */ + if (vmsg->type & VIRTIO_MSG_TYPE_RESPONSE) + complete(&vmudev->w_completion); + + return count; +} + +static const struct file_operations vmsg_miscdev_fops =3D { + .owner =3D THIS_MODULE, + .read =3D vmsg_miscdev_read, + .write =3D vmsg_miscdev_write, +}; + +/** + * virtio_msg_user_register - Register a user-space accessible virtio mess= age device + * @vmudev: Pointer to the virtio message user device + * + * Initializes and registers a user-accessible virtio message device as a = `misc` + * character device. Upon successful registration, the device appears in + * userspace as `/dev/virtio-msg-N` where `N` is a unique identifier assig= ned at + * runtime. + * + * The resulting device node allows user-space interaction with the virtio + * message transport. + * + * Return: 0 on success, or a negative error code on failure. + */ +int virtio_msg_user_register(struct virtio_msg_user_device *vmudev) +{ + static u8 vmsg_user_device_count; + int ret; + + if (!vmudev || !vmudev->ops) + return -EINVAL; + + init_completion(&vmudev->r_completion); + init_completion(&vmudev->w_completion); + + vmudev->misc.parent =3D vmudev->parent; + vmudev->misc.minor =3D MISC_DYNAMIC_MINOR; + vmudev->misc.fops =3D &vmsg_miscdev_fops; + vmudev->misc.name =3D vmudev->name; + sprintf(vmudev->name, "virtio-msg-%d", vmsg_user_device_count); + + ret =3D misc_register(&vmudev->misc); + if (ret) + return ret; + + vmsg_user_device_count++; + return 0; +} +EXPORT_SYMBOL_GPL(virtio_msg_user_register); + +/** + * virtio_msg_user_unregister - Unregister a user-space virtio message dev= ice + * @vmudev: Pointer to the virtio message user device + * + * Unregisters a previously registered virtio message device from the misc + * subsystem. This removes its user-space interface (e.g., /dev/virtio-msg= -N). + */ +void virtio_msg_user_unregister(struct virtio_msg_user_device *vmudev) +{ + misc_deregister(&vmudev->misc); +} +EXPORT_SYMBOL_GPL(virtio_msg_user_unregister); --=20 2.31.1.272.g89b43f80a514 From nobody Sun Oct 5 20:17:13 2025 Received: from mail-pj1-f41.google.com (mail-pj1-f41.google.com [209.85.216.41]) (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 F0926293B4D for ; Wed, 30 Jul 2025 09:30:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867823; cv=none; b=q/686W2FpBVkqp1mxRhNLtGfI4yTYinzD9zqBguZtfOoRwiU6BAUkQwMza3tF88GHCmJQxz8WkA9yp3ddRGB+ifMR99s1wUGVgKSifShPQoV5nKW0IJ+7med2doqFG5ENvP5A4R/hx4kc7uwaTA5Q6KP9aSjGH+yuHXOA5eJ3CE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867823; c=relaxed/simple; bh=kh8oZZLxtpKtHprLa+VlRCslzZw9tpPZ2cm6feCEKvQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=qicQTerJ0cuhFtHJsAspp3T7kCVYSAugx4radVmIbFd1c8I5NKJrRQpFLikOUnIB5ce8NTY1YHkl5zl8EjuBiih0t3oXFgMQ0tYRP/QM637sr4ZP07hK15NIFO3fJ9i8yGgK3rTSCVQlLpZLl29SpkBbyuuC2Ge2eQBmpB1c6ys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=w19YhsLy; arc=none smtp.client-ip=209.85.216.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="w19YhsLy" Received: by mail-pj1-f41.google.com with SMTP id 98e67ed59e1d1-313910f392dso5136017a91.2 for ; Wed, 30 Jul 2025 02:30:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753867820; x=1754472620; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RDdIW5aB1KFsKcGqeqlSYjq6LlhWq0LdQwZTMGlp6LY=; b=w19YhsLyh7QjnEAaOdEXD6BMm5w4tt3mZfM6fN+yr9gg/HT3vrEA6Ta1FEwPXdHvSH fO75Chc46Q/Hw4C3w3l6fjPZnPSrtVxHYM/5zubR6iKdlf+n6JRHDoiMEl1TyH0G4wmJ 3NS/1cEO0Ne23i1nYf69fFltdKQ+FqU1Y7H+J9wufDU/MUmTaBx9QJ5hWeaCjEzMFqwF GAUxs3fts2TflBkPGLSiAJ4aDAGkS0pGsTOqRCQdy5DRD7TWreras7c/5pWcchFKYvUq HDvj00YKYZVT/ufgCahT29bgLqTVrYaeZhTVqJt9eiBvzZcjCdsdS+vdBfliHRCbyXad c4cg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753867820; x=1754472620; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RDdIW5aB1KFsKcGqeqlSYjq6LlhWq0LdQwZTMGlp6LY=; b=KP8+qxen7skrZz+LBFVqnSzH9OiyHbcYAs+rOH/MS8iUQZpPlx4beiiZypxtBIwIKY obdHY4/qbB6pKYIMVgDc+cOXiXakAPL4FDDY//ZgqeJdUAKBFKAHF25VzcgFvSbN0B3E Mg2pITXurTndF1zTsY4rOK/aAV54QP4C41g9ljCI7FSv65d3dGySe93lM/aaX8/BUDA3 X/QwUmqNsTyZ1Ls/2cHkr8DPEf5bM+dQwBF6el4KvZyi5Pi+MgXepgiuF/dTXDWi8Gzg zoDAHnSo2VE8NZa/euHA4z72k0aGWNZoiKUH1v3CmZOgfWLU6dIlHKGTf43WZi/LezNo aolQ== X-Gm-Message-State: AOJu0YyJrKyxehA2de5vSIhE/Do0L8/CIO5nxSPot0ZQqyqMOgzZ1V7z HJDJ0A68wx/xcGhbGUbByWuwT9kNdGDFIv7pOWYpdwGt8fdu0G3K8E0wOoDsK0TskldWhR+yIei LVbO6 X-Gm-Gg: ASbGnctVsVTD/1yXXhLh1nG07sixW0Ryasb3km+l/ulDqNU+TutUMzdoD8szngn8FML EcrCCl6lcFIjhfhxs6MHk+DkIEyZCJ1Tky9Y093go77v+F49MXLFB/MpONER5YgkcqaTaFpedcL fWbADzqvfJK0XmozinaFXkbUsqaPKBq+aDr1CfJD61907jyUj46uUOgBAyUMhCSAhygzkQzZF3B LwfP/e/4RMZ8i2TpsBUezAowhj6wcIBE6J12+D699LVnnmG3Sls2OgVG0bQBMVznpkXeFIk2jhY focX+6Z90qUWw/CbPKd6oWvESdaTNEZ/jqfz/trsdoDkBzZyiUt/oX5g45dgDqDhwMznLqvbvLf baTehz8P3S0cYA7Cfs+QI984= X-Google-Smtp-Source: AGHT+IFQ0s2+2/egoEkMdJ3Tv9LHI5rzvo7KvcNNz9TKi4S2Jyq1GVoMeyJ7IOza8UhnllAqhv/heQ== X-Received: by 2002:a17:90b:4b83:b0:31c:3872:9411 with SMTP id 98e67ed59e1d1-31f5de63c28mr4175721a91.33.1753867819846; Wed, 30 Jul 2025 02:30:19 -0700 (PDT) Received: from localhost ([122.172.85.40]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-31f63f0b4b9sm1481141a91.27.2025.07.30.02.30.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 02:30:19 -0700 (PDT) From: Viresh Kumar To: linux-kernel@vger.kernel.org, "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?UTF-8?q?Eugenio=20P=C3=A9rez?= , Viresh Kumar Cc: Arnd Bergmann , Vincent Guittot , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Bill Mills , Rob Herring , Saravana Kannan , devicetree@vger.kernel.org, virtualization@lists.linux.dev, Sudeep Holla , Bertrand Marquis , "Edgar E . Iglesias" , Arnaud Pouliquen , Krzysztof Kozlowski , Conor Dooley Subject: [RFC PATCH 5/6] virtio-msg: Add support for FF-A (Firmware Framework for Arm) bus Date: Wed, 30 Jul 2025 14:59:34 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Introduce a virtio-msg bus implementation based on the Arm FF-A (Firmware Framework for Arm) communication interface. This bus enables virtio-msg transport over secure channels typically used between the normal world OS and a secure OS or hypervisor. It leverages the standardized FF-A interface to exchange messages with a remote backend service. The implementation integrates with the core virtio-msg transport and uses FF-A service calls to transmit and receive messages. Optionally, this bus supports attaching a reserved-memory region to constrain DMA-coherent and streaming DMA allocations to a well-defined contiguous area. This memory can be pre-mapped on the remote side, reducing runtime overhead and preventing accidental sharing of unrelated pages due to page-granularity mapping. To enable reserved memory, the following device tree node should be defined (the node must be named "vmsgffa"): reserved-memory { #address-cells =3D <2>; #size-cells =3D <2>; ranges; vmsgffa@100000000 { compatible =3D "restricted-dma-pool"; reg =3D <0x00000001 0x00000000 0x0 0x00400000>; /* 4 MiB */ }; }; Signed-off-by: Viresh Kumar --- drivers/virtio/Kconfig | 12 +- drivers/virtio/Makefile | 1 + drivers/virtio/virtio_msg_ffa.c | 505 ++++++++++++++++++++++++++++ include/uapi/linux/virtio_msg_ffa.h | 94 ++++++ 4 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 drivers/virtio/virtio_msg_ffa.c create mode 100644 include/uapi/linux/virtio_msg_ffa.h diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index a86025c9e008..683152477e3f 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -176,7 +176,8 @@ config VIRTIO_MSG select VIRTIO help This enables support for Virtio message transport. This option is - selected by any driver which implements the virtio message bus. + selected by any driver which implements the virtio message bus, such + as VIRTIO_MSG_FFA. =20 config VIRTIO_MSG_USER tristate "Userspace interface for virtio message transport" @@ -186,6 +187,15 @@ config VIRTIO_MSG_USER can be used to read / write messages over virtio-msg transport from userspace. =20 +config VIRTIO_MSG_FFA + tristate "FF-A bus driver for virtio message transport" + depends on ARM_FFA_TRANSPORT + select VIRTIO_MSG + help + This implements a Virtio message bus based on ARM FF-A protocol. + + If unsure, say N. + config VIRTIO_DMA_SHARED_BUFFER tristate depends on DMA_SHARED_BUFFER diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 5b664c5f5f25..96ec0a9c4a7a 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_VIRTIO_MMIO) +=3D virtio_mmio.o virtio_msg_transport-y :=3D virtio_msg.o virtio_msg_transport-$(CONFIG_VIRTIO_MSG_USER) +=3D virtio_msg_user.o obj-$(CONFIG_VIRTIO_MSG) +=3D virtio_msg_transport.o +obj-$(CONFIG_VIRTIO_MSG_FFA) +=3D virtio_msg_ffa.o obj-$(CONFIG_VIRTIO_PCI) +=3D virtio_pci.o virtio_pci-y :=3D virtio_pci_modern.o virtio_pci_common.o virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) +=3D virtio_pci_legacy.o diff --git a/drivers/virtio/virtio_msg_ffa.c b/drivers/virtio/virtio_msg_ff= a.c new file mode 100644 index 000000000000..e7f2cbcd238b --- /dev/null +++ b/drivers/virtio/virtio_msg_ffa.c @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * FF-A bus implementation for Virtio message transport. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + * + * This implements the FF-A (Arm Firmware Framework) bus for Virtio msg + * transport. + */ + +#define pr_fmt(fmt) "virtio-msg-ffa: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virtio_msg_internal.h" + +struct virtio_msg_indirect_data { + struct completion completion; + struct virtio_msg *response; +}; + +struct virtio_msg_device_data { + struct virtio_msg_device vmdev; + struct virtio_msg_indirect_data idata; +}; + +/* Represents FF-A corresponding to a partition */ +struct virtio_msg_ffa_device { + struct ffa_device *ffa_dev; + struct reserved_mem *rmem; + struct virtio_msg_indirect_data idata; + struct virtio_msg_device_data *vmdevs; + int (*send)(struct virtio_msg_ffa_device *vmfdev, + struct virtio_msg *request, + struct virtio_msg *response, + struct virtio_msg_indirect_data *idata); + int vmdev_count; + u16 msg_size; +}; + +#define to_vmdevdata(_vmdev) \ + container_of(_vmdev, struct virtio_msg_device_data, vmdev) +#define to_vmfdev(_vmdev) ((struct virtio_msg_ffa_device *)(_vmdev)->bus_d= ata) + +static int vmsg_ffa_send_direct(struct virtio_msg_ffa_device *vmfdev, + struct virtio_msg *request, + struct virtio_msg *response, + struct virtio_msg_indirect_data *idata_unused) +{ + struct ffa_device *ffa_dev =3D vmfdev->ffa_dev; + struct ffa_send_direct_data2 ffa_data; + int ret; + + memcpy(&ffa_data, request, request->msg_size); + + ret =3D ffa_dev->ops->msg_ops->sync_send_receive2(ffa_dev, &ffa_data); + if (ret) { + dev_dbg(&ffa_dev->dev, + "Unable to send direct FF-A message: %d\n", ret); + return ret; + } + + if (response) + memcpy(response, &ffa_data, vmfdev->msg_size); + + return 0; +} + +static int vmsg_ffa_send_indirect(struct virtio_msg_ffa_device *vmfdev, + struct virtio_msg *request, + struct virtio_msg *response, + struct virtio_msg_indirect_data *idata) +{ + struct ffa_device *ffa_dev =3D vmfdev->ffa_dev; + struct device *dev =3D &ffa_dev->dev; + int ret, count =3D 10; + + /* + * Store the response pointer in idata structure. This will be updated + * by vmsg_ffa_notifier_cb() later. + */ + idata->response =3D response; + +try_again: + ret =3D ffa_dev->ops->msg_ops->indirect_send(ffa_dev, request, + request->msg_size); + if (ret =3D=3D -EBUSY && --count) { + cpu_relax(); + goto try_again; + } + + if (ret) { + dev_err(dev, "Failed sending indirect FF-A message: %d\n", ret); + return ret; + } + + /* + * Always wait for the operation to finish, otherwise we may start + * another operation while the previous one is still ongoing. + */ + ret =3D wait_for_completion_interruptible_timeout(&idata->completion, 100= 0); + if (ret < 0) { + dev_err(dev, "Interrupted - waiting for a response: %d\n", ret); + } else if (!ret) { + dev_err(dev, "Timed out waiting for a response\n"); + ret =3D -ETIMEDOUT; + } else { + ret =3D 0; + } + + return ret; +} + +static struct virtio_msg_device * +find_vmdev(struct virtio_msg_ffa_device *vmfdev, u16 dev_id) +{ + int i; + + /* Find the device corresponding to a dev_id */ + for (i =3D 0; i < vmfdev->vmdev_count; i++) { + if (vmfdev->vmdevs[i].vmdev.dev_id =3D=3D dev_id) + return &vmfdev->vmdevs[i].vmdev; + } + + dev_err(&vmfdev->ffa_dev->dev, "Couldn't find matching vmdev: %d\n", + dev_id); + return NULL; +} + +static void vmsg_ffa_notifier_cb(int notify_id, void *cb_data, void *buf) +{ + struct virtio_msg_ffa_device *vmfdev =3D cb_data; + struct ffa_device *ffa_dev =3D vmfdev->ffa_dev; + struct virtio_msg_indirect_data *idata; + struct virtio_msg_device *vmdev; + struct virtio_msg *vmsg =3D buf; + + /* + * We can either receive a response message (to a previously sent + * request), or an EVENT_USED request message. + */ + if (vmsg->type & VIRTIO_MSG_TYPE_RESPONSE) { + if (vmsg->type & VIRTIO_MSG_TYPE_BUS) { + idata =3D &vmfdev->idata; + } else { + vmdev =3D find_vmdev(vmfdev, le16_to_cpu(vmsg->dev_id)); + if (!vmdev) + return; + + idata =3D &to_vmdevdata(vmdev)->idata; + } + + if (idata->response) + memcpy(idata->response, vmsg, vmsg->msg_size); + + complete(&idata->completion); + + return; + } + + /* Only support EVENT_USED virtio request messages */ + if (vmsg->type & VIRTIO_MSG_TYPE_BUS || + vmsg->msg_id !=3D VIRTIO_MSG_EVENT_USED) { + dev_err(&ffa_dev->dev, "Unsupported message received\n"); + return; + } + + vmdev =3D find_vmdev(vmfdev, le16_to_cpu(vmsg->dev_id)); + if (!vmdev) + return; + + virtio_msg_event(vmdev, vmsg); +} + +static int vmsg_ffa_notify_setup(struct virtio_msg_ffa_device *vmfdev) +{ + struct ffa_device *ffa_dev =3D vmfdev->ffa_dev; + int ret; + + ret =3D ffa_dev->ops->notifier_ops->fwk_notify_request(ffa_dev, + &vmsg_ffa_notifier_cb, vmfdev, 0); + if (ret) + dev_err(&ffa_dev->dev, "Unable to request notifier: %d\n", ret); + + return ret; +} + +static void vmsg_ffa_notify_cleanup(struct virtio_msg_ffa_device *vmfdev) +{ + struct ffa_device *ffa_dev =3D vmfdev->ffa_dev; + int ret; + + ret =3D ffa_dev->ops->notifier_ops->fwk_notify_relinquish(ffa_dev, 0); + if (ret) + dev_err(&ffa_dev->dev, "Unable to relinquish notifier: %d\n", ret); +} + +static int vmsg_ffa_bus_get_devices(struct virtio_msg_ffa_device *vmfdev, + u16 *map, u16 *count) +{ + u8 req_buf[VIRTIO_MSG_FFA_BUS_MSG_SIZE]; + u8 res_buf[VIRTIO_MSG_FFA_BUS_MSG_SIZE]; + struct virtio_msg *request =3D (struct virtio_msg *)&req_buf; + struct virtio_msg *response =3D (struct virtio_msg *)&res_buf; + struct bus_get_devices *req_payload =3D virtio_msg_payload(request); + struct bus_get_devices_resp *res_payload =3D virtio_msg_payload(response); + int ret; + + static_assert(sizeof(*request) + sizeof(*req_payload) < + VIRTIO_MSG_FFA_BUS_MSG_SIZE); + static_assert(sizeof(*response) + sizeof(*res_payload) < + VIRTIO_MSG_FFA_BUS_MSG_SIZE); + + virtio_msg_prepare(request, VIRTIO_MSG_BUS_GET_DEVICES, + sizeof(*req_payload)); + req_payload->offset =3D 0; + req_payload->num =3D cpu_to_le16(0xFF); + + ret =3D vmfdev->send(vmfdev, request, response, &vmfdev->idata); + if (ret < 0) + return ret; + + *count =3D le16_to_cpu(res_payload->num); + if (!*count) + return -ENODEV; + + if (res_payload->offset !=3D req_payload->offset) + return -EINVAL; + + /* Support up to 16 devices for now */ + if (res_payload->next_offset) + return -EINVAL; + + map[0] =3D res_payload->devices[0]; + map[1] =3D res_payload->devices[1]; + + return 0; +} + +static int vmsg_ffa_bus_version(struct virtio_msg_ffa_device *vmfdev) +{ + u8 req_buf[VIRTIO_MSG_FFA_BUS_MSG_SIZE]; + u8 res_buf[VIRTIO_MSG_FFA_BUS_MSG_SIZE]; + struct virtio_msg *request =3D (struct virtio_msg *)&req_buf; + struct virtio_msg *response =3D (struct virtio_msg *)&res_buf; + struct bus_ffa_version *req_payload =3D virtio_msg_payload(request); + struct bus_ffa_version_resp *res_payload =3D virtio_msg_payload(response); + u32 features; + int ret; + + static_assert(sizeof(*request) + sizeof(*req_payload) < + VIRTIO_MSG_FFA_BUS_MSG_SIZE); + static_assert(sizeof(*response) + sizeof(*res_payload) < + VIRTIO_MSG_FFA_BUS_MSG_SIZE); + + virtio_msg_prepare(request, VIRTIO_MSG_FFA_BUS_VERSION, + sizeof(*req_payload)); + req_payload->driver_version =3D cpu_to_le32(VIRTIO_MSG_FFA_BUS_VERSION_1_= 0); + req_payload->vmsg_revision =3D cpu_to_le32(VIRTIO_MSG_REVISION_1); + req_payload->vmsg_features =3D cpu_to_le32(VIRTIO_MSG_FEATURES); + req_payload->features =3D cpu_to_le32(VIRTIO_MSG_FFA_FEATURE_BOTH_SUPP); + req_payload->area_num =3D cpu_to_le16(VIRTIO_MSG_FFA_AREA_ID_MAX); + + ret =3D vmfdev->send(vmfdev, request, response, &vmfdev->idata); + if (ret < 0) + return ret; + + if (le32_to_cpu(res_payload->device_version) !=3D VIRTIO_MSG_FFA_BUS_VERS= ION_1_0) + return -EINVAL; + + if (le32_to_cpu(res_payload->vmsg_revision) !=3D VIRTIO_MSG_REVISION_1) + return -EINVAL; + + if (le32_to_cpu(res_payload->vmsg_features) !=3D VIRTIO_MSG_FEATURES) + return -EINVAL; + + features =3D le32_to_cpu(res_payload->features); + + /* + * - Direct message must be supported if it already worked. + * - Indirect message must be supported if it already worked + * - And direct message must not be supported since it didn't work. + */ + if ((ffa_partition_supports_direct_recv(vmfdev->ffa_dev) && + !(features & VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_RX_SUPP)) || + (ffa_partition_supports_indirect_msg(vmfdev->ffa_dev) && + !(features & VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_SUPP))) { + dev_err(&vmfdev->ffa_dev->dev, "Invalid features\n"); + return -EINVAL; + } + + return 0; +} + +static int virtio_msg_ffa_transfer(struct virtio_msg_device *vmdev, + struct virtio_msg *request, + struct virtio_msg *response) +{ + struct virtio_msg_indirect_data *idata =3D &to_vmdevdata(vmdev)->idata; + struct virtio_msg_ffa_device *vmfdev =3D to_vmfdev(vmdev); + + return vmfdev->send(vmfdev, request, response, idata); +} + +static const char *virtio_msg_ffa_bus_info(struct virtio_msg_device *vmdev, + u16 *msg_size, u32 *rev) +{ + struct virtio_msg_ffa_device *vmfdev =3D to_vmfdev(vmdev); + + *msg_size =3D vmfdev->msg_size; + *rev =3D VIRTIO_MSG_REVISION_1; + + return dev_name(&vmfdev->ffa_dev->dev); +} + +static struct virtio_msg_ops vmf_ops =3D { + .transfer =3D virtio_msg_ffa_transfer, + .bus_info =3D virtio_msg_ffa_bus_info, +}; + +static void remove_vmdevs(struct virtio_msg_ffa_device *vmfdev, int count) +{ + while (count--) + virtio_msg_unregister(&vmfdev->vmdevs[count].vmdev); +} + +static int virtio_msg_ffa_probe(struct ffa_device *ffa_dev) +{ + struct virtio_msg_ffa_device *vmfdev; + struct device *dev =3D &ffa_dev->dev; + struct virtio_msg_device *vmdev; + unsigned long devices =3D 0; + int ret, i =3D 0, bit; + u16 count; + + vmfdev =3D devm_kzalloc(dev, sizeof(*vmfdev), GFP_KERNEL); + if (!vmfdev) + return -ENOMEM; + + if (ffa_partition_supports_direct_recv(ffa_dev)) { + vmfdev->send =3D vmsg_ffa_send_direct; + } else if (ffa_partition_supports_indirect_msg(ffa_dev)) { + vmfdev->send =3D vmsg_ffa_send_indirect; + } else { + dev_err(dev, "Direct or Indirect messages not supported\n"); + return -EINVAL; + } + + vmfdev->ffa_dev =3D ffa_dev; + vmfdev->msg_size =3D VIRTIO_MSG_FFA_BUS_MSG_SIZE; + ffa_dev_set_drvdata(ffa_dev, vmfdev); + init_completion(&vmfdev->idata.completion); + + ret =3D vmsg_ffa_notify_setup(vmfdev); + if (ret) + return ret; + + ret =3D vmsg_ffa_bus_version(vmfdev); + if (ret) + goto notify_cleanup; + + ret =3D vmsg_ffa_bus_get_devices(vmfdev, (u16 *)&devices, &count); + if (ret) + goto notify_cleanup; + + ret =3D dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) + dev_warn(dev, "Failed to enable 64-bit or 32-bit DMA\n"); + + vmfdev->rmem =3D of_reserved_mem_lookup_by_name("vmsgffa"); + if (!IS_ERR(vmfdev->rmem)) { + ret =3D reserved_mem_device_init(dev, vmfdev->rmem); + if (ret) + goto rmem_free; + } else { + dev_info(dev, "Continuing without reserved-memory block\n"); + } + + vmfdev->vmdevs =3D devm_kcalloc(dev, count, sizeof(*vmfdev->vmdevs), + GFP_KERNEL); + if (!vmfdev->vmdevs) { + ret =3D -ENOMEM; + goto rmem_free; + } + vmfdev->vmdev_count =3D count; + + for_each_set_bit(bit, &devices, sizeof(devices)) { + init_completion(&vmfdev->vmdevs[i].idata.completion); + vmdev =3D &vmfdev->vmdevs[i].vmdev; + vmdev->dev_id =3D bit; + vmdev->ops =3D &vmf_ops; + vmdev->vdev.dev.parent =3D dev; + vmdev->bus_data =3D vmfdev; + + ret =3D virtio_msg_register(vmdev); + if (ret) { + dev_err(dev, "Failed to register virtio-msg device (%d)\n", ret); + goto unregister; + } + + i++; + } + + return 0; + +unregister: + remove_vmdevs(vmfdev, i); +rmem_free: + if (!IS_ERR(vmfdev->rmem)) + of_reserved_mem_device_release(dev); +notify_cleanup: + vmsg_ffa_notify_cleanup(vmfdev); + return ret; +} + +static void virtio_msg_ffa_remove(struct ffa_device *ffa_dev) +{ + struct virtio_msg_ffa_device *vmfdev =3D ffa_dev->dev.driver_data; + + remove_vmdevs(vmfdev, vmfdev->vmdev_count); + + if (!IS_ERR(vmfdev->rmem)) + of_reserved_mem_device_release(&ffa_dev->dev); + + vmsg_ffa_notify_cleanup(vmfdev); +} + +static const struct ffa_device_id virtio_msg_ffa_device_ids[] =3D { + /* c66028b5-2498-4aa1-9de7-77da6122abf0 */ + { UUID_INIT(0xc66028b5, 0x2498, 0x4aa1, + 0x9d, 0xe7, 0x77, 0xda, 0x61, 0x22, 0xab, 0xf0) }, + {} +}; + +static int __maybe_unused virtio_msg_ffa_suspend(struct device *dev) +{ + struct virtio_msg_ffa_device *vmfdev =3D dev_get_drvdata(dev); + int ret, i, index; + + for (i =3D 0; i < vmfdev->vmdev_count; i++) { + index =3D vmfdev->vmdev_count - i - 1; + ret =3D virtio_device_freeze(&vmfdev->vmdevs[index].vmdev.vdev); + if (ret) + return ret; + } + + return 0; +} + +static int __maybe_unused virtio_msg_ffa_resume(struct device *dev) +{ + struct virtio_msg_ffa_device *vmfdev =3D dev_get_drvdata(dev); + int ret, i; + + for (i =3D 0; i < vmfdev->vmdev_count; i++) { + ret =3D virtio_device_restore(&vmfdev->vmdevs[i].vmdev.vdev); + if (ret) + return ret; + } + + return 0; +} + +static const struct dev_pm_ops virtio_msg_ffa_pm_ops =3D { + SET_SYSTEM_SLEEP_PM_OPS(virtio_msg_ffa_suspend, virtio_msg_ffa_resume) +}; + +static struct ffa_driver virtio_msg_ffa_driver =3D { + .name =3D "virtio-msg-ffa", + .probe =3D virtio_msg_ffa_probe, + .remove =3D virtio_msg_ffa_remove, + .id_table =3D virtio_msg_ffa_device_ids, + .driver =3D { + .pm =3D &virtio_msg_ffa_pm_ops, + }, +}; + +static int virtio_msg_ffa_init(void) +{ + if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT)) + return ffa_register(&virtio_msg_ffa_driver); + else + return -EOPNOTSUPP; +} +module_init(virtio_msg_ffa_init); + +static void virtio_msg_ffa_exit(void) +{ + if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT)) + ffa_unregister(&virtio_msg_ffa_driver); +} +module_exit(virtio_msg_ffa_exit); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("Virtio message FF-A bus driver"); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/virtio_msg_ffa.h b/include/uapi/linux/virti= o_msg_ffa.h new file mode 100644 index 000000000000..adcc081b483a --- /dev/null +++ b/include/uapi/linux/virtio_msg_ffa.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) */ +/* + * Virtio message FF-A (Arm Firmware Framework) bus header. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + */ + +#ifndef _LINUX_VIRTIO_MSG_FFA_H +#define _LINUX_VIRTIO_MSG_FFA_H + +#include + +/* Message types */ +#define VIRTIO_MSG_FFA_BUS_VERSION 0x80 +#define VIRTIO_MSG_FFA_BUS_AREA_SHARE 0x81 +#define VIRTIO_MSG_FFA_BUS_AREA_UNSHARE 0x82 +#define VIRTIO_MSG_FFA_BUS_RESET 0x83 +#define VIRTIO_MSG_FFA_BUS_EVENT_POLL 0x84 +#define VIRTIO_MSG_FFA_BUS_AREA_RELEASE 0xC0 + +#define VIRTIO_MSG_FEATURES 0 +#define VIRTIO_MSG_FFA_BUS_VERSION_1_0 0x1 +#define VIRTIO_MSG_FFA_BUS_MSG_SIZE VIRTIO_MSG_MIN_SIZE + +#define VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_RX_SUPP (1 << 0) +#define VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_TX_SUPP (1 << 1) +#define VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_SUPP \ + (VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_RX_SUPP | \ + VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_TX_SUPP) + +#define VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_RX_SUPP (1 << 2) +#define VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_TX_SUPP (1 << 3) +#define VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_SUPP \ + (VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_RX_SUPP | \ + VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_TX_SUPP) + +#define VIRTIO_MSG_FFA_FEATURE_BOTH_SUPP \ + (VIRTIO_MSG_FFA_FEATURE_DIRECT_MSG_SUPP | \ + VIRTIO_MSG_FFA_FEATURE_INDIRECT_MSG_SUPP) + +#define VIRTIO_MSG_FFA_AREA_ID_MAX 0xFF +#define VIRTIO_MSG_FFA_AREA_ID_OFFSET 56 +#define VIRTIO_MSG_FFA_OFFSET_MASK \ + ((ULL(1) << VIRTIO_MSG_FFA_AREA_ID_OFFSET) - 1) + +#define VIRTIO_MSG_FFA_RESULT_ERROR (1 << 0) +#define VIRTIO_MSG_FFA_RESULT_BUSY (1 << 1) + +/* Message payload format */ + +struct bus_ffa_version { + __le32 driver_version; + __le32 vmsg_revision; + __le32 vmsg_features; + __le32 features; + __le16 area_num; +} __attribute__((packed)); + +struct bus_ffa_version_resp { + __le32 device_version; + __le32 vmsg_revision; + __le32 vmsg_features; + __le32 features; + __le16 area_num; +} __attribute__((packed)); + +struct bus_area_share { + __le16 area_id; + __le64 mem_handle; + __le64 tag; + __le32 count; + __le32 attr; +} __attribute__((packed)); + +struct bus_area_share_resp { + __le16 area_id; + __le16 result; +} __attribute__((packed)); + +struct bus_area_unshare { + __le16 area_id; +} __attribute__((packed)); + +struct bus_area_unshare_resp { + __le16 area_id; + __le16 result; +} __attribute__((packed)); + +struct bus_area_release { + __le16 area_id; +} __attribute__((packed)); + +#endif /* _LINUX_VIRTIO_MSG_FFA_H */ --=20 2.31.1.272.g89b43f80a514 From nobody Sun Oct 5 20:17:13 2025 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6FBB127144C for ; Wed, 30 Jul 2025 09:30:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867827; cv=none; b=lJOsALdHOFSpYAgvD2Xs/3a1ONXqaLzt6QshhmFOYKjbegR2l/061fN6bZaLGtPaibXJa/DDzola17nkc9UmnrXq2jWoJD0kGFlOqj8iOs3M3xVgO3QNj3Uoi5x3LandNkPESzs5MRFqwmdpthaIoObGQ8BOT205UyxuUR0MjV8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753867827; c=relaxed/simple; bh=EZG5GWBuYkwXyo63tWvaS2vVdUxh8TggH36mdHovo0U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=qeyUR7rcy++T3diC+ACGe2/bU3/GbaCGNkP4jsAJAmiaxBHB1U5UwdUxs+r7oP0YjmpIC5B43gUkqnU/4OHq2OdqYbTWYYGBRcmnVz3yDNyo02elqsgEcB2cXazWMxwOYEC4tLf+tdUFaIkREFjbrxMNjJncZWZIYejHhqFCbkE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=zxvy2Zpq; arc=none smtp.client-ip=209.85.216.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="zxvy2Zpq" Received: by mail-pj1-f47.google.com with SMTP id 98e67ed59e1d1-31eb40b050bso3189145a91.0 for ; Wed, 30 Jul 2025 02:30:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753867825; x=1754472625; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+ztfLizoM6vJzWJQpk/yKuNltuSgkusaceKeZjG9ohE=; b=zxvy2ZpqBnucmNMLGSBa6OS5fGglqfJLOYItaLW1FeLRekA3fiVD/bf1HntB3YoufV cZL+EMdDvFTZhnLNH9SiF7HwZoibomtziROVLGuvFTFEevVvcWSwIk5xZ1rrAwndzZEj aaWDkI9wRtWGWu6uDcc4B+JIwH06s9nySjjnd2jM7FzyA/XxXCwpn1lsD6aDOxuAMzel NV+VzUKBfkVqGAx6f8VTsqtKmxofCCUCZqQawpJgiJiO5JfIz4Mbbm6NGG/I/cGo9zT2 k7VdXJp4pP71d7vk6ahLxzCAwlu7SMyx1PvNzxzT42nPDUQqryDkqmj9uNr7AlbDW9Uh NyeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753867825; x=1754472625; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+ztfLizoM6vJzWJQpk/yKuNltuSgkusaceKeZjG9ohE=; b=Xek8Z1hJeOzSWkUOpEnPDE8MIuvs5YDrAz91bDxXRe/QaS8F0JqMIjyc44JC9uy3Eb nqjSNUIKNY3ex7FZTdM/Xt4/5BrBG70sIdH1Lxn+HZr9NF/KJwCsTlKqODYEbyL7tEKT KrtDybjcS8qKIzx8scuZtzC7bHhTaAyDD8tr8n8or4uUmpE6fss51tUOCDZvv+a7f5cu 5K0L/mzlvySzQ1iQa4malSnrOGZQCCYbsTLfyqz50B7mMERAQDThJVaz4UgPuotQ+RJU yGYdXWA4VxZdD7Z4X3oEF/xl5KFXfm6UEzNV0yta/WlvLYIFJaOL2IZK/WtCqX9E4B3Z Agjw== X-Gm-Message-State: AOJu0Yzu3Dpzw688WNLVTb16pjfkkt1a/Z6FOPBd/9k+wqbVpkqWpgDe DobLzlVchrsoHD1xrYrzU7koLxe2QUV2Xfi1FqIPPszoUhZpWMlb5idgVR5H7dyUQ/aAyuRXSRg n0skS X-Gm-Gg: ASbGncsip2VznO3K5OQBKQnpabALHpUsstuNUpbIAj+Ny6CrQG77AVQ+1azcN5M2Ryw M5sNprSv+cWJyX4vXcwQdzuv4kuE4FKDu0FsaODQstew8bq9HRgA9eMHTHKeE9rwQJS2Dc6YD4J DAleIH5Pc6RjKl+TQs/kr7/vOSMn/OOg9uVaYP08+Y5GZv0jRh/AA6voZ8DQXEK2df3py233WTa 2AvacNHMec7OtAr2R8F52qT6tkCTAk2bM7hCEWe7g2iRKeqaO6KON9mc0KqxhIOZF304eTe5YaD mgghwyzuvY/BLECXd620EW8zmDkD92orZd4Q6GwkBeiguS9L2G8Z3Hl62xmDGJ/2so3KA35cKip Z8kQFHz57tG8SA0UP44Hm9MA= X-Google-Smtp-Source: AGHT+IFUrg1QYU7YbPaiKF9yxuBVZ4/0jL0dMyof/YqyAVSp+4ZDAcvrCV6vSNusV2vKF99MbZL+zw== X-Received: by 2002:a17:90b:3e84:b0:311:e8cc:424c with SMTP id 98e67ed59e1d1-31f5ea4c967mr3628584a91.25.1753867824670; Wed, 30 Jul 2025 02:30:24 -0700 (PDT) Received: from localhost ([122.172.85.40]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-31f63dd8c04sm1479090a91.19.2025.07.30.02.30.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 02:30:24 -0700 (PDT) From: Viresh Kumar To: linux-kernel@vger.kernel.org, "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , =?UTF-8?q?Eugenio=20P=C3=A9rez?= , Viresh Kumar Cc: Arnd Bergmann , Vincent Guittot , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Bill Mills , Rob Herring , Saravana Kannan , devicetree@vger.kernel.org, virtualization@lists.linux.dev, Sudeep Holla , Bertrand Marquis , "Edgar E . Iglesias" , Arnaud Pouliquen , Krzysztof Kozlowski , Conor Dooley Subject: [RFC PATCH 6/6] virtio-msg: Add support for loopback bus Date: Wed, 30 Jul 2025 14:59:35 +0530 Message-Id: <622460b11118be66d5ec380b3d5771be77fc1e91.1753865268.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a loopback bus implementation for the virtio-msg transport. This bus simulates a backend that echoes messages to itself, allowing testing and development of virtio-msg without requiring an actual remote backend or transport hardware. The loopback bus requires a reserved memory region for its operation. All DMA-coherent and streaming DMA allocations are restricted to this region, enabling safe mapping into user space and helping validate the memory-sharing model. The reserved-memory region must be named "vmsglb" in the device tree. Example: reserved-memory { #address-cells =3D <2>; #size-cells =3D <2>; ranges; vmsglb@100000000 { compatible =3D "restricted-dma-pool"; reg =3D <0x00000001 0x00000000 0x0 0x00400000>; /* 4 MiB */ }; }; This bus is primarily intended for functional testing, development, and validation of the virtio-msg transport and its userspace interface. Signed-off-by: Viresh Kumar --- drivers/virtio/Kconfig | 9 + drivers/virtio/Makefile | 1 + drivers/virtio/virtio_msg_loopback.c | 323 +++++++++++++++++++++++++++ include/uapi/linux/virtio_msg_lb.h | 22 ++ 4 files changed, 355 insertions(+) create mode 100644 drivers/virtio/virtio_msg_loopback.c create mode 100644 include/uapi/linux/virtio_msg_lb.h diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 683152477e3f..934e8ccb3a01 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -196,6 +196,15 @@ config VIRTIO_MSG_FFA =20 If unsure, say N. =20 +config VIRTIO_MSG_LOOPBACK + tristate "Loopback bus driver for virtio message transport" + select VIRTIO_MSG + select VIRTIO_MSG_USER + help + This implements the Loopback bus for Virtio msg transport. + + If unsure, say N. + config VIRTIO_DMA_SHARED_BUFFER tristate depends on DMA_SHARED_BUFFER diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 96ec0a9c4a7a..90a2f1d86937 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_VIRTIO_MMIO) +=3D virtio_mmio.o virtio_msg_transport-y :=3D virtio_msg.o virtio_msg_transport-$(CONFIG_VIRTIO_MSG_USER) +=3D virtio_msg_user.o obj-$(CONFIG_VIRTIO_MSG) +=3D virtio_msg_transport.o +obj-$(CONFIG_VIRTIO_MSG_LOOPBACK) +=3D virtio_msg_loopback.o obj-$(CONFIG_VIRTIO_MSG_FFA) +=3D virtio_msg_ffa.o obj-$(CONFIG_VIRTIO_PCI) +=3D virtio_pci.o virtio_pci-y :=3D virtio_pci_modern.o virtio_pci_common.o diff --git a/drivers/virtio/virtio_msg_loopback.c b/drivers/virtio/virtio_m= sg_loopback.c new file mode 100644 index 000000000000..d1d454fadc6f --- /dev/null +++ b/drivers/virtio/virtio_msg_loopback.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Loopback bus implementation for Virtio message transport. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + * + * This implements the Loopback bus for Virtio msg transport. + */ + +#define pr_fmt(fmt) "virtio-msg-loopback: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virtio_msg_internal.h" + +struct vmlb_device { + struct virtio_msg_device vmdev; + struct list_head list; +}; + +struct virtio_msg_lb { + /* Serializes transfers and protects list */ + struct mutex lock; + struct list_head list; + struct miscdevice misc; + struct virtio_msg_user_device vmudev; + struct virtio_msg *response; + struct reserved_mem *rmem; + struct device *dev; +}; + +static struct virtio_msg_lb *vmlb; + +#define to_vmlbdev(_vmdev) ((struct vmlb_device *)(_vmdev)->bus_data) + +static struct vmlb_device *find_vmlbdev(u16 dev_id) +{ + struct vmlb_device *vmlbdev; + + list_for_each_entry(vmlbdev, &vmlb->list, list) { + if (vmlbdev->vmdev.dev_id =3D=3D dev_id) + return vmlbdev; + } + + return NULL; +} + +static const char *virtio_msg_lb_bus_info(struct virtio_msg_device *vmdev, + u16 *msg_size, u32 *rev) +{ + *msg_size =3D VIRTIO_MSG_MIN_SIZE; + *rev =3D VIRTIO_MSG_REVISION_1; + + return dev_name(vmlb->dev); +} + +static int virtio_msg_lb_transfer(struct virtio_msg_device *vmdev, + struct virtio_msg *request, + struct virtio_msg *response) +{ + struct virtio_msg_user_device *vmudev =3D &vmlb->vmudev; + int ret; + + /* + * Allow only one transaction to progress at once. + */ + guard(mutex)(&vmlb->lock); + + /* + * Set `vmsg` to `request` and finish the completion to wake up the + * `read()` thread. + */ + vmudev->vmsg =3D request; + vmlb->response =3D response; + complete(&vmudev->r_completion); + + /* + * Wait here for the `write()` thread to finish and not return before + * the operation is finished to avoid any potential races. + */ + ret =3D wait_for_completion_interruptible_timeout(&vmudev->w_completion, = 1000); + if (ret < 0) { + dev_err(vmlb->dev, "Interrupted while waiting for response: %d\n", ret); + } else if (!ret) { + dev_err(vmlb->dev, "Timed out waiting for response\n"); + ret =3D -ETIMEDOUT; + } else { + ret =3D 0; + } + + /* Clear the pointers, just to be safe */ + vmudev->vmsg =3D NULL; + vmlb->response =3D NULL; + + return ret; +} + +static struct virtio_msg_ops virtio_msg_lb_ops =3D { + .transfer =3D virtio_msg_lb_transfer, + .bus_info =3D virtio_msg_lb_bus_info, +}; + +static int virtio_msg_lb_user_handle(struct virtio_msg_user_device *vmudev, + struct virtio_msg *vmsg) +{ + struct vmlb_device *vmlbdev; + + /* Response message */ + if (vmsg->type & VIRTIO_MSG_TYPE_RESPONSE) { + if (vmlb->response) + memcpy(vmlb->response, vmsg, VIRTIO_MSG_MIN_SIZE); + + return 0; + } + + /* Only support EVENT_USED virtio request messages */ + if (vmsg->type & VIRTIO_MSG_TYPE_BUS || vmsg->msg_id !=3D VIRTIO_MSG_EVEN= T_USED) { + dev_err(vmlb->dev, "Unsupported message received\n"); + return 0; + } + + vmlbdev =3D find_vmlbdev(le16_to_cpu(vmsg->dev_id)); + if (!vmlbdev) + return 0; + + virtio_msg_event(&vmlbdev->vmdev, vmsg); + return 0; +} + +static struct virtio_msg_user_ops vmlb_user_ops =3D { + .handle =3D virtio_msg_lb_user_handle, +}; + +static int vmlbdev_add(struct file *file, struct vmsg_lb_dev_info *info) +{ + struct vmlb_device *vmlbdev; + int ret; + + scoped_guard(mutex, &vmlb->lock) { + if (find_vmlbdev(info->dev_id)) + return -EEXIST; + + vmlbdev =3D kzalloc(sizeof(*vmlbdev), GFP_KERNEL); + if (!vmlbdev) + return -ENOMEM; + + vmlbdev->vmdev.dev_id =3D info->dev_id; + vmlbdev->vmdev.ops =3D &virtio_msg_lb_ops; + vmlbdev->vmdev.vdev.dev.parent =3D vmlb->dev; + vmlbdev->vmdev.bus_data =3D vmlbdev; + + list_add(&vmlbdev->list, &vmlb->list); + } + + ret =3D virtio_msg_register(&vmlbdev->vmdev); + if (ret) { + dev_err(vmlb->dev, "Failed to register virtio msg lb device (%d)\n", ret= ); + goto out; + } + + return 0; + +out: + scoped_guard(mutex, &vmlb->lock) + list_del(&vmlbdev->list); + + kfree(vmlbdev); + return ret; +} + +static int vmlbdev_remove(struct file *file, struct vmsg_lb_dev_info *info) +{ + struct vmlb_device *vmlbdev; + + scoped_guard(mutex, &vmlb->lock) { + vmlbdev =3D find_vmlbdev(info->dev_id); + if (vmlbdev) { + list_del(&vmlbdev->list); + virtio_msg_unregister(&vmlbdev->vmdev); + return 0; + } + } + + dev_err(vmlb->dev, "Failed to find virtio msg lb device.\n"); + return -ENODEV; +} + +static void vmlbdev_remove_all(void) +{ + struct vmlb_device *vmlbdev, *tvmlbdev; + + guard(mutex)(&vmlb->lock); + + list_for_each_entry_safe(vmlbdev, tvmlbdev, &vmlb->list, list) { + virtio_msg_unregister(&vmlbdev->vmdev); + list_del(&vmlbdev->list); + } +} + +static long vmlb_ioctl(struct file *file, unsigned int cmd, unsigned long = data) +{ + struct vmsg_lb_dev_info info; + + if (copy_from_user(&info, (void __user *)data, sizeof(info))) + return -EFAULT; + + switch (cmd) { + case IOCTL_VMSG_LB_ADD: + return vmlbdev_add(file, &info); + + case IOCTL_VMSG_LB_REMOVE: + return vmlbdev_remove(file, &info); + + default: + return -ENOTTY; + } +} + +static int vmlb_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long size =3D vma->vm_end - vma->vm_start; + unsigned long offset =3D vma->vm_pgoff << PAGE_SHIFT; + + if (offset > vmlb->rmem->size - size) + return -EINVAL; + + return remap_pfn_range(vma, vma->vm_start, + (vmlb->rmem->base + offset) >> PAGE_SHIFT, + size, + vma->vm_page_prot); +} + +static loff_t vmlb_llseek(struct file *file, loff_t offset, int whence) +{ + return fixed_size_llseek(file, offset, whence, vmlb->rmem->size); +} + +static const struct file_operations vmlb_miscdev_fops =3D { + .owner =3D THIS_MODULE, + .unlocked_ioctl =3D vmlb_ioctl, + .mmap =3D vmlb_mmap, + .llseek =3D vmlb_llseek, +}; + +static int virtio_msg_lb_init(void) +{ + int ret; + + vmlb =3D kzalloc(sizeof(*vmlb), GFP_KERNEL); + if (!vmlb) + return -ENOMEM; + + INIT_LIST_HEAD(&vmlb->list); + mutex_init(&vmlb->lock); + vmlb->vmudev.ops =3D &vmlb_user_ops; + + vmlb->misc.name =3D "virtio-msg-lb"; + vmlb->misc.minor =3D MISC_DYNAMIC_MINOR; + vmlb->misc.fops =3D &vmlb_miscdev_fops; + + ret =3D misc_register(&vmlb->misc); + if (ret) + goto vmlb_free; + + vmlb->dev =3D vmlb->misc.this_device; + vmlb->vmudev.parent =3D vmlb->dev; + + vmlb->rmem =3D of_reserved_mem_lookup_by_name("vmsglb"); + if (IS_ERR(vmlb->rmem)) { + ret =3D PTR_ERR(vmlb->rmem); + goto unregister; + } + ret =3D reserved_mem_device_init(vmlb->dev, vmlb->rmem); + if (ret) + goto mem_release; + + /* Register with virtio-msg UAPI */ + ret =3D virtio_msg_user_register(&vmlb->vmudev); + if (ret) { + dev_err(vmlb->dev, "Could not register virtio-msg user API\n"); + goto mem_release; + } + + ret =3D dma_coerce_mask_and_coherent(vmlb->dev, DMA_BIT_MASK(64)); + if (ret) + dev_warn(vmlb->dev, "Failed to enable 64-bit or 32-bit DMA\n"); + + return 0; + +mem_release: + of_reserved_mem_device_release(vmlb->dev); +unregister: + misc_deregister(&vmlb->misc); +vmlb_free: + kfree(vmlb); + return ret; +} +module_init(virtio_msg_lb_init); + +static void virtio_msg_lb_exit(void) +{ + virtio_msg_user_unregister(&vmlb->vmudev); + of_reserved_mem_device_release(vmlb->dev); + vmlbdev_remove_all(); + misc_deregister(&vmlb->misc); + kfree(vmlb); +} +module_exit(virtio_msg_lb_exit); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("Virtio message loopback bus driver"); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/virtio_msg_lb.h b/include/uapi/linux/virtio= _msg_lb.h new file mode 100644 index 000000000000..fe0ce6269a0a --- /dev/null +++ b/include/uapi/linux/virtio_msg_lb.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) */ +/* + * Virtio message Loopback bus header. + * + * Copyright (C) 2025 Google LLC and Linaro. + * Viresh Kumar + */ + +#ifndef _LINUX_VIRTIO_MSG_LB_H +#define _LINUX_VIRTIO_MSG_LB_H + +struct vmsg_lb_dev_info { + unsigned int dev_id; +}; + +#define IOCTL_VMSG_LB_ADD \ + _IOC(_IOC_NONE, 'P', 0, sizeof(struct vmsg_lb_dev_info)) + +#define IOCTL_VMSG_LB_REMOVE \ + _IOC(_IOC_NONE, 'P', 1, sizeof(struct vmsg_lb_dev_info)) + +#endif /* _LINUX_VIRTIO_MSG_LB_H */ --=20 2.31.1.272.g89b43f80a514