Re: [PATCH v2 4/4] Bluetooth: hci_qca: Add HCI command timeout handling

From: Marcel Holtmann
Date: Thu Dec 26 2019 - 15:30:01 EST


Hi Rocky,

> This patch adds the HCI command timeout handling, it will trigger btsoc
> to report its memory dump via vendor specific events when hit the defined
> max HCI command timeout count. After all the memory dump VSE are sent, the
> btsoc will also send a HCI_HW_ERROR event to host and this will cause a new
> hci down/up process and the btsoc will be re-initialized.
>
> Signed-off-by: Rocky Liao <rjliao@xxxxxxxxxxxxxx>
> ---
>
> Changes in v2:
> - Fix build error
>
> drivers/bluetooth/hci_qca.c | 43 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 43 insertions(+)
>
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index 7e202041ed77..34ef73daebb2 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -47,6 +47,8 @@
> #define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
> #define CMD_TRANS_TIMEOUT_MS 100
>
> +#define QCA_BTSOC_DUMP_CMD 0xFB
> +
> /* susclk rate */
> #define SUSCLK_RATE_32KHZ 32768
>
> @@ -56,6 +58,9 @@
> /* max retry count when init fails */
> #define QCA_MAX_INIT_RETRY_COUNT 3
>
> +/* when hit the max cmd time out count, trigger btsoc dump */
> +#define QCA_MAX_CMD_TIMEOUT_COUNT 3
> +
> enum qca_flags {
> QCA_IBS_ENABLED,
> QCA_DROP_VENDOR_EVENT,
> @@ -123,6 +128,8 @@ struct qca_data {
> u64 rx_votes_off;
> u64 votes_on;
> u64 votes_off;
> +
> + u32 cmd_timeout_cnt;
> };
>
> enum qca_speed_type {
> @@ -170,6 +177,7 @@ static int qca_regulator_enable(struct qca_serdev *qcadev);
> static void qca_regulator_disable(struct qca_serdev *qcadev);
> static void qca_power_shutdown(struct hci_uart *hu);
> static int qca_power_off(struct hci_dev *hdev);
> +static void qca_cmd_timeout(struct hci_dev *hdev);

I thought that I already mentioned that these forward declaration have to be removed. I have no plan to take patches that even add more forward declarations.

>
> static enum qca_btsoc_type qca_soc_type(struct hci_uart *hu)
> {
> @@ -1337,6 +1345,8 @@ static int qca_setup(struct hci_uart *hu)
> if (!ret) {
> set_bit(QCA_IBS_ENABLED, &qca->flags);
> qca_debugfs_init(hdev);
> + hdev->cmd_timeout = qca_cmd_timeout;

Why set it here? Set in the probe() callback.

> + qca->cmd_timeout_cnt = 0;

This is a race conditions if not all chip types will use NON_PERSISTENT_SETUP.

> } else if (ret == -ENOENT) {
> /* No patch/nvm-config found, run with original fw/config */
> ret = 0;
> @@ -1467,6 +1477,39 @@ static int qca_power_off(struct hci_dev *hdev)
> return 0;
> }
>
> +static int qca_send_btsoc_dump_cmd(struct hci_uart *hu)
> +{
> + int err = 0;
> + struct sk_buff *skb = NULL;
> + struct qca_data *qca = hu->priv;
> +
> + BT_DBG("hu %p sending btsoc dump command", hu);
> +
> + skb = bt_skb_alloc(1, GFP_ATOMIC);
> + if (!skb) {
> + BT_ERR("Failed to allocate memory for qca dump command");
> + return -ENOMEM;
> + }
> +
> + skb_put_u8(skb, QCA_BTSOC_DUMP_CMD);
> +
> + skb_queue_tail(&qca->txq, skb);
> +
> + return err;
> +}
> +
> +

No double empty lines.

> +static void qca_cmd_timeout(struct hci_dev *hdev)
> +{
> + struct hci_uart *hu = hci_get_drvdata(hdev);
> + struct qca_data *qca = hu->priv;
> +
> + BT_ERR("hu %p hci cmd timeout count=0x%x", hu, ++qca->cmd_timeout_cnt);
> +
> + if (qca->cmd_timeout_cnt >= QCA_MAX_CMD_TIMEOUT_COUNT)
> + qca_send_btsoc_dump_cmd(hu);
> +}
> +
> static int qca_regulator_enable(struct qca_serdev *qcadev)
> {
> struct qca_power *power = qcadev->bt_power;

Regards

Marcel