* Re: [PATCH BlueZ 1/2] avdtp: Fix GET_CONFIGURATION cmd
From: patchwork-bot+bluetooth @ 2026-06-08 18:20 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608112923.3722754-1-simon.mikuda@streamunlimited.com>
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Mon, 8 Jun 2026 13:29:22 +0200 you wrote:
> This fixes AVDTP/SNK/ACP/SIG/SMG/BV-12-C
> ---
> profiles/audio/avdtp.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
Here is the summary with links:
- [BlueZ,1/2] avdtp: Fix GET_CONFIGURATION cmd
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=60437c06560e
- [BlueZ,2/2] avdtp: Fix error handling for AVDTP_OPEN cmd
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7c1c90f7b6d0
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH BlueZ v3 1/3] device: Refactor device_discover_services function
From: patchwork-bot+bluetooth @ 2026-06-08 18:20 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608110743.3683728-1-simon.mikuda@streamunlimited.com>
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Mon, 8 Jun 2026 13:07:41 +0200 you wrote:
> After refactoring we can reuse function once more in function
> void device_bonding_complete(...)
> ---
> profiles/input/server.c | 2 +-
> src/adapter.c | 2 +-
> src/device.c | 26 ++++++++------------------
> src/device.h | 3 ++-
> 4 files changed, 12 insertions(+), 21 deletions(-)
Here is the summary with links:
- [BlueZ,v3,1/3] device: Refactor device_discover_services function
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=56835e9061de
- [BlueZ,v3,2/3] device: Rename start_discovery function
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=415955bb70ba
- [BlueZ,v3,3/3] device: Fix returning discovery error for Device.Pair
(no matching commit)
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH BlueZ] a2dp: Add codec prioritization
From: Pauli Virtanen @ 2026-06-08 15:58 UTC (permalink / raw)
To: Simon Mikuda, linux-bluetooth; +Cc: Luiz Augusto von Dentz
In-Reply-To: <20260608111658.3686364-1-simon.mikuda@streamunlimited.com>
Hi,
ma, 2026-06-08 kello 13:16 +0200, Simon Mikuda kirjoitti:
> This change will select best codec when connecting to A2DP:
> LDAC > AptX HD > AptX > AAC > SBC
Currently it's media server's job to decide what A2DP codec to use.
What they do for this sort of static ordering, is to register endpoints
in the wanted priority order, so I think another mechanism for fixed
ordering is not really needed.
What could be useful is something that allows per-device priority
selection, e.g. DBus callback that BlueZ uses to query which endpoint
to configure, before starting SelectConfiguration.
I'm not sure this is highly needed though, as iirc BlueZ remembers what
configuration was used on previous connects, and if BlueZ gets it wrong
the sound server can just reconfigure as needed at the cost of some
extra delay when connecting.
> ---
> profiles/audio/avdtp.c | 51 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 50 insertions(+), 1 deletion(-)
>
> diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
> index d475a545e..a8733a7e1 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -42,6 +42,8 @@
> #include "sink.h"
> #include "source.h"
>
> +#include "a2dp-codecs.h"
> +
> #define AVDTP_PSM 25
>
> #define MAX_SEID 0x3E
> @@ -1293,10 +1295,49 @@ static struct avdtp_stream *find_stream_by_lseid(struct avdtp *session,
> return find_stream_by_lsep(session, sep);
> }
>
> +static unsigned int get_codec_priority(
> + struct avdtp_media_codec_capability *codec_cap)
> +{
> + unsigned int priority = codec_cap->media_codec_type;
> +
> + if (codec_cap->media_codec_type == A2DP_CODEC_VENDOR) {
> + a2dp_vendor_codec_t *vendor_codec = (void *) codec_cap->data;
> +
> + switch (A2DP_GET_VENDOR_ID(*vendor_codec)) {
> + case APTX_VENDOR_ID:
> + return priority + 100;
> + case APTX_HD_VENDOR_ID:
> + return priority + 200;
> + case LDAC_VENDOR_ID:
> + return priority + 300;
> + }
> + }
> +
> + return priority;
> +}
> +
> +static int sep_codec_cmp(gconstpointer a, gconstpointer b)
> +{
> + const struct avdtp_remote_sep *sep1 = a;
> + struct avdtp_service_capability *cap1 = sep1->codec;
> + unsigned int priority1 = get_codec_priority((void *) cap1->data);
> +
> + const struct avdtp_remote_sep *sep2 = b;
> + struct avdtp_service_capability *cap2 = sep2->codec;
> + unsigned int priority2 = get_codec_priority((void *) cap2->data);
> +
> + if (priority1 < priority2)
> + return 1;
> + if (priority1 > priority2)
> + return -1;
> + return 0;
> +}
> +
> struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
> struct avdtp_local_sep *lsep)
> {
> GSList *l;
> + GSList *sorted = NULL;
>
> for (l = session->seps; l != NULL; l = g_slist_next(l)) {
> struct avdtp_remote_sep *sep = l->data;
> @@ -1325,7 +1366,15 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
> continue;
>
> if (sep->stream == NULL)
> - return sep;
> + sorted = g_slist_insert_sorted(sorted, sep,
> + sep_codec_cmp);
> + }
> +
> + if (sorted) {
> + struct avdtp_remote_sep *sep = sorted->data;
> +
> + g_slist_free(sorted);
> + return sep;
> }
>
> return NULL;
--
Pauli Virtanen
^ permalink raw reply
* RE: [BlueZ,1/2] avdtp: Add GetConfiguration DBus function
From: bluez.test.bot @ 2026-06-08 15:54 UTC (permalink / raw)
To: linux-bluetooth, simon.mikuda
In-Reply-To: <20260608121226.3727101-1-simon.mikuda@streamunlimited.com>
[-- Attachment #1: Type: text/plain, Size: 990 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1107804
---Test result---
Test Summary:
CheckPatch PASS 1.24 seconds
GitLint PASS 0.67 seconds
BuildEll PASS 21.01 seconds
BluezMake PASS 661.73 seconds
MakeCheck PASS 18.56 seconds
MakeDistcheck PASS 246.15 seconds
CheckValgrind PASS 291.39 seconds
CheckSmatch PASS 357.14 seconds
bluezmakeextell PASS 182.97 seconds
IncrementalBuild PASS 661.73 seconds
ScanBuild PASS 1030.26 seconds
https://github.com/bluez/bluez/pull/2193
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: [BlueZ,1/2] avdtp: Fix GET_CONFIGURATION cmd
From: bluez.test.bot @ 2026-06-08 15:53 UTC (permalink / raw)
To: linux-bluetooth, simon.mikuda
In-Reply-To: <20260608112923.3722754-1-simon.mikuda@streamunlimited.com>
[-- Attachment #1: Type: text/plain, Size: 989 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1107789
---Test result---
Test Summary:
CheckPatch PASS 1.03 seconds
GitLint PASS 0.65 seconds
BuildEll PASS 20.54 seconds
BluezMake PASS 664.01 seconds
MakeCheck PASS 3.51 seconds
MakeDistcheck PASS 247.31 seconds
CheckValgrind PASS 226.51 seconds
CheckSmatch PASS 353.09 seconds
bluezmakeextell PASS 182.98 seconds
IncrementalBuild PASS 664.39 seconds
ScanBuild PASS 1049.89 seconds
https://github.com/bluez/bluez/pull/2192
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: [BlueZ] gatt-client: Add PreferredNotifyType property
From: bluez.test.bot @ 2026-06-08 15:49 UTC (permalink / raw)
To: linux-bluetooth, simon.mikuda
In-Reply-To: <20260608142050.3742000-1-simon.mikuda@streamunlimited.com>
[-- Attachment #1: Type: text/plain, Size: 989 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1107894
---Test result---
Test Summary:
CheckPatch PASS 0.61 seconds
GitLint PASS 0.34 seconds
BuildEll PASS 20.15 seconds
BluezMake PASS 607.22 seconds
MakeCheck PASS 19.31 seconds
MakeDistcheck PASS 233.45 seconds
CheckValgrind PASS 272.52 seconds
CheckSmatch PASS 321.85 seconds
bluezmakeextell PASS 163.91 seconds
IncrementalBuild PASS 609.86 seconds
ScanBuild PASS 915.31 seconds
https://github.com/bluez/bluez/pull/2195
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: [BlueZ] device: Fix cache update on device remove
From: bluez.test.bot @ 2026-06-08 15:41 UTC (permalink / raw)
To: linux-bluetooth, frederic.danis
In-Reply-To: <20260608122713.72681-1-frederic.danis@collabora.com>
[-- Attachment #1: Type: text/plain, Size: 825 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1107813
---Test result---
Test Summary:
CheckPatch PASS 0.31 seconds
GitLint PASS 0.22 seconds
BuildEll PASS 17.71 seconds
BluezMake PASS 653.12 seconds
CheckSmatch PASS 313.99 seconds
bluezmakeextell PASS 166.43 seconds
IncrementalBuild PASS 616.69 seconds
ScanBuild PASS 909.63 seconds
https://github.com/bluez/bluez/pull/2194
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH BlueZ] gatt-client: Add PreferredNotifyType property
From: Luiz Augusto von Dentz @ 2026-06-08 15:21 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608142050.3742000-1-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 10:31 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> When a characteristic supports both notifications and indications the
> CCC we always register for notifications, leaving no way to choose
> indications from D-Bus.
>
> Add PreferredNotifyType (string, "notification"/"indication") to
> org.bluez.GattCharacteristic1, only present when both flags are set.
> StartNotify() and AcquireNotify() honor it on the next CCC write.
> ---
> doc/org.bluez.GattCharacteristic.rst | 21 +++++++
> src/gatt-client.c | 85 ++++++++++++++++++++++++++++
> src/shared/gatt-client.c | 31 +++++++++-
> src/shared/gatt-client.h | 3 +
> 4 files changed, 138 insertions(+), 2 deletions(-)
>
> diff --git a/doc/org.bluez.GattCharacteristic.rst b/doc/org.bluez.GattCharacteristic.rst
> index 805f39593..f7e541590 100644
> --- a/doc/org.bluez.GattCharacteristic.rst
> +++ b/doc/org.bluez.GattCharacteristic.rst
> @@ -401,3 +401,24 @@ uint16 MTU [read-only]
>
> Characteristic MTU, this is valid both for **ReadValue()** and **WriteValue()**
> but either method can use long procedures when supported.
> +
> +string PreferredNotifyType [readwrite, optional, experimental]
> +``````````````````````````````````````````````````````````````
> +
> +Selects whether **StartNotify()** and **AcquireNotify()** enable notifications
> +or indications when the characteristic supports both. Only present when both
> +"notify" and "indicate" flags are set.
> +
> +Possible values:
> +
> +:"notification":
> +
> + Enable notifications (CCC = 0x0001). Default.
> +
> +:"indication":
> +
> + Enable indications (CCC = 0x0002).
> +
> +Note: the preference applies on the next CCC write. If another client has
> +already enabled the CCC on this characteristic, the existing setting is kept
> +and the new preference takes effect only after the last subscriber stops.
Well the spec seems to have changed to allow setting both notify and
indicate simultaneously as well:
If both the Notification and Indication bits are set, then the server
shall use the notification procedure (see Section 4.10) when an
acknowledgment is not required by a higher-layer specification or
shall use the indication procedure (see Section 4.11) when an
acknowledgment is required. The server should not use both procedures
to send the same characteristic value.
So perhaps we need to handle that as well, that said I don't know if
it wouldn't be more efficient to add another method which would enable
passing the value directly rather modifying the
StartNotify/AcquireNotify behavior, but then we would need to create a
different interface name in order to break the existing methods, so
maybe going wit this is better and we just need to handle 0x0003 as
being both enabled and the server decides what to do with it.
> diff --git a/src/gatt-client.c b/src/gatt-client.c
> index 3baf95c4f..29564a87d 100644
> --- a/src/gatt-client.c
> +++ b/src/gatt-client.c
> @@ -115,6 +115,7 @@ struct characteristic {
> struct queue *descs;
>
> bool notifying;
> + bool prefer_indicate;
> struct queue *notify_clients;
> };
>
> @@ -1595,6 +1596,9 @@ static DBusMessage *characteristic_acquire_notify(DBusConnection *conn,
> if (!client)
> return btd_error_failed(msg, "Failed allocate notify session");
>
> + bt_gatt_client_set_notify_prefer_indicate(gatt, chrc->value_handle,
> + chrc->prefer_indicate);
> +
> client->notify_id = bt_gatt_client_register_notify(gatt,
> chrc->value_handle,
> register_notify_io_cb,
> @@ -1673,6 +1677,9 @@ static DBusMessage *characteristic_start_notify(DBusConnection *conn,
>
> op = async_dbus_op_new(msg, client);
>
> + bt_gatt_client_set_notify_prefer_indicate(gatt, chrc->value_handle,
> + chrc->prefer_indicate);
> +
> client->notify_id = bt_gatt_client_register_notify(gatt,
> chrc->value_handle,
> register_notify_cb, notify_cb,
> @@ -1719,6 +1726,76 @@ static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
> return dbus_message_new_method_return(msg);
> }
>
> +static gboolean
> +characteristic_get_prefer_notify_type(const GDBusPropertyTable *property,
> + DBusMessageIter *iter, void *data)
> +{
> + struct characteristic *chrc = data;
> + const char *str = chrc->prefer_indicate ? "indication" : "notification";
> +
> + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
> +
> + return TRUE;
> +}
> +
> +static void
> +characteristic_set_prefer_notify_type(const GDBusPropertyTable *property,
> + DBusMessageIter *iter,
> + GDBusPendingPropertySet id, void *data)
> +{
> + struct characteristic *chrc = data;
> + struct bt_gatt_client *gatt = chrc->service->client->gatt;
> + const char *str;
> + bool prefer;
> +
> + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
> + g_dbus_pending_property_error(id,
> + ERROR_INTERFACE ".InvalidArguments",
> + "Invalid arguments in method call");
> + return;
> + }
> +
> + dbus_message_iter_get_basic(iter, &str);
> +
> + if (!strcmp(str, "notification"))
> + prefer = false;
> + else if (!strcmp(str, "indication"))
> + prefer = true;
> + else {
> + g_dbus_pending_property_error(id,
> + ERROR_INTERFACE ".InvalidArguments",
> + "Invalid arguments in method call");
> + return;
> + }
> +
> + if (chrc->prefer_indicate == prefer) {
> + g_dbus_pending_property_success(id);
> + return;
> + }
> +
> + chrc->prefer_indicate = prefer;
> +
> + if (gatt)
> + bt_gatt_client_set_notify_prefer_indicate(gatt,
> + chrc->value_handle, prefer);
> +
> + g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
> + GATT_CHARACTERISTIC_IFACE,
> + "PreferredNotifyType");
> +
> + g_dbus_pending_property_success(id);
> +}
> +
> +static gboolean
> +characteristic_prefer_notify_type_exists(const GDBusPropertyTable *property,
> + void *data)
> +{
> + struct characteristic *chrc = data;
> +
> + return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY) &&
> + (chrc->props & BT_GATT_CHRC_PROP_INDICATE);
> +}
> +
> static const GDBusPropertyTable characteristic_properties[] = {
> { "Handle", "q", characteristic_get_handle },
> { "UUID", "s", characteristic_get_uuid, NULL, NULL },
> @@ -1733,6 +1810,10 @@ static const GDBusPropertyTable characteristic_properties[] = {
> { "NotifyAcquired", "b", characteristic_get_notify_acquired, NULL,
> characteristic_notify_acquired_exists },
> { "MTU", "q", characteristic_get_mtu, NULL, characteristic_mtu_exists },
> + { "PreferredNotifyType", "s", characteristic_get_prefer_notify_type,
> + characteristic_set_prefer_notify_type,
> + characteristic_prefer_notify_type_exists,
> + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
> { }
> };
>
> @@ -2282,6 +2363,10 @@ static void register_notify(void *data, void *user_data)
> op = new0(struct async_dbus_op, 1);
> op->data = notify_client;
>
> + bt_gatt_client_set_notify_prefer_indicate(client->gatt,
> + notify_client->chrc->value_handle,
> + notify_client->chrc->prefer_indicate);
> +
> notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
> notify_client->chrc->value_handle,
> register_notify_cb, notify_cb,
> diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
> index a6abe8ac2..403d22758 100644
> --- a/src/shared/gatt-client.c
> +++ b/src/shared/gatt-client.c
> @@ -217,6 +217,7 @@ struct notify_chrc {
> uint16_t properties;
> unsigned int notify_id;
> int notify_count; /* Reference count of registered notify callbacks */
> + bool prefer_indicate;
>
> /* Pending calls to register_notify are queued here so that they can be
> * processed after a write that modifies the CCC descriptor.
> @@ -1671,9 +1672,13 @@ static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable,
>
> if (enable) {
> /* Try to enable notifications or indications based on
> - * whatever the characteristic supports.
> + * whatever the characteristic supports. If both are
> + * available honor the per-chrc prefer_indicate flag.
> */
> - if (properties & BT_GATT_CHRC_PROP_NOTIFY)
> + if (notify_data->chrc->prefer_indicate &&
> + (properties & BT_GATT_CHRC_PROP_INDICATE))
> + value = cpu_to_le16(0x0002);
> + else if (properties & BT_GATT_CHRC_PROP_NOTIFY)
> value = cpu_to_le16(0x0001);
> else if (properties & BT_GATT_CHRC_PROP_INDICATE)
> value = cpu_to_le16(0x0002);
> @@ -3838,6 +3843,28 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
> user_data, destroy);
> }
>
> +bool bt_gatt_client_set_notify_prefer_indicate(struct bt_gatt_client *client,
> + uint16_t value_handle,
> + bool prefer)
> +{
> + struct notify_chrc *chrc;
> +
> + if (!client || !client->db || !value_handle)
> + return false;
> +
> + chrc = queue_find(client->notify_chrcs, match_notify_chrc_value_handle,
> + UINT_TO_PTR(value_handle));
> + if (!chrc) {
> + chrc = notify_chrc_create(client, value_handle);
> + if (!chrc)
> + return false;
> + }
> +
> + chrc->prefer_indicate = prefer;
> +
> + return true;
> +}
> +
> bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
> unsigned int id)
> {
> diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
> index 63cf99500..0d08f8014 100644
> --- a/src/shared/gatt-client.h
> +++ b/src/shared/gatt-client.h
> @@ -124,6 +124,9 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
> bt_gatt_client_destroy_func_t destroy);
> bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
> unsigned int id);
> +bool bt_gatt_client_set_notify_prefer_indicate(struct bt_gatt_client *client,
> + uint16_t value_handle,
> + bool prefer);
>
> bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level);
> int bt_gatt_client_get_security(struct bt_gatt_client *client);
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v2 0/7] arm64: dts: qcom: enable WiFi/BT on SM8350 HDK
From: Rob Herring @ 2026-06-08 15:18 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Konrad Dybcio, Qiang Yu,
Jeff Johnson, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
Bjorn Andersson, Konrad Dybcio, linux-arm-msm, linux-pci,
linux-kernel, linux-wireless, ath11k, devicetree,
Bartosz Golaszewski, linux-bluetooth, Bartosz Golaszewski
In-Reply-To: <20260608-sm8350-wifi-v2-0-efb68f1ff04c@oss.qualcomm.com>
On Mon, Jun 08, 2026 at 09:59:18AM +0300, Dmitry Baryshkov wrote:
> The SM8350 HDK has an onboard WCN6851 WiFi/BT chip, which for a long
> time was not supported. Bring up different pieces required to enable
> this SoC.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
> Changes in v2:
> - Bumped num_vdevs to 4 to follow other similar devices (Jeff)
> - Link to v1: https://patch.msgid.link/20260601-sm8350-wifi-v1-0-242917d88031@oss.qualcomm.com
>
> ---
> Dmitry Baryshkov (7):
> PCI: qcom: fix parsing of PERST# in the legacy case
> wifi: ath11k: enable support for WCN6851
> regulator: dt-bindings: qcom,qca6390-pmu: document WCN6851
> dt-bindings: bluetooth: qcom,wcn6855-bt: document WCN6851
> arm64: dts: qcom: sm8350: expand UART18 to 4 pins config
> arm64: dts: qcom: sm8350: modernize PCIe entries
> arm64: dts: qcom: sm8350-hdk: describe WiFi/BT chip
Before adding new devices, can you (Qcom) fix the all the existing DT
warnings related to QCom WiFi/BT:
6 (qcom,wcn6855-bt): 'vddrfa1p7-supply' is a required property
6 (qcom,wcn6855-bt): Unevaluated properties are not allowed ('vddrfa1p8-supply' was unexpected)
2 (qcom,wcn6855-bt): 'vddwlmx-supply' is a required property
2 (qcom,wcn6855-bt): 'vddwlcx-supply' is a required property
2 (qcom,wcn6855-bt): 'vddbtcmx-supply' is a required property
2 (qcom,wcn6855-bt): 'vddaon-supply' is a required property
2 (pci17cb,1103): 'vddwlmx-supply' is a required property
2 (pci17cb,1103): 'vddwlcx-supply' is a required property
2 (pci17cb,1103): 'vddrfacmn-supply' is a required property
2 (pci17cb,1103): 'vddrfa1p8-supply' is a required property
2 (pci17cb,1103): 'vddrfa1p2-supply' is a required property
2 (pci17cb,1103): 'vddrfa0p8-supply' is a required property
2 (pci17cb,1103): 'vddpcie1p8-supply' is a required property
2 (pci17cb,1103): 'vddpcie0p9-supply' is a required property
2 (pci17cb,1103): 'vddaon-supply' is a required property
Rob
^ permalink raw reply
* [bluez/bluez]
From: BluezTestBot @ 2026-06-08 14:56 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1107759
Home: https://github.com/bluez/bluez
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez]
From: BluezTestBot @ 2026-06-08 14:56 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1107770
Home: https://github.com/bluez/bluez
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] 19245b: gatt-client: Add PreferredNotifyType property
From: Šimon Mikuda @ 2026-06-08 14:55 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1107894
Home: https://github.com/bluez/bluez
Commit: 19245b27a229da41b4c5f417dc544bbf2f87b46b
https://github.com/bluez/bluez/commit/19245b27a229da41b4c5f417dc544bbf2f87b46b
Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
Date: 2026-06-08 (Mon, 08 Jun 2026)
Changed paths:
M doc/org.bluez.GattCharacteristic.rst
M src/gatt-client.c
M src/shared/gatt-client.c
M src/shared/gatt-client.h
Log Message:
-----------
gatt-client: Add PreferredNotifyType property
When a characteristic supports both notifications and indications the
CCC we always register for notifications, leaving no way to choose
indications from D-Bus.
Add PreferredNotifyType (string, "notification"/"indication") to
org.bluez.GattCharacteristic1, only present when both flags are set.
StartNotify() and AcquireNotify() honor it on the next CCC write.
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] 3c59a0: device: Fix cache update on device remove
From: fdanis-oss @ 2026-06-08 14:55 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1107813
Home: https://github.com/bluez/bluez
Commit: 3c59a00a62750b4a8c78db5334c7275c5cfa7a46
https://github.com/bluez/bluez/commit/3c59a00a62750b4a8c78db5334c7275c5cfa7a46
Author: Frédéric Danis <frederic.danis@collabora.com>
Date: 2026-06-08 (Mon, 08 Jun 2026)
Changed paths:
M src/device.c
Log Message:
-----------
device: Fix cache update on device remove
If there's no other group than the one explicitly removed the length
returned by g_key_file_to_data() will be 0 and currently nothing
will be changed in the device cache file.
If there's nothing to write, remove the device cache file.
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] f8fd83: avdtp: Add GetConfiguration DBus function
From: Šimon Mikuda @ 2026-06-08 14:55 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1107804
Home: https://github.com/bluez/bluez
Commit: f8fd83da41d0f7478ef4748b7aef68f7fab4ea60
https://github.com/bluez/bluez/commit/f8fd83da41d0f7478ef4748b7aef68f7fab4ea60
Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
Date: 2026-06-08 (Mon, 08 Jun 2026)
Changed paths:
M profiles/audio/a2dp.c
M profiles/audio/avdtp.c
M profiles/audio/avdtp.h
Log Message:
-----------
avdtp: Add GetConfiguration DBus function
Change avdtp_get_configuration to accept remote SEP instead of stream a
and add an async callback for response/reject handling; the old function
was not used anywhere (unit-test just copied signature), so it was
changed in place.
Add a GetConfiguration async D-Bus method to the remote SEP interface that
returns the retrieved configuration as a byte array.
This can be used to pass: AVDTP/SRC/INT/SIG/SMG/BV-11-C
Commit: 12ee17f9ca7eab2b4b210e7c2fc004c4e868a9bf
https://github.com/bluez/bluez/commit/12ee17f9ca7eab2b4b210e7c2fc004c4e868a9bf
Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
Date: 2026-06-08 (Mon, 08 Jun 2026)
Changed paths:
M client/player.c
M doc/bluetoothctl-endpoint.rst
M doc/org.bluez.MediaEndpoint.rst
Log Message:
-----------
client/player: Add get-config command
Compare: https://github.com/bluez/bluez/compare/f8fd83da41d0%5E...12ee17f9ca7e
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] f9278b: avdtp: Fix GET_CONFIGURATION cmd
From: Šimon Mikuda @ 2026-06-08 14:55 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1107789
Home: https://github.com/bluez/bluez
Commit: f9278b28dabae5f252432a1a1258477ac8ace703
https://github.com/bluez/bluez/commit/f9278b28dabae5f252432a1a1258477ac8ace703
Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
Date: 2026-06-08 (Mon, 08 Jun 2026)
Changed paths:
M profiles/audio/avdtp.c
Log Message:
-----------
avdtp: Fix GET_CONFIGURATION cmd
This fixes AVDTP/SNK/ACP/SIG/SMG/BV-12-C
Commit: 4db6f6a6d2440bc13d522ae3d66917d8146cc296
https://github.com/bluez/bluez/commit/4db6f6a6d2440bc13d522ae3d66917d8146cc296
Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
Date: 2026-06-08 (Mon, 08 Jun 2026)
Changed paths:
M profiles/audio/avdtp.c
Log Message:
-----------
avdtp: Fix error handling for AVDTP_OPEN cmd
We have to return BAD_STATE when local SEP is available instead of
BAD_ACP_SEID.
This fixes: AVDTP/SNK/ACP/SIG/SMG/BI-26-C
Compare: https://github.com/bluez/bluez/compare/f9278b28daba%5E...4db6f6a6d244
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* Re: [PATCH v2 1/7] PCI: qcom: fix parsing of PERST# in the legacy case
From: Bartosz Golaszewski @ 2026-06-08 14:30 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Konrad Dybcio, Qiang Yu, Jeff Johnson, Liam Girdwood, Mark Brown,
Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Bjorn Andersson, Konrad Dybcio, linux-arm-msm,
linux-pci, linux-kernel, linux-wireless, ath11k, devicetree,
Bartosz Golaszewski, linux-bluetooth
In-Reply-To: <20260608-sm8350-wifi-v2-1-efb68f1ff04c@oss.qualcomm.com>
On Mon, 8 Jun 2026 08:59:19 +0200, Dmitry Baryshkov
<dmitry.baryshkov@oss.qualcomm.com> said:
> Commit deed8aec62dc ("PCI: qcom: Handle mixed PERST#/PHY DT
> configuration") fixed support for the "mixed" platforms which declare
> PERST# pin the RC node and the PHY in the RP node, however it also broke
> support for a majority of existing platforms, which declare both PERST#
> and PHY in the RC node, because now PERST# is first acquired in
> qcom_pcie_parse_ports(), which then returns -ENODEV (as there are no
> PHYs in the RP nodes). Later qcom_pcie_parse_legacy_binding() tries to
> acquire the PERST# GPIO again and fails with -EBUSY (as the GPIO has
> already been requested).
>
> Move parsing of RC's perst-gpios to qcom_pcie_probe(), making it obvious
> that it's shared for both cases and skip parsing it in both functions.
>
> Fixes: deed8aec62dc ("PCI: qcom: Handle mixed PERST#/PHY DT configuration")
> Closes: https://lore.kernel.org/r/gieaybsg2ckxpctvqj77nlwu7utama2yeyvebkonmexsxrra3v@v3fobqasxnmy/
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH BlueZ 1/2] avdtp: Fix GET_CONFIGURATION cmd
From: Luiz Augusto von Dentz @ 2026-06-08 14:28 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608112923.3722754-1-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 7:42 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> This fixes AVDTP/SNK/ACP/SIG/SMG/BV-12-C
> ---
> profiles/audio/avdtp.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
> index d475a545e..7cfc9a80d 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -1641,7 +1641,6 @@ static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
> struct seid_req *req, int size)
> {
> GSList *l;
> - struct avdtp_local_sep *sep = NULL;
> struct avdtp_stream *stream;
> int rsp_size;
> uint8_t err;
> @@ -1656,7 +1655,7 @@ static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
> memset(buf, 0, sizeof(buf));
>
> stream = find_stream_by_lseid(session, req->acp_seid);
> - if (!sep) {
> + if (!stream) {
> err = AVDTP_BAD_ACP_SEID;
> goto failed;
> }
> --
> 2.43.0
>
Ditto, they seem valid but will probably need to update avdtp-pts.rst
as well, it can probably be a separate set of patches though.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ 2/2] avdtp: Fix error handling for AVDTP_OPEN cmd
From: Luiz Augusto von Dentz @ 2026-06-08 14:26 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608112923.3722754-2-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 7:42 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> We have to return BAD_STATE when local SEP is available instead of
> BAD_ACP_SEID.
>
> This fixes: AVDTP/SNK/ACP/SIG/SMG/BI-26-C
> ---
> profiles/audio/avdtp.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
> index 7cfc9a80d..6be6e99b4 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -1771,13 +1771,14 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
> return FALSE;
> }
>
> - stream = find_stream_by_lseid(session, req->acp_seid);
> - if (!stream) {
> + sep = find_local_sep_by_seid(session, req->acp_seid);
> + if (!sep) {
> err = AVDTP_BAD_ACP_SEID;
> goto failed;
> }
>
> - if (stream->state != AVDTP_STATE_CONFIGURED) {
> + stream = find_stream_by_lsep(session, sep);
> + if (!stream || stream->state != AVDTP_STATE_CONFIGURED) {
> err = AVDTP_BAD_STATE;
> goto failed;
> }
Looks valid but we should update avdtp-pts.rst with instructions on
how to pass AVDTP/SNK/ACP/SIG/SMG/BI-26-C then.
> @@ -1790,7 +1791,6 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
> AVDTP_OPEN, NULL, 0);
> }
>
> - sep = stream->lsep;
> if (sep->ind && sep->ind->open && !session->pending_open) {
> if (!sep->ind->open(session, sep, stream, &err,
> sep->user_data))
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ] hog: Fix starting encryption on some BLE remotes
From: Luiz Augusto von Dentz @ 2026-06-08 14:23 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608091140.3606008-1-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 5:20 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> When BLE remote doesn't reply with Insufficient Authentication Error
> encryption is not started.
>
> Good remote:
> < ACL Data TX: Handle 64 flags 0x00 dlen 7
> ATT: Read Request (0x0a) len 2
> Handle: 0x0021 Type: HID Information (0x2a4a)
> > ACL Data RX: Handle 64 flags 0x02 dlen 9
> ATT: Error Response (0x01) len 4
> Read Request (0x0a)
> Handle: 0x0000
> Error: Insufficient Authentication (0x05)
> < HCI Command: LE Start Encryption (0x08|0x0019) plen 28
> Handle: 64 Address: xx:xx:xx:xx:xx:xx (OUI xx-xx-xx)
> Random number: ...
> Encrypted diversifier: ...
> Long term key: ...
>
> Bad remote:
> < ACL Data TX: Handle 64 flags 0x00 dlen 7
> ATT: Read Request (0x0a) len 2
> Handle: 0x001e Type: HID Information (0x2a4a)
> > ACL Data RX: Handle 64 flags 0x02 dlen 9
> ATT: Read Response (0x0b) len 4
> ---
> profiles/input/hog.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/profiles/input/hog.c b/profiles/input/hog.c
> index f50a0f217..845087c9d 100644
> --- a/profiles/input/hog.c
> +++ b/profiles/input/hog.c
> @@ -189,6 +189,9 @@ static int hog_accept(struct btd_service *service)
> if (!bt_gatt_client_set_security(client,
> BT_ATT_SECURITY_MEDIUM))
> return -ECONNREFUSED;
> + } else if (auto_sec) {
> + bt_gatt_client_set_security(btd_device_get_gatt_client(device),
> + BT_ATT_SECURITY_MEDIUM);
So this forces encryption even without bonding; why?
> }
>
> /* TODO: Replace GAttrib with bt_gatt_client */
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH BlueZ] gatt-client: Add PreferredNotifyType property
From: Simon Mikuda @ 2026-06-08 14:20 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Simon Mikuda
When a characteristic supports both notifications and indications the
CCC we always register for notifications, leaving no way to choose
indications from D-Bus.
Add PreferredNotifyType (string, "notification"/"indication") to
org.bluez.GattCharacteristic1, only present when both flags are set.
StartNotify() and AcquireNotify() honor it on the next CCC write.
---
doc/org.bluez.GattCharacteristic.rst | 21 +++++++
src/gatt-client.c | 85 ++++++++++++++++++++++++++++
src/shared/gatt-client.c | 31 +++++++++-
src/shared/gatt-client.h | 3 +
4 files changed, 138 insertions(+), 2 deletions(-)
diff --git a/doc/org.bluez.GattCharacteristic.rst b/doc/org.bluez.GattCharacteristic.rst
index 805f39593..f7e541590 100644
--- a/doc/org.bluez.GattCharacteristic.rst
+++ b/doc/org.bluez.GattCharacteristic.rst
@@ -401,3 +401,24 @@ uint16 MTU [read-only]
Characteristic MTU, this is valid both for **ReadValue()** and **WriteValue()**
but either method can use long procedures when supported.
+
+string PreferredNotifyType [readwrite, optional, experimental]
+``````````````````````````````````````````````````````````````
+
+Selects whether **StartNotify()** and **AcquireNotify()** enable notifications
+or indications when the characteristic supports both. Only present when both
+"notify" and "indicate" flags are set.
+
+Possible values:
+
+:"notification":
+
+ Enable notifications (CCC = 0x0001). Default.
+
+:"indication":
+
+ Enable indications (CCC = 0x0002).
+
+Note: the preference applies on the next CCC write. If another client has
+already enabled the CCC on this characteristic, the existing setting is kept
+and the new preference takes effect only after the last subscriber stops.
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 3baf95c4f..29564a87d 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -115,6 +115,7 @@ struct characteristic {
struct queue *descs;
bool notifying;
+ bool prefer_indicate;
struct queue *notify_clients;
};
@@ -1595,6 +1596,9 @@ static DBusMessage *characteristic_acquire_notify(DBusConnection *conn,
if (!client)
return btd_error_failed(msg, "Failed allocate notify session");
+ bt_gatt_client_set_notify_prefer_indicate(gatt, chrc->value_handle,
+ chrc->prefer_indicate);
+
client->notify_id = bt_gatt_client_register_notify(gatt,
chrc->value_handle,
register_notify_io_cb,
@@ -1673,6 +1677,9 @@ static DBusMessage *characteristic_start_notify(DBusConnection *conn,
op = async_dbus_op_new(msg, client);
+ bt_gatt_client_set_notify_prefer_indicate(gatt, chrc->value_handle,
+ chrc->prefer_indicate);
+
client->notify_id = bt_gatt_client_register_notify(gatt,
chrc->value_handle,
register_notify_cb, notify_cb,
@@ -1719,6 +1726,76 @@ static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
return dbus_message_new_method_return(msg);
}
+static gboolean
+characteristic_get_prefer_notify_type(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct characteristic *chrc = data;
+ const char *str = chrc->prefer_indicate ? "indication" : "notification";
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+ return TRUE;
+}
+
+static void
+characteristic_set_prefer_notify_type(const GDBusPropertyTable *property,
+ DBusMessageIter *iter,
+ GDBusPendingPropertySet id, void *data)
+{
+ struct characteristic *chrc = data;
+ struct bt_gatt_client *gatt = chrc->service->client->gatt;
+ const char *str;
+ bool prefer;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &str);
+
+ if (!strcmp(str, "notification"))
+ prefer = false;
+ else if (!strcmp(str, "indication"))
+ prefer = true;
+ else {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ if (chrc->prefer_indicate == prefer) {
+ g_dbus_pending_property_success(id);
+ return;
+ }
+
+ chrc->prefer_indicate = prefer;
+
+ if (gatt)
+ bt_gatt_client_set_notify_prefer_indicate(gatt,
+ chrc->value_handle, prefer);
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
+ GATT_CHARACTERISTIC_IFACE,
+ "PreferredNotifyType");
+
+ g_dbus_pending_property_success(id);
+}
+
+static gboolean
+characteristic_prefer_notify_type_exists(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct characteristic *chrc = data;
+
+ return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY) &&
+ (chrc->props & BT_GATT_CHRC_PROP_INDICATE);
+}
+
static const GDBusPropertyTable characteristic_properties[] = {
{ "Handle", "q", characteristic_get_handle },
{ "UUID", "s", characteristic_get_uuid, NULL, NULL },
@@ -1733,6 +1810,10 @@ static const GDBusPropertyTable characteristic_properties[] = {
{ "NotifyAcquired", "b", characteristic_get_notify_acquired, NULL,
characteristic_notify_acquired_exists },
{ "MTU", "q", characteristic_get_mtu, NULL, characteristic_mtu_exists },
+ { "PreferredNotifyType", "s", characteristic_get_prefer_notify_type,
+ characteristic_set_prefer_notify_type,
+ characteristic_prefer_notify_type_exists,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
{ }
};
@@ -2282,6 +2363,10 @@ static void register_notify(void *data, void *user_data)
op = new0(struct async_dbus_op, 1);
op->data = notify_client;
+ bt_gatt_client_set_notify_prefer_indicate(client->gatt,
+ notify_client->chrc->value_handle,
+ notify_client->chrc->prefer_indicate);
+
notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
notify_client->chrc->value_handle,
register_notify_cb, notify_cb,
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index a6abe8ac2..403d22758 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -217,6 +217,7 @@ struct notify_chrc {
uint16_t properties;
unsigned int notify_id;
int notify_count; /* Reference count of registered notify callbacks */
+ bool prefer_indicate;
/* Pending calls to register_notify are queued here so that they can be
* processed after a write that modifies the CCC descriptor.
@@ -1671,9 +1672,13 @@ static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable,
if (enable) {
/* Try to enable notifications or indications based on
- * whatever the characteristic supports.
+ * whatever the characteristic supports. If both are
+ * available honor the per-chrc prefer_indicate flag.
*/
- if (properties & BT_GATT_CHRC_PROP_NOTIFY)
+ if (notify_data->chrc->prefer_indicate &&
+ (properties & BT_GATT_CHRC_PROP_INDICATE))
+ value = cpu_to_le16(0x0002);
+ else if (properties & BT_GATT_CHRC_PROP_NOTIFY)
value = cpu_to_le16(0x0001);
else if (properties & BT_GATT_CHRC_PROP_INDICATE)
value = cpu_to_le16(0x0002);
@@ -3838,6 +3843,28 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
user_data, destroy);
}
+bool bt_gatt_client_set_notify_prefer_indicate(struct bt_gatt_client *client,
+ uint16_t value_handle,
+ bool prefer)
+{
+ struct notify_chrc *chrc;
+
+ if (!client || !client->db || !value_handle)
+ return false;
+
+ chrc = queue_find(client->notify_chrcs, match_notify_chrc_value_handle,
+ UINT_TO_PTR(value_handle));
+ if (!chrc) {
+ chrc = notify_chrc_create(client, value_handle);
+ if (!chrc)
+ return false;
+ }
+
+ chrc->prefer_indicate = prefer;
+
+ return true;
+}
+
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
unsigned int id)
{
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 63cf99500..0d08f8014 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -124,6 +124,9 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
bt_gatt_client_destroy_func_t destroy);
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
unsigned int id);
+bool bt_gatt_client_set_notify_prefer_indicate(struct bt_gatt_client *client,
+ uint16_t value_handle,
+ bool prefer);
bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level);
int bt_gatt_client_get_security(struct bt_gatt_client *client);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH BlueZ 1/2] avdtp: Add GetConfiguration DBus function
From: Luiz Augusto von Dentz @ 2026-06-08 13:59 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608121226.3727101-1-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 8:15 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> Change avdtp_get_configuration to accept remote SEP instead of stream a
> and add an async callback for response/reject handling; the old function
> was not used anywhere (unit-test just copied signature), so it was
> changed in place.
>
> Add a GetConfiguration async D-Bus method to the remote SEP interface that
> returns the retrieved configuration as a byte array.
>
> This can be used to pass: AVDTP/SRC/INT/SIG/SMG/BV-11-C
> ---
> profiles/audio/a2dp.c | 63 ++++++++++++++++++++++++++++++++++
> profiles/audio/avdtp.c | 76 ++++++++++++++++++++++++++++++++++++++++--
> profiles/audio/avdtp.h | 9 ++++-
> 3 files changed, 144 insertions(+), 4 deletions(-)
>
> diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
> index c7e0fc75c..8dcf510ca 100644
> --- a/profiles/audio/a2dp.c
> +++ b/profiles/audio/a2dp.c
> @@ -2168,11 +2168,74 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
> return NULL;
> }
>
> +static void get_configuration_cb(struct avdtp *session, GSList *caps,
> + struct avdtp_error *err, void *user_data)
> +{
> + DBusMessage *msg = user_data;
> + DBusMessage *reply;
> + DBusMessageIter iter, array;
> + GSList *l;
> +
> + if (err) {
> + reply = btd_error_failed(msg, "GetConfiguration rejected");
> + goto done;
> + }
> +
> + reply = dbus_message_new_method_return(msg);
> +
> + dbus_message_iter_init_append(reply, &iter);
> + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> + DBUS_TYPE_BYTE_AS_STRING, &array);
> +
> + for (l = caps; l; l = g_slist_next(l)) {
> + struct avdtp_service_capability *cap = l->data;
> + uint8_t *ptr = (uint8_t *) cap;
> + int i;
> +
> + for (i = 0; i < cap->length + 2; i++)
> + dbus_message_iter_append_basic(&array,
> + DBUS_TYPE_BYTE,
> + &ptr[i]);
> + }
> +
> + dbus_message_iter_close_container(&iter, &array);
> +
> +done:
> + g_dbus_send_message(btd_get_dbus_connection(), reply);
> + dbus_message_unref(msg);
> + g_slist_free_full(caps, g_free);
> +}
> +
> +static DBusMessage *get_configuration(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + struct a2dp_remote_sep *rsep = data;
> + struct a2dp_channel *chan = rsep->chan;
> + int err;
> +
> + if (chan->session == NULL)
> + return btd_error_not_available(msg);
> +
> + err = avdtp_get_configuration(chan->session, rsep->sep,
> + get_configuration_cb,
> + dbus_message_ref(msg));
> + if (err < 0) {
> + dbus_message_unref(msg);
> + return btd_error_failed(msg, strerror(-err));
> + }
> +
> + return NULL;
> +}
> +
> static const GDBusMethodTable sep_methods[] = {
> { GDBUS_ASYNC_METHOD("SetConfiguration",
> GDBUS_ARGS({ "endpoint", "o" },
> { "properties", "a{sv}" } ),
> NULL, set_configuration) },
> + { GDBUS_ASYNC_METHOD("GetConfiguration",
> + NULL,
> + GDBUS_ARGS({ "configuration", "ay" }),
> + get_configuration) },
The configuration is already exposed via MediaTransport properties:
https://github.com/bluez/bluez/blob/master/doc/org.bluez.MediaTransport.rst#arraybyte-configuration-readonly
So if this is only to satisfy PTS, maybe it should be hidden behind
main.conf:Testing, that said we do have a dedicated tool for passing
PTS testing, avdtptest, and if you had grepped for
AVDTP/SRC/INT/SIG/SMG/BV-11-C you would have found it is documented in
avdtp-pts.rst:
https://github.com/bluez/bluez/blob/7a0c8ebf91e69c3b2d2d48f8f4b0074fddde1fa4/doc/qualification/avdtp-pts.rst#L258
> { },
> };
>
> diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
> index d475a545e..5f0424c81 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -348,6 +348,11 @@ struct discover_callback {
> void *user_data;
> };
>
> +struct getconf_callback {
> + avdtp_get_configuration_cb_t cb;
> + void *user_data;
> +};
> +
> struct avdtp_stream {
> GIOChannel *io;
> uint16_t imtu;
> @@ -406,6 +411,7 @@ struct avdtp {
> char *buf;
>
> struct discover_callback *discover;
> + struct getconf_callback *getconf;
> struct pending_req *req;
>
> unsigned int dc_timer;
> @@ -1093,6 +1099,24 @@ static void finalize_discovery(struct avdtp *session, int err)
> session->discover = NULL;
> }
>
> +static void finalize_getconf(struct avdtp *session, int err)
> +{
> + struct getconf_callback *getconf = session->getconf;
> + struct avdtp_error avdtp_err;
> +
> + if (!getconf)
> + return;
> +
> + session->getconf = NULL;
> +
> + avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err);
> +
> + if (getconf->cb)
> + getconf->cb(session, NULL, &avdtp_err, getconf->user_data);
> +
> + g_free(getconf);
> +}
> +
> static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
> {
> struct avdtp_local_sep *sep = stream->lsep;
> @@ -1144,6 +1168,7 @@ static void avdtp_free(void *data)
> g_slist_free_full(session->seps, sep_free);
>
> g_free(session->buf);
> + g_free(session->getconf);
>
> btd_device_unref(session->device);
> g_free(session);
> @@ -1162,6 +1187,7 @@ static void connection_lost(struct avdtp *session, int err)
> session->streams = NULL;
>
> finalize_discovery(session, err);
> + finalize_getconf(session, err);
>
> avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
>
> @@ -3008,6 +3034,20 @@ static gboolean avdtp_parse_resp(struct avdtp *session,
> next->signal_id == AVDTP_GET_ALL_CAPABILITIES)))
> finalize_discovery(session, 0);
> return TRUE;
> + case AVDTP_GET_CONFIGURATION:
> + DBG("GET_CONFIGURATION request succeeded");
> + if (session->getconf) {
> + struct getconf_callback *cb = session->getconf;
> + GSList *caps;
> +
> + session->getconf = NULL;
> + caps = caps_to_list(((struct getcap_resp *) buf)->caps,
> + size - sizeof(struct getcap_resp),
> + NULL, NULL, NULL);
> + cb->cb(session, caps, NULL, cb->user_data);
> + g_free(cb);
> + }
> + return TRUE;
> }
>
> /* The remaining commands require an existing stream so bail out
> @@ -3115,6 +3155,19 @@ static gboolean avdtp_parse_rej(struct avdtp *session,
> error("GET_CAPABILITIES request rejected: %s (%d)",
> avdtp_strerror(&err), err.err.error_code);
> return TRUE;
> + case AVDTP_GET_CONFIGURATION:
> + if (!seid_rej_to_err(buf, size, &err))
> + return FALSE;
> + error("GET_CONFIGURATION request rejected: %s (%d)",
> + avdtp_strerror(&err), err.err.error_code);
> + if (session->getconf) {
> + struct getconf_callback *cb = session->getconf;
> +
> + session->getconf = NULL;
> + cb->cb(session, NULL, &err, cb->user_data);
> + g_free(cb);
> + }
> + return TRUE;
> case AVDTP_OPEN:
> if (!seid_rej_to_err(buf, size, &err))
> return FALSE;
> @@ -3536,18 +3589,35 @@ unsigned int avdtp_stream_add_cb(struct avdtp *session,
> return stream_cb->id;
> }
>
> -int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream)
> +int avdtp_get_configuration(struct avdtp *session,
> + struct avdtp_remote_sep *rsep,
> + avdtp_get_configuration_cb_t cb,
> + void *user_data)
> {
> struct seid_req req;
> + int err;
>
> if (session->state < AVDTP_SESSION_STATE_CONNECTED)
> return -EINVAL;
>
> + if (session->getconf)
> + return -EBUSY;
> +
> memset(&req, 0, sizeof(req));
> - req.acp_seid = stream->rseid;
> + req.acp_seid = rsep->seid;
>
> - return send_request(session, FALSE, stream, AVDTP_GET_CONFIGURATION,
> + err = send_request(session, FALSE, NULL, AVDTP_GET_CONFIGURATION,
> &req, sizeof(req));
> + if (err < 0)
> + return err;
> +
> + if (cb) {
> + session->getconf = g_new0(struct getconf_callback, 1);
> + session->getconf->cb = cb;
> + session->getconf->user_data = user_data;
> + }
> +
> + return 0;
> }
>
> static void copy_capabilities(gpointer data, gpointer user_data)
> diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h
> index 10c8f496b..45c54086f 100644
> --- a/profiles/audio/avdtp.h
> +++ b/profiles/audio/avdtp.h
> @@ -267,8 +267,15 @@ int avdtp_set_configuration(struct avdtp *session,
> GSList *caps,
> struct avdtp_stream **stream);
>
> +typedef void (*avdtp_get_configuration_cb_t)(struct avdtp *session,
> + GSList *caps,
> + struct avdtp_error *err,
> + void *user_data);
> +
> int avdtp_get_configuration(struct avdtp *session,
> - struct avdtp_stream *stream);
> + struct avdtp_remote_sep *rsep,
> + avdtp_get_configuration_cb_t cb,
> + void *user_data);
>
> int avdtp_open(struct avdtp *session, struct avdtp_stream *stream);
> int avdtp_start(struct avdtp *session, struct avdtp_stream *stream);
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ] a2dp: Add codec prioritization
From: Luiz Augusto von Dentz @ 2026-06-08 13:48 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608111658.3686364-1-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 7:19 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> This change will select best codec when connecting to A2DP:
> LDAC > AptX HD > AptX > AAC > SBC
> ---
> profiles/audio/avdtp.c | 51 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 50 insertions(+), 1 deletion(-)
>
> diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
> index d475a545e..a8733a7e1 100644
> --- a/profiles/audio/avdtp.c
> +++ b/profiles/audio/avdtp.c
> @@ -42,6 +42,8 @@
> #include "sink.h"
> #include "source.h"
>
> +#include "a2dp-codecs.h"
> +
> #define AVDTP_PSM 25
>
> #define MAX_SEID 0x3E
> @@ -1293,10 +1295,49 @@ static struct avdtp_stream *find_stream_by_lseid(struct avdtp *session,
> return find_stream_by_lsep(session, sep);
> }
>
> +static unsigned int get_codec_priority(
> + struct avdtp_media_codec_capability *codec_cap)
> +{
> + unsigned int priority = codec_cap->media_codec_type;
> +
> + if (codec_cap->media_codec_type == A2DP_CODEC_VENDOR) {
> + a2dp_vendor_codec_t *vendor_codec = (void *) codec_cap->data;
> +
> + switch (A2DP_GET_VENDOR_ID(*vendor_codec)) {
> + case APTX_VENDOR_ID:
> + return priority + 100;
> + case APTX_HD_VENDOR_ID:
> + return priority + 200;
> + case LDAC_VENDOR_ID:
> + return priority + 300;
> + }
> + }
Nak, not going to accept fixed, made up, ranking, the ranking should
be per endpoint source by ordering from higher to lower priority.
> + return priority;
> +}
> +
> +static int sep_codec_cmp(gconstpointer a, gconstpointer b)
> +{
> + const struct avdtp_remote_sep *sep1 = a;
> + struct avdtp_service_capability *cap1 = sep1->codec;
> + unsigned int priority1 = get_codec_priority((void *) cap1->data);
> +
> + const struct avdtp_remote_sep *sep2 = b;
> + struct avdtp_service_capability *cap2 = sep2->codec;
> + unsigned int priority2 = get_codec_priority((void *) cap2->data);
> +
> + if (priority1 < priority2)
> + return 1;
> + if (priority1 > priority2)
> + return -1;
> + return 0;
> +}
> +
> struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
> struct avdtp_local_sep *lsep)
> {
> GSList *l;
> + GSList *sorted = NULL;
>
> for (l = session->seps; l != NULL; l = g_slist_next(l)) {
> struct avdtp_remote_sep *sep = l->data;
> @@ -1325,7 +1366,15 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
> continue;
>
> if (sep->stream == NULL)
> - return sep;
> + sorted = g_slist_insert_sorted(sorted, sep,
> + sep_codec_cmp);
> + }
> +
> + if (sorted) {
> + struct avdtp_remote_sep *sep = sorted->data;
> +
> + g_slist_free(sorted);
> + return sep;
> }
>
> return NULL;
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ] bap: Fix CCC value for ASE control point
From: Luiz Augusto von Dentz @ 2026-06-08 13:44 UTC (permalink / raw)
To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260608112028.3686726-1-simon.mikuda@streamunlimited.com>
Hi Simon,
On Mon, Jun 8, 2026 at 7:31 AM Simon Mikuda
<simon.mikuda@streamunlimited.com> wrote:
>
> WriteWithoutResponse was missing
> ---
> src/shared/bap.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/src/shared/bap.c b/src/shared/bap.c
> index 8fc2fb14d..968b85730 100644
> --- a/src/shared/bap.c
> +++ b/src/shared/bap.c
> @@ -3776,6 +3776,7 @@ static struct bt_ascs *ascs_new(struct gatt_db *db)
> &uuid,
> BT_ATT_PERM_WRITE,
> BT_GATT_CHRC_PROP_WRITE |
> + BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP |
> BT_GATT_CHRC_PROP_NOTIFY,
> NULL, ascs_ase_cp_write,
> ascs);
> --
> 2.43.0
>
CCCD explicitly requires ATT Write Request as per amber.bluetooth.com:
Core GATT does not allow Write Without Response for the standard
“Write Characteristic Descriptor” sub-procedure. For a CCCD write, the
defined descriptor-write procedure uses ATT_WRITE_REQ / ATT_WRITE_RSP,
not ATT_WRITE_CMD.
The exact source is Core Specification 6.3, Vol 3, Part G, Section
4.12.3. That section says Write Characteristic Descriptor uses
ATT_WRITE_REQ, and the server returns ATT_WRITE_RSP if successful. The
procedure mapping in Core Specification 6.3, Vol 3, Part G, Section
4.12 lists only these descriptor sub-procedures: Read Characteristic
Descriptor, Read Long Characteristic Descriptor, Write Characteristic
Descriptor, and Write Long Characteristic Descriptor. It does not
include a descriptor variant of Write Without Response.
Supporting mapping is also explicit in Core Specification 6.3, Vol 3,
Part G, Section 4.13:
Write Without Response maps to Characteristic Value Write
Write Characteristic Descriptor is a separate procedure
So for your original ASCS question, the answer remains:
ASE CCCD configuration is not specified as Write Without Response
The Core GATT descriptor write procedure is a write with response
A CCCD write should use ATT_WRITE_REQ, not ATT_WRITE_CMD
One subtle but important distinction: Write Without Response exists
for Characteristic Value writes under Core Specification 6.3, Vol 3,
Part G, Section 4.9.1. That does not make it a valid GATT
sub-procedure for descriptor writes such as CCCD.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-08 13:28 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <d01691b5-1651-4399-9208-b845dfeffb9c@app.fastmail.com>
Hi Luiz,
On Thu, Jun 4, 2026, at 11:52 AM, Siwei Zhang wrote:
> Hi Luiz,
>
> On Wed, Jun 3, 2026, at 2:17 PM, Luiz Augusto von Dentz wrote:
>> Hi Siwei,
>>
>> On Wed, Jun 3, 2026 at 11:09 AM Siwei Zhang <oss@fourdim.xyz> wrote:
>>>
>>> l2cap_sock_new_connection_cb() accesses l2cap_pi(sk)->chan after
>>> release_sock(parent). Once the parent lock is released, the child
>>> socket sk can be freed by another task.
>>>
>>> Allocate the channel outside the func to prevent this.
>>>
>>> Fixes: 8ffb929098a5 ("Bluetooth: Remove parent socket usage from l2cap_core.c")
>>> Cc: stable@kernel.org
>>> Assisted-by: Claude:claude-opus-4-8
>>> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
>>> ---
>>> include/net/bluetooth/l2cap.h | 10 +++--
>>> net/bluetooth/6lowpan.c | 31 +++++++------
>>> net/bluetooth/l2cap_core.c | 41 ++++++++++++-----
>>> net/bluetooth/l2cap_sock.c | 83 +++++++++++++++++++++--------------
>>> net/bluetooth/smp.c | 17 ++++---
>>> 5 files changed, 113 insertions(+), 69 deletions(-)
>>>
>>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>>> index e0a1f2293679..7f5e4647f6e0 100644
>>> --- a/include/net/bluetooth/l2cap.h
>>> +++ b/include/net/bluetooth/l2cap.h
>>> @@ -620,7 +620,9 @@ struct l2cap_chan {
>>> struct l2cap_ops {
>>> char *name;
>>>
>>> - struct l2cap_chan *(*new_connection) (struct l2cap_chan *chan);
>>> + int (*new_connection)(struct l2cap_conn *conn,
>>> + struct l2cap_chan *chan,
>>> + struct l2cap_chan *new_chan);
>>> int (*recv) (struct l2cap_chan * chan,
>>> struct sk_buff *skb);
>>> void (*teardown) (struct l2cap_chan *chan, int err);
>>> @@ -884,9 +886,11 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
>>> return (seq + 1) % (chan->tx_win_max + 1);
>>> }
>>>
>>> -static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
>>> +static inline int l2cap_chan_no_new_connection(struct l2cap_conn *conn,
>>> + struct l2cap_chan *chan,
>>> + struct l2cap_chan *new_chan)
>>> {
>>> - return NULL;
>>> + return -EOPNOTSUPP;
>>> }
>>>
>>> static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
>>> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
>>> index cb1e329d66fd..94863af97a44 100644
>>> --- a/net/bluetooth/6lowpan.c
>>> +++ b/net/bluetooth/6lowpan.c
>>> @@ -624,6 +624,15 @@ static bool is_bt_6lowpan(struct hci_conn *hcon)
>>> return true;
>>> }
>>>
>>> +static void chan_init(struct l2cap_chan *chan)
>>> +{
>>> + l2cap_chan_set_defaults(chan);
>>> +
>>> + chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
>>> + chan->mode = L2CAP_MODE_LE_FLOWCTL;
>>> + chan->imtu = 1280;
>>> +}
>>> +
>>> static struct l2cap_chan *chan_create(void)
>>> {
>>> struct l2cap_chan *chan;
>>> @@ -632,11 +641,7 @@ static struct l2cap_chan *chan_create(void)
>>> if (!chan)
>>> return NULL;
>>>
>>> - l2cap_chan_set_defaults(chan);
>>> -
>>> - chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
>>> - chan->mode = L2CAP_MODE_LE_FLOWCTL;
>>> - chan->imtu = 1280;
>>> + chan_init(chan);
>>>
>>> return chan;
>>> }
>>> @@ -745,19 +750,19 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
>>> ifup(dev->netdev);
>>> }
>>>
>>> -static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
>>> +static inline int chan_new_conn_cb(struct l2cap_conn *conn,
>>> + struct l2cap_chan *pchan,
>>> + struct l2cap_chan *chan)
>>> {
>>> - struct l2cap_chan *chan;
>>> -
>>> - chan = chan_create();
>>> - if (!chan)
>>> - return NULL;
>>> -
>>> + chan_init(chan);
>>> chan->ops = pchan->ops;
>>>
>>> + /* Take the conn list reference; see l2cap_new_connection(). */
>>> + __l2cap_chan_add(conn, chan);
>>> +
>>> BT_DBG("chan %p pchan %p", chan, pchan);
>>>
>>> - return chan;
>>> + return 0;
>>> }
>>>
>>> static void unregister_dev(struct lowpan_btle_dev *dev)
>>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>>> index c4ccfbda9d78..62acf90837fb 100644
>>> --- a/net/bluetooth/l2cap_core.c
>>> +++ b/net/bluetooth/l2cap_core.c
>>> @@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
>>> return 0;
>>> }
>>>
>>> +/* Allocate and initialise a channel for an incoming connection.
>>> + *
>>> + * ->new_connection() initialises the channel and links it into @conn with
>>> + * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
>>> + * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
>>> + * released by its teardown callback; the conn list reference is released by
>>> + * l2cap_chan_del().
>>> + */
>>> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
>>> + struct l2cap_chan *pchan)
>>> +{
>>> + struct l2cap_chan *chan;
>>> +
>>> + chan = l2cap_chan_create();
>>> + if (!chan)
>>> + return NULL;
>>> +
>>> + if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
>>> + l2cap_chan_put(chan);
>>> + return NULL;
>>> + }
>>
>> I don't quite get why we can't just place __l2cap_chan_add here
>> instead of having it called by new_connection callbacks?
>>
>
> It's specifically the l2cap_sock_new_connection_cb() case - the very
> use-after-free this patch fixes. The __l2cap_chan_add() has to happen while
> the parent lock is still held, and only the callback holds that lock.
>
> The reference counting on the new child chan starts at one ref,
> owned by the new socket:
>
> /* l2cap_new_connection() */
> chan = l2cap_chan_create(); /* refcount = 1 */
> if (!chan)
> return NULL;
>
> pchan->ops->new_connection(conn, pchan, chan);
>
> and inside the socket callback:
>
> /* l2cap_sock_new_connection_cb() */
> lock_sock(parent);
> ...
> sk = l2cap_sock_alloc(..., new_chan); /* sk owns the chan_create ref */
> ...
> l2cap_sock_init(sk, parent);
>
> __l2cap_chan_add(conn, new_chan); /* (A) conn list takes a ref */
> bt_accept_enqueue(parent, sk, false); /* (B) sk now on accept queue */
>
> release_sock(parent); /* (C) parent lock dropped */
> return 0;
>
> The moment we hit (C), sk is reachable through the parent's accept queue, so
> another task can grab and tear it down:
>
> accept() -> l2cap_sock_kill() -> l2cap_sock_put_chan()
> chan->data = NULL;
> l2cap_chan_put(chan); /* drops the sk's chan ref */
>
> If __l2cap_chan_add() at (A) hadn't already taken the conn list reference,
> that put would drop the last ref and free new_chan. Control then returns up
> to l2cap_new_connection(), which hands the now-freed chan back to
> l2cap_connect():
>
> /* l2cap_connect() - runs after the callback returns */
> chan = l2cap_new_connection(conn, pchan);
> if (!chan)
> goto response;
> ...
> bacpy(&chan->src, &conn->hcon->src); /* <-- UAF on freed chan */
> chan->psm = psm;
> chan->dcid = scid;
>
> The conn list reference taken at (A), before (C), is what keeps new_chan
> alive across the release_sock() window so l2cap_connect() can keep using it.
>
> So __l2cap_chan_add() can't move out to l2cap_new_connection(): by the time
> the callback returns, the parent lock is already dropped and chan may already
> be freed - which is exactly the race. It has to be taken inside the callback,
> under the parent lock, before the socket is exposed.
>
> The other callbacks (6lowpan, smp) have no equivalent lock-drop window.
> I kept __l2cap_chan_add() inside all of the ->new_connection() callbacks
> just to keep the "callback links the channel into conn" contract uniform.
>
Could you please check this?
Just remind you in case you miss this.
>>> +
>>> + return chan;
>>> +}
>>> +
>>> static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>>> u8 *data, u8 rsp_code)
>>> {
>>> @@ -4053,7 +4078,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>>> goto response;
>>> }
>>>
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_new_connection(conn, pchan);
>>> if (!chan)
>>> goto response;
>>>
>>> @@ -4071,8 +4096,6 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>>> chan->psm = psm;
>>> chan->dcid = scid;
>>>
>>> - __l2cap_chan_add(conn, chan);
>>> -
>>> dcid = chan->scid;
>>>
>>> __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
>>> @@ -4955,7 +4978,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>>> goto response_unlock;
>>> }
>>>
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_new_connection(conn, pchan);
>>> if (!chan) {
>>> result = L2CAP_CR_LE_NO_MEM;
>>> goto response_unlock;
>>> @@ -4970,8 +4993,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>>> chan->omtu = mtu;
>>> chan->remote_mps = mps;
>>>
>>> - __l2cap_chan_add(conn, chan);
>>> -
>>> l2cap_le_flowctl_init(chan, __le16_to_cpu(req->credits));
>>>
>>> dcid = chan->scid;
>>> @@ -5179,7 +5200,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
>>> continue;
>>> }
>>>
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_new_connection(conn, pchan);
>>> if (!chan) {
>>> result = L2CAP_CR_LE_NO_MEM;
>>> continue;
>>> @@ -5194,8 +5215,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
>>> chan->omtu = mtu;
>>> chan->remote_mps = mps;
>>>
>>> - __l2cap_chan_add(conn, chan);
>>> -
>>> l2cap_ecred_init(chan, __le16_to_cpu(req->credits));
>>>
>>> /* Init response */
>>> @@ -7470,14 +7489,12 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
>>> goto next;
>>>
>>> l2cap_chan_lock(pchan);
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_new_connection(conn, pchan);
>>> if (chan) {
>>> bacpy(&chan->src, &hcon->src);
>>> bacpy(&chan->dst, &hcon->dst);
>>> chan->src_type = bdaddr_src_type(hcon);
>>> chan->dst_type = dst_type;
>>> -
>>> - __l2cap_chan_add(conn, chan);
>>> }
>>>
>>> l2cap_chan_unlock(pchan);
>>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
>>> index 025329636353..87f4c0db5c0c 100644
>>> --- a/net/bluetooth/l2cap_sock.c
>>> +++ b/net/bluetooth/l2cap_sock.c
>>> @@ -46,7 +46,8 @@ static struct bt_sock_list l2cap_sk_list = {
>>> static const struct proto_ops l2cap_sock_ops;
>>> static void l2cap_sock_init(struct sock *sk, struct sock *parent);
>>> static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
>>> - int proto, gfp_t prio, int kern);
>>> + int proto, gfp_t prio, int kern,
>>> + struct l2cap_chan *chan);
>>> static void l2cap_sock_cleanup_listen(struct sock *parent);
>>>
>>> bool l2cap_is_socket(struct socket *sock)
>>> @@ -1287,6 +1288,23 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
>>> return err;
>>> }
>>>
>>> +/* Release the sock's ref on chan and clear the pointer so that the ref is
>>> + * dropped exactly once even if both l2cap_sock_kill() and
>>> + * l2cap_sock_destruct() run. Setting chan->data to NULL first stops any other
>>> + * task from dereferencing the now-dead sock pointer.
>>> + */
>>> +static void l2cap_sock_put_chan(struct sock *sk)
>>> +{
>>> + struct l2cap_chan *chan = l2cap_pi(sk)->chan;
>>> +
>>> + if (!chan)
>>> + return;
>>> +
>>> + chan->data = NULL;
>>> + l2cap_pi(sk)->chan = NULL;
>>> + l2cap_chan_put(chan);
>>> +}
>>> +
>>> /* Kill socket (only if zapped and orphan)
>>> * Must be called on unlocked socket, with l2cap channel lock.
>>> */
>>> @@ -1297,13 +1315,9 @@ static void l2cap_sock_kill(struct sock *sk)
>>>
>>> BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
>>>
>>> - /* Sock is dead, so set chan data to NULL, avoid other task use invalid
>>> - * sock pointer.
>>> - */
>>> - l2cap_pi(sk)->chan->data = NULL;
>>> - /* Kill poor orphan */
>>> + l2cap_sock_put_chan(sk);
>>>
>>> - l2cap_chan_put(l2cap_pi(sk)->chan);
>>> + /* Kill poor orphan */
>>> sock_set_flag(sk, SOCK_DEAD);
>>> sock_put(sk);
>>> }
>>> @@ -1546,12 +1560,14 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
>>> }
>>> }
>>>
>>> -static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
>>> +static int l2cap_sock_new_connection_cb(struct l2cap_conn *conn,
>>> + struct l2cap_chan *chan,
>>> + struct l2cap_chan *new_chan)
>>> {
>>> struct sock *sk, *parent = chan->data;
>>>
>>> if (!parent)
>>> - return NULL;
>>> + return -EINVAL;
>>>
>>> lock_sock(parent);
>>>
>>> @@ -1559,25 +1575,33 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
>>> if (sk_acceptq_is_full(parent)) {
>>> BT_DBG("backlog full %d", parent->sk_ack_backlog);
>>> release_sock(parent);
>>> - return NULL;
>>> + return -ENOBUFS;
>>> }
>>>
>>> sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
>>> - GFP_ATOMIC, 0);
>>> + GFP_ATOMIC, 0, new_chan);
>>> if (!sk) {
>>> release_sock(parent);
>>> - return NULL;
>>> - }
>>> + return -ENOMEM;
>>> + }
>>>
>>> bt_sock_reclassify_lock(sk, BTPROTO_L2CAP);
>>>
>>> l2cap_sock_init(sk, parent);
>>>
>>> + /* Link the channel into conn before exposing the new socket via the
>>> + * accept queue. Once release_sock() below drops the parent lock the
>>> + * socket may be freed by another task, dropping its reference on
>>> + * new_chan; the conn list reference taken here keeps new_chan alive so
>>> + * the caller can safely use it after ->new_connection() returns.
>>> + */
>>> + __l2cap_chan_add(conn, new_chan);
>>> +
>>> bt_accept_enqueue(parent, sk, false);
>>>
>>> release_sock(parent);
>>>
>>> - return l2cap_pi(sk)->chan;
>>> + return 0;
>>> }
>>>
>>> static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
>>> @@ -1874,10 +1898,7 @@ static void l2cap_sock_destruct(struct sock *sk)
>>>
>>> BT_DBG("sk %p", sk);
>>>
>>> - if (l2cap_pi(sk)->chan) {
>>> - l2cap_pi(sk)->chan->data = NULL;
>>> - l2cap_chan_put(l2cap_pi(sk)->chan);
>>> - }
>>> + l2cap_sock_put_chan(sk);
>>>
>>> list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
>>> kfree_skb(rx_busy->skb);
>>> @@ -1978,10 +1999,10 @@ static struct proto l2cap_proto = {
>>> };
>>>
>>> static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
>>> - int proto, gfp_t prio, int kern)
>>> + int proto, gfp_t prio, int kern,
>>> + struct l2cap_chan *chan)
>>> {
>>> struct sock *sk;
>>> - struct l2cap_chan *chan;
>>>
>>> sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
>>> if (!sk)
>>> @@ -1992,16 +2013,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
>>>
>>> INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy);
>>>
>>> - chan = l2cap_chan_create();
>>> - if (!chan) {
>>> - sk_free(sk);
>>> - if (sock)
>>> - sock->sk = NULL;
>>> - return NULL;
>>> - }
>>> -
>>> - l2cap_chan_hold(chan);
>>> -
>>> + /* The sock takes ownership of the caller's reference on chan. */
>>> l2cap_pi(sk)->chan = chan;
>>>
>>> return sk;
>>> @@ -2011,6 +2023,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
>>> int kern)
>>> {
>>> struct sock *sk;
>>> + struct l2cap_chan *chan;
>>>
>>> BT_DBG("sock %p", sock);
>>>
>>> @@ -2025,10 +2038,16 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
>>>
>>> sock->ops = &l2cap_sock_ops;
>>>
>>> - sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
>>> - if (!sk)
>>> + chan = l2cap_chan_create();
>>> + if (!chan)
>>> return -ENOMEM;
>>>
>>> + sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern, chan);
>>> + if (!sk) {
>>> + l2cap_chan_put(chan);
>>> + return -ENOMEM;
>>> + }
>>> +
>>> l2cap_sock_init(sk, NULL);
>>> bt_sock_link(&l2cap_sk_list, sk);
>>> return 0;
>>> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
>>> index 1739c1989dbd..2d31c3c7bbc0 100644
>>> --- a/net/bluetooth/smp.c
>>> +++ b/net/bluetooth/smp.c
>>> @@ -3204,16 +3204,12 @@ static const struct l2cap_ops smp_chan_ops = {
>>> .get_sndtimeo = l2cap_chan_no_get_sndtimeo,
>>> };
>>>
>>> -static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
>>> +static inline int smp_new_conn_cb(struct l2cap_conn *conn,
>>> + struct l2cap_chan *pchan,
>>> + struct l2cap_chan *chan)
>>> {
>>> - struct l2cap_chan *chan;
>>> -
>>> BT_DBG("pchan %p", pchan);
>>>
>>> - chan = l2cap_chan_create();
>>> - if (!chan)
>>> - return NULL;
>>> -
>>> chan->chan_type = pchan->chan_type;
>>> chan->ops = &smp_chan_ops;
>>> chan->scid = pchan->scid;
>>> @@ -3229,9 +3225,12 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
>>> */
>>> atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
>>>
>>> - BT_DBG("created chan %p", chan);
>>> + /* Take the conn list reference; see l2cap_new_connection(). */
>>> + __l2cap_chan_add(conn, chan);
>>>
>>> - return chan;
>>> + BT_DBG("initialised chan %p", chan);
>>> +
>>> + return 0;
>>> }
>>>
>>> static const struct l2cap_ops smp_root_chan_ops = {
>>> --
>>> 2.54.0
>>>
>>
>>
>> --
>> Luiz Augusto von Dentz
>
> Best,
> Siwei
Best,
Siwei
^ permalink raw reply
* Re: [PATCH v3 4/7] block: implement NVMEM provider
From: Loic Poulain @ 2026-06-08 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, daniel
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, Ulf Hansson,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Jens Axboe, Johannes Berg, Jeff Johnson,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Srinivas Kandagatla, Andrew Lunn,
Heiner Kallweit, Russell King, Saravana Kannan
In-Reply-To: <CAMRc=McmoWvezeH05_5AR7ZbAyg1L567HsKWbuD7711LwnjV0Q@mail.gmail.com>
On Mon, Jun 8, 2026 at 1:17 PM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Mon, 8 Jun 2026 12:50:41 +0200, Loic Poulain
> <loic.poulain@oss.qualcomm.com> said:
> > From: Daniel Golle <daniel@makrotopia.org>
> >
> > On embedded devices using an eMMC it is common that one or more partitions
> > on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
> > data. Allow referencing the partition in device tree for the kernel and
> > Wi-Fi drivers accessing it via the NVMEM layer.
> >
> > To safely defer the freeing of the provider private data until all
> > consumers have released their cells, a nvmem_dev() accessor is added to
> > the NVMEM core to expose the struct device embedded in struct nvmem_device.
> > This allows registering a devm action on the nvmem device itself, ensuring
> > the private data outlives any active cell references.
> >
> > Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> > Co-developed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > ---
> > block/Kconfig | 9 +++
> > block/Makefile | 1 +
> > block/blk-nvmem.c | 171 +++++++++++++++++++++++++++++++++++++++++
> > drivers/nvmem/core.c | 13 ++++
> > include/linux/nvmem-consumer.h | 6 ++
> > 5 files changed, 200 insertions(+)
> >
> > diff --git a/block/Kconfig b/block/Kconfig
> > index 15027963472d7b40e27b9097a5993c457b5b3054..0b33747e16dc33473683706f75c92bdf8b648f7c 100644
> > --- a/block/Kconfig
> > +++ b/block/Kconfig
> > @@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
> > by falling back to the kernel crypto API when inline
> > encryption hardware is not present.
> >
> > +config BLK_NVMEM
> > + bool "Block device NVMEM provider"
> > + depends on OF
> > + depends on NVMEM
> > + help
> > + Allow block devices (or partitions) to act as NVMEM providers,
> > + typically used with eMMC to store MAC addresses or Wi-Fi
> > + calibration data on embedded devices.
> > +
> > source "block/partitions/Kconfig"
> >
> > config BLK_PM
> > diff --git a/block/Makefile b/block/Makefile
> > index 7dce2e44276c4274c11a0a61121c83d9c43d6e0c..d7ac389e71902bc091a8800ea266190a43b3e63d 100644
> > --- a/block/Makefile
> > +++ b/block/Makefile
> > @@ -36,3 +36,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
> > blk-crypto-sysfs.o
> > obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
> > obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
> > +obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
> > diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..99c7728fb7bccdc2216780a73a89a9210f925049
> > --- /dev/null
> > +++ b/block/blk-nvmem.c
> > @@ -0,0 +1,171 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * block device NVMEM provider
> > + *
> > + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + *
> > + * Useful on devices using a partition on an eMMC for MAC addresses or
> > + * Wi-Fi calibration EEPROM data.
> > + */
> > +
> > +#include <linux/cleanup.h>
> > +#include <linux/mutex.h>
> > +#include <linux/nvmem-provider.h>
> > +#include <linux/nvmem-consumer.h>
> > +#include <linux/of.h>
> > +#include <linux/pagemap.h>
> > +#include <linux/property.h>
> > +
> > +#include "blk.h"
> > +
> > +
>
> Stray newline?
>
> > +/* List of all NVMEM devices */
> > +static LIST_HEAD(nvmem_devices);
> > +static DEFINE_MUTEX(devices_mutex);
> > +
> > +struct blk_nvmem {
> > + struct nvmem_device *nvmem;
> > + dev_t devt;
> > + struct list_head list;
> > +};
> > +
> > +static int blk_nvmem_reg_read(void *priv, unsigned int from,
> > + void *val, size_t bytes)
> > +{
> > + blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES;
> > + struct blk_nvmem *bnv = priv;
> > + size_t bytes_left = bytes;
> > + struct file *bdev_file;
> > + loff_t pos = from;
> > + int ret = 0;
> > +
> > + bdev_file = bdev_file_open_by_dev(bnv->devt, mode, priv, NULL);
> > + if (!bdev_file)
> > + return -ENODEV;
> > +
> > + if (IS_ERR(bdev_file))
> > + return PTR_ERR(bdev_file);
> > +
> > + while (bytes_left) {
> > + pgoff_t f_index = pos >> PAGE_SHIFT;
> > + struct folio *folio;
> > + size_t folio_off;
> > + size_t to_read;
> > +
> > + folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
> > + if (IS_ERR(folio)) {
> > + ret = PTR_ERR(folio);
> > + goto err_release_bdev;
> > + }
> > +
> > + folio_off = offset_in_folio(folio, pos);
> > + to_read = min(bytes_left, folio_size(folio) - folio_off);
> > + memcpy_from_folio(val, folio, folio_off, to_read);
> > + pos += to_read;
> > + bytes_left -= to_read;
> > + val += to_read;
> > + folio_put(folio);
> > + }
> > +
> > +err_release_bdev:
> > + fput(bdev_file);
>
> There's a __free() action defined in linux/file.h so you can use:
>
> struct file *bdev_file __free(fput) = ...
>
> and avoid this label.
Ok, thanks, will use.
>
> > +
> > + return ret;
> > +}
> > +
> > +static int blk_nvmem_register(struct device *dev)
> > +{
> > + struct device_node *child, *np = dev_of_node(dev);
> > + struct block_device *bdev = dev_to_bdev(dev);
> > + struct nvmem_config config = {};
> > + struct blk_nvmem *bnv;
> > +
> > + /* skip devices which do not have a device tree node */
> > + if (!np)
> > + return 0;
> > +
> > + /* skip devices without an nvmem layout defined */
> > + child = of_get_child_by_name(np, "nvmem-layout");
> > + if (!child)
> > + return 0;
> > + of_node_put(child);
>
> Same as above, can be:
>
> struct device_node *child __free(device_node) == ...
Ack.
>
> > +
> > + /*
> > + * skip block device too large to be represented as NVMEM devices,
> > + * the NVMEM reg_read callback uses an unsigned int offset
> > + */
> > + if (bdev_nr_bytes(bdev) > UINT_MAX)
> > + return -EFBIG;
>
> This will mean a failed probe. Wouldn't it be better to use -ENODEV?
That would indeed be an appropriate error.
>
> > +
> > + bnv = kzalloc_obj(*bnv);
> > + if (!bnv)
> > + return -ENOMEM;
> > +
> > + config.id = NVMEM_DEVID_NONE;
> > + config.dev = &bdev->bd_device;
> > + config.name = dev_name(&bdev->bd_device);
> > + config.owner = THIS_MODULE;
> > + config.priv = bnv;
> > + config.reg_read = blk_nvmem_reg_read;
> > + config.size = bdev_nr_bytes(bdev);
> > + config.word_size = 1;
> > + config.stride = 1;
> > + config.read_only = true;
> > + config.root_only = true;
> > + config.ignore_wp = true;
> > + config.of_node = to_of_node(dev->fwnode);
> > +
> > + bnv->devt = bdev->bd_device.devt;
> > + bnv->nvmem = nvmem_register(&config);
> > + if (IS_ERR(bnv->nvmem)) {
> > + dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
> > + "Failed to register NVMEM device\n");
> > + kfree(bnv);
> > + return PTR_ERR(bnv->nvmem);
> > + }
> > +
> > + scoped_guard(mutex, &devices_mutex)
> > + list_add_tail(&bnv->list, &nvmem_devices);
>
> I'm not sure I understand the need to store these? Whatever you need to do in
> remove() can be scheduled in a devres action here.
I think the devm_ approach would work fine in practice. The only
difference is that NVMEM unregistration would be delayed from
device_del() to device_release(), but during that window any read
attempt would simply return -ENODEV, so there is no real race or
safety concern AFAIU. I guess the explicit list was initially kept to
mirror the add_dev/remove_dev symmetry of the class interface. But,
except if there is no strong technical argument against devm_, I will
switch to that simpler approach in the next version.
Daniel, feel free to nack or ask for authorship removal if needed.
This patch submitted in your name has accumulated enough changes since
the original submission that the current shape may no longer reflect
your intent.
>
> > +
> > + return 0;
> > +}
> > +
> > +static void blk_nvmem_unregister(struct device *dev)
> > +{
> > + struct blk_nvmem *bnv_c, *bnv_t, *bnv = NULL;
> > +
> > + scoped_guard(mutex, &devices_mutex) {
> > + list_for_each_entry_safe(bnv_c, bnv_t, &nvmem_devices, list) {
> > + if (bnv_c->devt == dev_to_bdev(dev)->bd_device.devt) {
> > + bnv = bnv_c;
> > + list_del(&bnv->list);
> > + break;
> > + }
> > + }
> > +
> > + if (!bnv)
> > + return;
> > + }
> > +
> > + nvmem_unregister(bnv->nvmem);
> > + kfree(bnv);
> > +}
> > +
> > +static struct class_interface blk_nvmem_bus_interface __refdata = {
> > + .class = &block_class,
> > + .add_dev = &blk_nvmem_register,
> > + .remove_dev = &blk_nvmem_unregister,
> > +};
> > +
> > +static int __init blk_nvmem_init(void)
> > +{
> > + int ret;
> > +
> > + ret = class_interface_register(&blk_nvmem_bus_interface);
> > + if (ret)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +device_initcall(blk_nvmem_init);
> > diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> > index 311cb2e5a5c02d2c6979d7c9bbb7f94abdfbdad1..ee3481229c20b3063c86d0dd66aabbf6b5e29169 100644
> > --- a/drivers/nvmem/core.c
> > +++ b/drivers/nvmem/core.c
> > @@ -2154,6 +2154,19 @@ const char *nvmem_dev_name(struct nvmem_device *nvmem)
> > }
> > EXPORT_SYMBOL_GPL(nvmem_dev_name);
> >
> > +/**
> > + * nvmem_dev() - Get the struct device of a given nvmem device.
> > + *
> > + * @nvmem: nvmem device.
> > + *
> > + * Return: pointer to the struct device of the nvmem device.
> > + */
> > +struct device *nvmem_dev(struct nvmem_device *nvmem)
> > +{
> > + return &nvmem->dev;
> > +}
> > +EXPORT_SYMBOL_GPL(nvmem_dev);
>
> This should still be a separate patch.
Well yes, actually I should even remove this as this is no more needed.
Regards,
Loic
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox