2017-11-15 07:28:19

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 0/8] rsi: add bluetooth and coex support

From: Amitkumar Karwar <[email protected]>

This patch series adds new bluetooth driver and coex enhancments
in existing wlan driver for RSI chipsets.
As per our architecture, both wlan and bluetooth drivers talk
over same SDIO interface to device. Separate endpoint will be
used in case of USB interface.

Prameela Rani Garnepudi (6):
rsi: add rx control block to handle rx packets in USB
rsi: add header file rsi_header
rsi: add coex support
Bluetooth: btrsi: add new rsi bluetooth driver
rsi: add module parameter operating mode
rsi: sdio changes to support BT

Siva Rebbagondla (2):
rsi: add bluetooth rx endpoint
rsi: handle BT traffic in driver

drivers/bluetooth/Kconfig | 12 ++
drivers/bluetooth/Makefile | 2 +
drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++
drivers/bluetooth/rsi_hci.h | 51 ++++++
drivers/net/wireless/rsi/Makefile | 1 +
drivers/net/wireless/rsi/rsi_91x_coex.c | 184 +++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_core.c | 16 +-
drivers/net/wireless/rsi/rsi_91x_hal.c | 56 +++++-
drivers/net/wireless/rsi/rsi_91x_main.c | 127 ++++++++++++-
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 2 +-
drivers/net/wireless/rsi/rsi_91x_sdio.c | 13 +-
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 5 +-
drivers/net/wireless/rsi/rsi_91x_usb.c | 124 +++++++++----
drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 35 ++--
drivers/net/wireless/rsi/rsi_coex.h | 38 ++++
drivers/net/wireless/rsi/rsi_common.h | 5 +-
drivers/net/wireless/rsi/rsi_hal.h | 21 +++
drivers/net/wireless/rsi/rsi_main.h | 22 +--
drivers/net/wireless/rsi/rsi_mgmt.h | 3 +
drivers/net/wireless/rsi/rsi_usb.h | 16 +-
include/linux/rsi_header.h | 58 ++++++
21 files changed, 977 insertions(+), 82 deletions(-)
create mode 100644 drivers/bluetooth/btrsi.c
create mode 100644 drivers/bluetooth/rsi_hci.h
create mode 100644 drivers/net/wireless/rsi/rsi_91x_coex.c
create mode 100644 drivers/net/wireless/rsi/rsi_coex.h
create mode 100644 include/linux/rsi_header.h

--
2.7.4


2017-11-15 08:56:35

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [PATCH 7/8] rsi: add module parameter operating mode

On 11/15/2017 8:20 AM, Amitkumar Karwar wrote:
> From: Prameela Rani Garnepudi <[email protected]>
>
> Operating mode determines the support for other protocols.
> This is made as module parameter for better usage.
>
> Signed-off-by: Prameela Rani Garnepudi <[email protected]>
> Signed-off-by: Siva Rebbagondla <[email protected]>
> Signed-off-by: Amitkumar Karwar <[email protected]>
> ---

[...]

> -struct rsi_hw *rsi_91x_init(void)
> +struct rsi_hw *rsi_91x_init(u16 oper_mode)
> {
> struct rsi_hw *adapter = NULL;
> struct rsi_common *common = NULL;
> @@ -320,11 +336,34 @@ struct rsi_hw *rsi_91x_init(void)
> spin_lock_init(&adapter->ps_lock);
> timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
> init_completion(&common->wlan_init_completion);
> + common->oper_mode = oper_mode;
> common->init_done = true;
> -
> - common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
> - common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
> adapter->device_model = RSI_DEV_9113;

Seems there are definitions for coex_mode....
> +
> + /* Determine coex mode */
> + switch (common->oper_mode) {
> + case DEV_OPMODE_STA_BT_DUAL:
> + case DEV_OPMODE_STA_BT:
> + case DEV_OPMODE_STA_BT_LE:
> + case DEV_OPMODE_BT_ALONE:
> + case DEV_OPMODE_BT_LE_ALONE:
> + case DEV_OPMODE_BT_DUAL:
> + common->coex_mode = 2;

... why use magic values here ?

> + break;
> + case DEV_OPMODE_AP_BT_DUAL:
> + case DEV_OPMODE_AP_BT:
> + common->coex_mode = 4;
> + break;
> + case DEV_OPMODE_WIFI_ALONE:
> + common->coex_mode = 1;
> + break;
> + default:
> + common->oper_mode = 1;
> + common->coex_mode = 1;
> + }
> + rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
> + __func__, common->oper_mode, common->coex_mode);
> +
> if (common->coex_mode > 1) {
> if (rsi_coex_attach(common)) {
> rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
> @@ -359,10 +398,13 @@ void rsi_91x_deinit(struct rsi_hw *adapter)
> for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
> skb_queue_purge(&common->tx_queue[ii]);
>
> - common->init_done = false;
> -
> - if (common->coex_mode > 1)
> + if (common->coex_mode > 1) {
> rsi_coex_detach(common);
> + if (g_proto_ops.bt_ops->detach)
> + g_proto_ops.bt_ops->detach(common->bt_adapter);
> + }
> +
> + common->init_done = false;

Regards,
Arend

2017-11-30 14:23:15

by Amitkumar Karwar

[permalink] [raw]
Subject: Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver

On Wed, Nov 29, 2017 at 7:03 PM, Marcel Holtmann <[email protected]> wrot=
e:
> Hi Amitkumar,
>
>>>> Redpine bluetooth driver is a thin driver which depends on
>>>> 'rsi_91x' driver for transmitting and receiving packets
>>>> to/from device. It creates hci interface when attach() is
>>>> called from 'rsi_91x' module.
>>>>
>>>> Signed-off-by: Prameela Rani Garnepudi <[email protected]>
>>>> Signed-off-by: Siva Rebbagondla <[email protected]>
>>>> Signed-off-by: Amitkumar Karwar <[email protected]>
>>>> ---
>>>> drivers/bluetooth/Kconfig | 12 ++
>>>> drivers/bluetooth/Makefile | 2 +
>>>> drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++++++++++=
++++++++
>>>> drivers/bluetooth/rsi_hci.h | 51 +++++++++
>>>> 4 files changed, 333 insertions(+)
>>>> create mode 100644 drivers/bluetooth/btrsi.c
>>>> create mode 100644 drivers/bluetooth/rsi_hci.h
>>>>
>>>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>>>> index 60e1c7d..ca58d74 100644
>>>> --- a/drivers/bluetooth/Kconfig
>>>> +++ b/drivers/bluetooth/Kconfig
>>>> @@ -378,4 +378,16 @@ config BT_QCOMSMD
>>>> Say Y here to compile support for HCI over Qualcomm SMD into th=
e
>>>> kernel or say M to compile as a module.
>>>>
>>>> +config BT_RSI
>>>> + tristate "Redpine HCI support"
>>>> + depends on BT && BT_RFCOMM
>>>
>>> the depends on BT_RFCOMM is wrong. And even the depends on BT is unneed=
ed since that is already covered with the above menu clause.
>>>
>>>
>>>> + default m
>>>
>>> No. New drivers are by default off.
>>
>> We made it by default on, as RSI core module depends on this.
>>
>>>
>>>> + help
>>>> + Redpine BT driver.
>>>> + This driver handles BT traffic from upper layers and pass
>>>> + to the RSI_91x coex module for further scheduling to device
>>>> +
>>>> + Say Y here to compile support for HCI over Qualcomm SMD into t=
he
>>>> + kernel or say M to compile as a module.
>>>> +
>>>
>>> What I am missing is the depends on the RSI core piece that is needed.
>>
>> Actually RSI core module depends on RSI BT module as per our design.
>> As soon as firmware is downloaded by RSI core module, we get WLAN and
>> BT card ready frames from firmware. BT initialization has to happen at
>> this point. So btrsi module should be loaded first.
>
> that should be solved by the dependencies and not by a default m.

Understood. I will take care of it and submit v3.

>
>>
>>>
>>>> endmenu
>>>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>>>> index 4e4e44d..712af83a 100644
>>>> --- a/drivers/bluetooth/Makefile
>>>> +++ b/drivers/bluetooth/Makefile
>>>> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) +=3D btqca.o
>>>>
>>>> obj-$(CONFIG_BT_HCIUART_NOKIA) +=3D hci_nokia.o
>>>>
>>>> +obj-$(CONFIG_BT_RSI) +=3D btrsi.o
>>>> +
>>>> btmrvl-y :=3D btmrvl_main.o
>>>> btmrvl-$(CONFIG_DEBUG_FS) +=3D btmrvl_debugfs.o
>>>>
>>>> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
>>>> new file mode 100644
>>>> index 0000000..c52f418
>>>> --- /dev/null
>>>> +++ b/drivers/bluetooth/btrsi.c
>>>> @@ -0,0 +1,268 @@
>>>> +/**
>>>> + * Copyright (c) 2017 Redpine Signals Inc.
>>>> + *
>>>> + * Permission to use, copy, modify, and/or distribute this software f=
or any
>>>> + * purpose with or without fee is hereby granted, provided that the a=
bove
>>>> + * copyright notice and this permission notice appear in all copies.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARR=
ANTIES
>>>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>>>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABL=
E FOR
>>>> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAM=
AGES
>>>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN=
AN
>>>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING O=
UT OF
>>>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>>>> + */
>>>> +#include <linux/version.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/kernel.h>
>>>> +#include "rsi_hci.h"
>>>> +
>>>> +static struct rsi_mod_ops rsi_bt_ops =3D {
>>>> + .attach =3D rsi_hci_attach,
>>>> + .detach =3D rsi_hci_detach,
>>>> + .recv_pkt =3D rsi_hci_recv_pkt,
>>>> +};
>>>> +
>>>> +static int rsi_hci_open(struct hci_dev *hdev)
>>>> +{
>>>> + BT_INFO("%s open\n", hdev->name);
>>>
>>> No BT_INFO here. We are not spamming dmesg with pointless information. =
And this applies to all of these.
>>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int rsi_hci_close(struct hci_dev *hdev)
>>>> +{
>>>> + BT_INFO("%s closed\n", hdev->name);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int rsi_hci_flush(struct hci_dev *hdev)
>>>> +{
>>>> + BT_ERR("%s flush\n", hdev->name);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb=
)
>>>> +{
>>>> + struct rsi_hci_adapter *h_adapter;
>>>
>>> =3D hci_get_drvdata(dev);
>>>
>>> There is no need to do that separate.
>>>
>>>> + struct sk_buff *new_skb =3D NULL;
>>>> +
>>>> + int status =3D 0;
>>>> +
>>>> + h_adapter =3D hci_get_drvdata(hdev);
>>>> + if (!h_adapter) {
>>>> + status =3D -EFAULT;
>>>> + goto fail;
>>>> + }
>>>
>>> And this error check seems unneeded since the Bluetooth core will never=
call ->send unless it is all correctly set up.
>>>
>>>> +
>>>> + if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>>>> + BT_INFO("BT Device not ready\n");
>>>> + status =3D -ENODEV;
>>>> + goto fail;
>>>> + }
>>>
>>> Why are we registering a HCI device that might not be ready. This will =
be a massive bug in the whole system. Also one that is not recoverable. If =
something goes wrong, then lets unregister the HCI device.
>>>
>>>> +
>>>> + if (!test_bit(HCI_RUNNING, &hdev->flags)) {
>>>> + status =3D -EBUSY;
>>>> + goto fail;
>>>> + }
>>>
>>> This should no longer be needed. We moved this into the core and beside=
s some old USB drivers, nobody is using this anymore.
>>>
>>>> +
>>>> + switch (bt_cb(skb)->pkt_type) {
>>>> + case HCI_COMMAND_PKT:
>>>> + hdev->stat.cmd_tx++;
>>>> + break;
>>>> +
>>>> + case HCI_ACLDATA_PKT:
>>>> + hdev->stat.acl_tx++;
>>>> + break;
>>>> +
>>>> + case HCI_SCODATA_PKT:
>>>> + hdev->stat.sco_tx++;
>>>> + break;
>>>> +
>>>> + default:
>>>> + dev_kfree_skb(skb);
>>>
>>> Don=E2=80=99t use dev_kfree_skb() here. I think the Bluetooth subsystem=
is not ready for that.
>>>
>>>> + status =3D -EILSEQ;
>>>> + goto fail;
>>>> + }
>>>> +
>>>> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>>>> + /* Re-allocate one more skb with sufficent headroom */
>>>> + /* Space for Descriptor (16 bytes) is required in head r=
oom */
>>>> + u16 new_len =3D skb->len + RSI_HEADROOM_FOR_BT_HAL;
>>>> +
>>>> + new_skb =3D dev_alloc_skb(new_len);
>>>> + if (!new_skb) {
>>>> + dev_kfree_skb(skb);
>>>> + return -ENOMEM;
>>>> + }
>>>> + skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
>>>> + skb_put(new_skb, skb->len);
>>>> + memcpy(new_skb->data, skb->data, skb->len);
>>>> + bt_cb(new_skb)->pkt_type =3D bt_cb(skb)->pkt_type;
>>>> + dev_kfree_skb(skb);
>>>> + skb =3D new_skb;
>>>
>>> Just allocate a new skb with proper headroom. The data part can be shar=
ed. Doing this fully manual is just a bad idea.
>>>
>>> I also get the feeling that long term we want to change the Bluetooth d=
rivers to specify the required SKB headroom so that they always get SKBs th=
at are large enough for their needs.
>>>
>>>> + }
>>>> + if (h_adapter->proto_ops->coex_send_pkt)
>>>> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->pr=
iv, skb,
>>>> + RSI_BT_Q);
>>>
>>> This is worrisome. You need to send. If this callback is not available,=
then better not register the HCI device at all.
>>>
>>>> +
>>>> +fail:
>>>> + dev_kfree_skb(skb);
>>>> + return status;
>>>> +}
>>>> +
>>>> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
>>>> +{
>>>> + struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)=
priv;
>>>> + struct hci_dev *hdev =3D NULL;
>>>> + struct sk_buff *skb;
>>>> + int pkt_len =3D (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
>>>> + u8 queue_no =3D (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
>>>
>>> We have get_unaligned_le16 helpers for this.
>>>
>>>> +
>>>> + if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>>>> + BT_INFO("BT Device not ready\n");
>>>> + return 0;
>>>> + }
>>>
>>> Why call this function if the device is not ready? Can that not be chec=
ked and the HCI device not be registered.
>>>
>>>> +
>>>> + if (queue_no =3D=3D RSI_BT_MGMT_Q) {
>>>> + u8 msg_type =3D pkt[14] & 0xFF;
>>>> +
>>>> + switch (msg_type) {
>>>> + case RSI_RESULT_CONFIRM:
>>>> + BT_INFO("BT Result Confirm\n");
>>>> + return 0;
>>>> + case RSI_BT_BER:
>>>> + BT_INFO("BT Ber\n");
>>>> + return 0;
>>>> + case RSI_BT_CW:
>>>> + BT_INFO("BT CW\n");
>>>> + return 0;
>>>> + default:
>>>> + break;
>>>> + }
>>>> + }
>>>
>>> How noisy is this? Also no \n required for the BT_INFO functions. And h=
ere bt_dev_info is preferred anyway.
>>>
>>>> +
>>>> + skb =3D dev_alloc_skb(pkt_len);
>>>> + if (!skb)
>>>> + return -ENOMEM;
>>>> +
>>>> + hdev =3D h_adapter->hdev;
>>>> + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
>>>> + skb_put(skb, pkt_len);
>>>> + h_adapter->hdev->stat.byte_rx +=3D skb->len;
>>>> +
>>>> + skb->dev =3D (void *)hdev;
>>>> + bt_cb(skb)->pkt_type =3D pkt[14];
>>>> +
>>>> + return hci_recv_frame(hdev, skb);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
>>>> +
>>>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
>>>> +{
>>>> + struct rsi_hci_adapter *h_adapter =3D NULL;
>>>> + struct hci_dev *hdev;
>>>> + int status =3D 0;
>>>> +
>>>> + h_adapter =3D kzalloc(sizeof(*h_adapter), GFP_KERNEL);
>>>> + if (!h_adapter)
>>>> + return -ENOMEM;
>>>> +
>>>> + h_adapter->priv =3D priv;
>>>> + ops->set_bt_context(priv, h_adapter);
>>>> + h_adapter->proto_ops =3D ops;
>>>> + ops->bt_ops =3D &rsi_bt_ops;
>>>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>>>> +
>>>> + hdev =3D hci_alloc_dev();
>>>> + if (!hdev) {
>>>> + BT_ERR("Failed to alloc HCI device\n");
>>>> + goto err;
>>>> + }
>>>> + h_adapter->hdev =3D hdev;
>>>> +
>>>> + if (ops->get_host_intf(priv) =3D=3D RSI_HOST_INTF_SDIO)
>>>> + hdev->bus =3D HCI_SDIO;
>>>> + else
>>>> + hdev->bus =3D HCI_USB;
>>>> +
>>>> + hci_set_drvdata(hdev, h_adapter);
>>>> + hdev->dev_type =3D HCI_PRIMARY;
>>>> + hdev->open =3D rsi_hci_open;
>>>> + hdev->close =3D rsi_hci_close;
>>>> + hdev->flush =3D rsi_hci_flush;
>>>> + hdev->send =3D rsi_hci_send_pkt;
>>>> +
>>>> + status =3D hci_register_dev(hdev);
>>>> + if (status < 0) {
>>>> + BT_ERR("%s: HCI registration failed with errcode %d\n",
>>>> + __func__, status);
>>>> + goto err;
>>>> + }
>>>> +
>>>> + BT_INFO("%s interface created\n", hdev->name);
>>>> +
>>>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>>>> +
>>>> + return 0;
>>>> +
>>>> +err:
>>>> + if (hdev) {
>>>> + hci_unregister_dev(hdev);
>>>> + hci_free_dev(hdev);
>>>> + h_adapter->hdev =3D NULL;
>>>> + }
>>>> + kfree(h_adapter);
>>>> +
>>>> + return -EINVAL;
>>>> +}
>>>> +
>>>> +void rsi_hci_detach(void *priv)
>>>> +{
>>>> + struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)=
priv;
>>>> + struct hci_dev *hdev;
>>>> +
>>>> + if (!h_adapter)
>>>> + return;
>>>> +
>>>> + hdev =3D h_adapter->hdev;
>>>> +
>>>> + BT_INFO("Detaching %s\n", hdev->name);
>>>> +
>>>> + if (hdev) {
>>>> + hci_unregister_dev(hdev);
>>>> + hci_free_dev(hdev);
>>>> + h_adapter->hdev =3D NULL;
>>>> + }
>>>> +
>>>> + kfree(h_adapter);
>>>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_NOT_READY;
>>>> +}
>>>> +
>>>> +struct rsi_mod_ops *rsi_get_hci_ops(void)
>>>> +{
>>>> + return &rsi_bt_ops;
>>>> +};
>>>> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
>>>> +
>>>> +static int rsi_91x_bt_module_init(void)
>>>> +{
>>>> + BT_INFO("%s: BT Module init called\n", __func__);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static void rsi_91x_bt_module_exit(void)
>>>> +{
>>>> + BT_INFO("%s: BT Module exit called\n", __func__);
>>>> +}
>>>> +
>>>> +module_init(rsi_91x_bt_module_init);
>>>> +module_exit(rsi_91x_bt_module_exit);
>>>> +MODULE_AUTHOR("Redpine Signals Inc");
>>>> +MODULE_DESCRIPTION("RSI BT driver");
>>>> +MODULE_SUPPORTED_DEVICE("RSI-BT");
>>>> +MODULE_LICENSE("Dual BSD/GPL");
>>>> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
>>>> new file mode 100644
>>>> index 0000000..6f44231
>>>> --- /dev/null
>>>> +++ b/drivers/bluetooth/rsi_hci.h
>>>> @@ -0,0 +1,51 @@
>>>> +/**
>>>> + * Copyright (c) 2017 Redpine Signals Inc.
>>>> + *
>>>> + * Permission to use, copy, modify, and/or distribute this software f=
or any
>>>> + * purpose with or without fee is hereby granted, provided that the a=
bove
>>>> + * copyright notice and this permission notice appear in all copies.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARR=
ANTIES
>>>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>>>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABL=
E FOR
>>>> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAM=
AGES
>>>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN=
AN
>>>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING O=
UT OF
>>>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>>>> + */
>>>> +
>>>> +#ifndef __RSI_HCI_H__
>>>> +#define __RSI_HCI_H__
>>>> +
>>>> +#include <net/bluetooth/bluetooth.h>
>>>> +#include <net/bluetooth/hci_core.h>
>>>> +#include <linux/rsi_header.h>
>>>> +#include <net/genetlink.h>
>>>> +
>>>> +/* RX frame types */
>>>> +#define RSI_RESULT_CONFIRM 0x80
>>>> +#define RSI_BT_PER 0x10
>>>> +#define RSI_BT_BER 0x11
>>>> +#define RSI_BT_CW 0x12
>>>> +
>>>> +#define RSI_HEADROOM_FOR_BT_HAL 16
>>>> +
>>>> +enum bt_fsm_state {
>>>> + RSI_BT_FSM_DEVICE_NOT_READY =3D 0,
>>>> + RSI_BT_FSM_DEVICE_READY,
>>>> +};
>>>> +
>>>> +struct rsi_hci_adapter {
>>>> + void *priv;
>>>> + struct rsi_proto_ops *proto_ops;
>>>> + enum bt_fsm_state fsm_state;
>>>> + struct hci_dev *hdev;
>>>> +};
>>>
>>> If they are btrsi.c specific, they should be in btrsi.c and not in a he=
ader file.
>>>
>>>> +
>>>> +#define RSI_FRAME_DESC_SIZE 16
>>>> +
>>>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
>>>> +void rsi_hci_detach(void *priv);
>>>> +int rsi_hci_recv_pkt(void *data, u8 *pkt);
>>>
>>> And this is the part I do not get. What is the deal with the rsi_bt_ops=
. Having both exported is pointless.
>>
>> rsi core module initializes rsi_bt_ops by calling exported function
>> rsi_get_hci_ops().
>
> Still exporting both is pointless. There are a few too many exports / pub=
lic functions here. Make as much static as possible.

Sure. I have now removed unnecessary exports. I will submit v3 patch series=
.

Regards,
Amitkumar

2017-11-16 05:12:29

by Amitkumar Karwar

[permalink] [raw]
Subject: Re: [PATCH 2/8] rsi: add bluetooth rx endpoint

On Wed, Nov 15, 2017 at 8:53 PM, Marcel Holtmann <[email protected]> wrot=
e:
> Hi Amitkumar,
>
>> USB endpoint 1 is used for WLAN which is presently in use.
>> USB endpoint 2 is introduced for BT Rx traffic. Enumeration
>> of Rx BT endpoint and submitting Rx BT URB are added.
>
> wouldn=E2=80=99t it be good to include the /sys/kernel/debug/usb/devices =
part here that shows how the USB device=E2=80=99s layout.

Sure. We will do this in updated version.

Regards,
Amitkumar

2017-11-15 07:28:35

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 4/8] rsi: add coex support

From: Prameela Rani Garnepudi <[email protected]>

With BT support, driver has to handle two streams of data
(i.e. wlan and BT). Actual coex implementation is in firmware.
Coex module just schedule the packets to firmware by taking them
from the corresponding paths.

Structures for module and protocol operations are introduced for
this purpose. Protocol operations structure is global structure
which can be shared among different modules. Initialization of
coex and operating mode values is moved to rsi_91x_init().

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/Makefile | 1 +
drivers/net/wireless/rsi/rsi_91x_coex.c | 182 ++++++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_hal.c | 17 +--
drivers/net/wireless/rsi/rsi_91x_main.c | 30 +++++-
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 2 +-
drivers/net/wireless/rsi/rsi_91x_sdio.c | 1 +
drivers/net/wireless/rsi/rsi_91x_usb.c | 2 +
drivers/net/wireless/rsi/rsi_coex.h | 38 +++++++
drivers/net/wireless/rsi/rsi_main.h | 5 +
drivers/net/wireless/rsi/rsi_mgmt.h | 3 +
include/linux/rsi_header.h | 22 ++++
11 files changed, 293 insertions(+), 10 deletions(-)
create mode 100644 drivers/net/wireless/rsi/rsi_91x_coex.c
create mode 100644 drivers/net/wireless/rsi/rsi_coex.h

diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile
index 47c4590..fda827b 100644
--- a/drivers/net/wireless/rsi/Makefile
+++ b/drivers/net/wireless/rsi/Makefile
@@ -5,6 +5,7 @@ rsi_91x-y += rsi_91x_mac80211.o
rsi_91x-y += rsi_91x_mgmt.o
rsi_91x-y += rsi_91x_hal.o
rsi_91x-y += rsi_91x_ps.o
+rsi_91x-y += rsi_91x_coex.o
rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o

rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c
new file mode 100644
index 0000000..914a0c5
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_coex.c
@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rsi_main.h"
+#include "rsi_coex.h"
+#include "rsi_mgmt.h"
+#include "rsi_hal.h"
+
+static enum rsi_coex_queues rsi_coex_determine_coex_q
+ (struct rsi_coex_ctrl_block *coex_cb)
+{
+ enum rsi_coex_queues q_num = RSI_COEX_Q_INVALID;
+
+ if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_COMMON]) > 0)
+ q_num = RSI_COEX_Q_COMMON;
+ if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]) > 0)
+ q_num = RSI_COEX_Q_BT;
+ if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_WLAN]) > 0)
+ q_num = RSI_COEX_Q_WLAN;
+
+ return q_num;
+}
+
+static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
+{
+ enum rsi_coex_queues coex_q;
+ struct sk_buff *skb;
+
+ while (1) {
+ coex_q = rsi_coex_determine_coex_q(coex_cb);
+ rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q);
+
+ if (coex_q == RSI_COEX_Q_INVALID) {
+ rsi_dbg(DATA_TX_ZONE, "No more pkt\n");
+ break;
+ }
+
+ if (coex_q == RSI_COEX_Q_BT)
+ skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]);
+ }
+}
+
+static void rsi_coex_scheduler_thread(struct rsi_common *common)
+{
+ struct rsi_coex_ctrl_block *coex_cb =
+ (struct rsi_coex_ctrl_block *)common->coex_cb;
+ u32 timeout = EVENT_WAIT_FOREVER;
+
+ do {
+ rsi_wait_event(&coex_cb->coex_tx_thread.event, timeout);
+ rsi_reset_event(&coex_cb->coex_tx_thread.event);
+
+ rsi_coex_sched_tx_pkts(coex_cb);
+ } while (atomic_read(&coex_cb->coex_tx_thread.thread_done) == 0);
+
+ complete_and_exit(&coex_cb->coex_tx_thread.completion, 0);
+}
+
+int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg)
+{
+ u8 msg_type = msg[RSI_RX_DESC_MSG_TYPE_OFFSET];
+
+ switch (msg_type) {
+ case COMMON_CARD_READY_IND:
+ rsi_dbg(INFO_ZONE, "common card ready received\n");
+ rsi_handle_card_ready(common, msg);
+ break;
+ case SLEEP_NOTIFY_IND:
+ rsi_dbg(INFO_ZONE, "sleep notify received\n");
+ rsi_mgmt_pkt_recv(common, msg);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int rsi_map_coex_q(u8 hal_queue)
+{
+ switch (hal_queue) {
+ case RSI_COEX_Q:
+ return RSI_COEX_Q_COMMON;
+ case RSI_WLAN_Q:
+ return RSI_COEX_Q_WLAN;
+ case RSI_BT_Q:
+ return RSI_COEX_Q_BT;
+ }
+ return RSI_COEX_Q_INVALID;
+}
+
+int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue)
+{
+ struct rsi_common *common = (struct rsi_common *)priv;
+ struct rsi_coex_ctrl_block *coex_cb =
+ (struct rsi_coex_ctrl_block *)common->coex_cb;
+ struct skb_info *tx_params = NULL;
+ enum rsi_coex_queues coex_q;
+ int status;
+
+ coex_q = rsi_map_coex_q(hal_queue);
+ if (coex_q == RSI_COEX_Q_INVALID) {
+ rsi_dbg(ERR_ZONE, "Invalid coex queue\n");
+ return -EINVAL;
+ }
+ if (coex_q != RSI_COEX_Q_COMMON &&
+ coex_q != RSI_COEX_Q_WLAN) {
+ skb_queue_tail(&coex_cb->coex_tx_qs[coex_q], skb);
+ rsi_set_event(&coex_cb->coex_tx_thread.event);
+ return 0;
+ }
+ if (common->iface_down) {
+ tx_params =
+ (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data;
+
+ if (!(tx_params->flags & INTERNAL_MGMT_PKT)) {
+ rsi_indicate_tx_status(common->priv, skb, -EINVAL);
+ return 0;
+ }
+ }
+
+ /* Send packet to hal */
+ if (skb->priority == MGMT_SOFT_Q)
+ status = rsi_send_mgmt_pkt(common, skb);
+ else
+ status = rsi_send_data_pkt(common, skb);
+
+ return status;
+}
+
+int rsi_coex_attach(struct rsi_common *common)
+{
+ struct rsi_coex_ctrl_block *coex_cb;
+ int cnt;
+
+ coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL);
+ if (!coex_cb)
+ return -ENOMEM;
+
+ common->coex_cb = (void *)coex_cb;
+ coex_cb->priv = common;
+
+ /* Initialize co-ex queues */
+ for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
+ skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]);
+ rsi_init_event(&coex_cb->coex_tx_thread.event);
+
+ /* Initialize co-ex thread */
+ if (rsi_create_kthread(common,
+ &coex_cb->coex_tx_thread,
+ rsi_coex_scheduler_thread,
+ "Coex-Tx-Thread")) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void rsi_coex_detach(struct rsi_common *common)
+{
+ struct rsi_coex_ctrl_block *coex_cb =
+ (struct rsi_coex_ctrl_block *)common->coex_cb;
+ int cnt;
+
+ rsi_kill_thread(&coex_cb->coex_tx_thread);
+
+ for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
+ skb_queue_purge(&coex_cb->coex_tx_qs[cnt]);
+
+ kfree(coex_cb);
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 1176de6..8b30448 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -31,8 +31,15 @@ int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
struct rsi_hw *adapter = common->priv;
int status;

+ if (common->coex_mode > 1)
+ down(&common->tx_bus_lock);
+
status = adapter->host_intf_ops->write_pkt(common->priv,
skb->data, skb->len);
+
+ if (common->coex_mode > 1)
+ up(&common->tx_bus_lock);
+
return status;
}

@@ -296,8 +303,7 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
if (status)
goto err;

- status = adapter->host_intf_ops->write_pkt(common->priv, skb->data,
- skb->len);
+ status = rsi_send_pkt_to_bus(common, skb);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);

@@ -342,8 +348,7 @@ int rsi_send_mgmt_pkt(struct rsi_common *common,
goto err;

rsi_prepare_mgmt_desc(common, skb);
- status = adapter->host_intf_ops->write_pkt(common->priv,
- (u8 *)skb->data, skb->len);
+ status = rsi_send_pkt_to_bus(common, skb);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);

@@ -926,10 +931,6 @@ int rsi_hal_device_init(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;

- common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
- common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
- adapter->device_model = RSI_DEV_9113;
-
switch (adapter->device_model) {
case RSI_DEV_9113:
if (rsi_load_firmware(adapter)) {
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 0413af8..7dce533 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -20,6 +20,7 @@
#include <linux/firmware.h>
#include "rsi_mgmt.h"
#include "rsi_common.h"
+#include "rsi_coex.h"
#include "rsi_hal.h"

u32 rsi_zone_enabled = /* INFO_ZONE |
@@ -160,8 +161,13 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)

switch (queueno) {
case RSI_COEX_Q:
- rsi_mgmt_pkt_recv(common, (frame_desc + offset));
+ if (common->coex_mode > 1)
+ rsi_coex_recv_pkt(common, frame_desc + offset);
+ else
+ rsi_mgmt_pkt_recv(common,
+ (frame_desc + offset));
break;
+
case RSI_WIFI_DATA_Q:
skb = rsi_prepare_skb(common,
(frame_desc + offset),
@@ -217,6 +223,13 @@ static void rsi_tx_scheduler_thread(struct rsi_common *common)
complete_and_exit(&common->tx_thread.completion, 0);
}

+enum rsi_host_intf rsi_get_host_intf(void *priv)
+{
+ struct rsi_common *common = (struct rsi_common *)priv;
+
+ return common->priv->rsi_host_intf;
+}
+
/**
* rsi_91x_init() - This function initializes os interface operations.
* @void: Void.
@@ -251,6 +264,7 @@ struct rsi_hw *rsi_91x_init(void)
mutex_init(&common->mutex);
mutex_init(&common->tx_lock);
mutex_init(&common->rx_lock);
+ sema_init(&common->tx_bus_lock, 1);

if (rsi_create_kthread(common,
&common->tx_thread,
@@ -265,6 +279,17 @@ struct rsi_hw *rsi_91x_init(void)
timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
init_completion(&common->wlan_init_completion);
common->init_done = true;
+
+ common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
+ common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
+ adapter->device_model = RSI_DEV_9113;
+ if (common->coex_mode > 1) {
+ if (rsi_coex_attach(common)) {
+ rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
+ goto err;
+ }
+ }
+
return adapter;

err:
@@ -294,6 +319,9 @@ void rsi_91x_deinit(struct rsi_hw *adapter)

common->init_done = false;

+ if (common->coex_mode > 1)
+ rsi_coex_detach(common);
+
kfree(common);
kfree(adapter->rsi_dev);
kfree(adapter);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 46c9d54..c21fca7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1791,7 +1791,7 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
return -EINVAL;
}

-static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
+int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
{
switch (common->fsm_state) {
case FSM_CARD_NOT_READY:
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index b0cf411..ba38c6d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include "rsi_sdio.h"
#include "rsi_common.h"
+#include "rsi_coex.h"
#include "rsi_hal.h"

/**
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index b212a15..b09c7da 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -16,8 +16,10 @@
*/

#include <linux/module.h>
+#include <linux/rsi_header.h>
#include "rsi_usb.h"
#include "rsi_hal.h"
+#include "rsi_coex.h"

/**
* rsi_usb_card_write() - This function writes to the USB Card.
diff --git a/drivers/net/wireless/rsi/rsi_coex.h b/drivers/net/wireless/rsi/rsi_coex.h
new file mode 100644
index 0000000..22fe6ff
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_coex.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_COEX_H__
+#define __RSI_COEX_H__
+
+#include "rsi_common.h"
+
+#define RSI_COEX_TXQ_MAX_PKTS 64
+#define RSI_COEX_TXQ_WATER_MARK 50
+#define COMMON_CARD_READY_IND 0
+#define NUM_COEX_TX_QUEUES 5
+
+struct rsi_coex_ctrl_block {
+ struct rsi_common *priv;
+ struct sk_buff_head coex_tx_qs[NUM_COEX_TX_QUEUES];
+ struct rsi_thread coex_tx_thread;
+};
+
+int rsi_coex_attach(struct rsi_common *common);
+void rsi_coex_detach(struct rsi_common *common);
+int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 proto_type);
+int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg);
+
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index ca02a4b..e1c1dc8 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -206,6 +206,7 @@ struct rsi_common {
struct rsi_hw *priv;
struct vif_priv vif_info[RSI_MAX_VIFS];

+ void *coex_cb;
bool mgmt_q_block;
struct version_info lmac_ver;

@@ -270,6 +271,7 @@ struct rsi_common {
u8 obm_ant_sel_val;
int tx_power;
u8 ant_in_use;
+ struct semaphore tx_bus_lock;
bool hibernate_resume;
bool reinit_hw;
u8 wow_flags;
@@ -359,4 +361,7 @@ struct rsi_host_intf_ops {
u8 *fw);
int (*reinit_device)(struct rsi_hw *adapter);
};
+
+enum rsi_host_intf rsi_get_host_intf(void *priv);
+
#endif
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index 389094a..cf6567a 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -57,12 +57,14 @@
#define WOW_PATTERN_SIZE 256

/* Receive Frame Types */
+#define RSI_RX_DESC_MSG_TYPE_OFFSET 2
#define TA_CONFIRM_TYPE 0x01
#define RX_DOT11_MGMT 0x02
#define TX_STATUS_IND 0x04
#define BEACON_EVENT_IND 0x08
#define PROBEREQ_CONFIRM 2
#define CARD_READY_IND 0x00
+#define SLEEP_NOTIFY_IND 0x06

#define RSI_DELETE_PEER 0x0
#define RSI_ADD_PEER 0x1
@@ -638,6 +640,7 @@ static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno)
*addr = cpu_to_le16(len | ((qno & 7) << 12));
}

+int rsi_handle_card_ready(struct rsi_common *common, u8 *msg);
int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg);
int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode,
u8 *mac_addr, u8 vap_id, u8 vap_status);
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
index 16a447b..277f748 100644
--- a/include/linux/rsi_header.h
+++ b/include/linux/rsi_header.h
@@ -17,6 +17,8 @@
#ifndef __RSI_HEADER_H__
#define __RSI_HEADER_H__

+#include <linux/skbuff.h>
+
/* HAL queue information */
#define RSI_COEX_Q 0x0
#define RSI_BT_Q 0x2
@@ -26,9 +28,29 @@
#define RSI_BT_MGMT_Q 0x6
#define RSI_BT_DATA_Q 0x7

+enum rsi_coex_queues {
+ RSI_COEX_Q_INVALID = -1,
+ RSI_COEX_Q_COMMON = 0,
+ RSI_COEX_Q_BT,
+ RSI_COEX_Q_WLAN
+};
+
enum rsi_host_intf {
RSI_HOST_INTF_SDIO = 0,
RSI_HOST_INTF_USB
};

+struct rsi_proto_ops {
+ int (*coex_send_pkt)(void *priv, struct sk_buff *skb, u8 hal_queue);
+ enum rsi_host_intf (*get_host_intf)(void *priv);
+ void (*set_bt_context)(void *priv, void *context);
+ void *(*get_bt_context)(void *priv);
+ struct rsi_mod_ops *bt_ops;
+};
+
+struct rsi_mod_ops {
+ int (*attach)(void *priv, struct rsi_proto_ops *ops);
+ void (*detach)(void *priv);
+ int (*recv_pkt)(void *priv, u8 *msg);
+};
#endif
--
2.7.4

2017-11-29 13:33:54

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver

Hi Amitkumar,

>>> Redpine bluetooth driver is a thin driver which depends on
>>> 'rsi_91x' driver for transmitting and receiving packets
>>> to/from device. It creates hci interface when attach() is
>>> called from 'rsi_91x' module.
>>>
>>> Signed-off-by: Prameela Rani Garnepudi <[email protected]>
>>> Signed-off-by: Siva Rebbagondla <[email protected]>
>>> Signed-off-by: Amitkumar Karwar <[email protected]>
>>> ---
>>> drivers/bluetooth/Kconfig | 12 ++
>>> drivers/bluetooth/Makefile | 2 +
>>> drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++++++++++++++++++
>>> drivers/bluetooth/rsi_hci.h | 51 +++++++++
>>> 4 files changed, 333 insertions(+)
>>> create mode 100644 drivers/bluetooth/btrsi.c
>>> create mode 100644 drivers/bluetooth/rsi_hci.h
>>>
>>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>>> index 60e1c7d..ca58d74 100644
>>> --- a/drivers/bluetooth/Kconfig
>>> +++ b/drivers/bluetooth/Kconfig
>>> @@ -378,4 +378,16 @@ config BT_QCOMSMD
>>> Say Y here to compile support for HCI over Qualcomm SMD into the
>>> kernel or say M to compile as a module.
>>>
>>> +config BT_RSI
>>> + tristate "Redpine HCI support"
>>> + depends on BT && BT_RFCOMM
>>
>> the depends on BT_RFCOMM is wrong. And even the depends on BT is unneeded since that is already covered with the above menu clause.
>>
>>
>>> + default m
>>
>> No. New drivers are by default off.
>
> We made it by default on, as RSI core module depends on this.
>
>>
>>> + help
>>> + Redpine BT driver.
>>> + This driver handles BT traffic from upper layers and pass
>>> + to the RSI_91x coex module for further scheduling to device
>>> +
>>> + Say Y here to compile support for HCI over Qualcomm SMD into the
>>> + kernel or say M to compile as a module.
>>> +
>>
>> What I am missing is the depends on the RSI core piece that is needed.
>
> Actually RSI core module depends on RSI BT module as per our design.
> As soon as firmware is downloaded by RSI core module, we get WLAN and
> BT card ready frames from firmware. BT initialization has to happen at
> this point. So btrsi module should be loaded first.

that should be solved by the dependencies and not by a default m.

>
>>
>>> endmenu
>>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>>> index 4e4e44d..712af83a 100644
>>> --- a/drivers/bluetooth/Makefile
>>> +++ b/drivers/bluetooth/Makefile
>>> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) += btqca.o
>>>
>>> obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
>>>
>>> +obj-$(CONFIG_BT_RSI) += btrsi.o
>>> +
>>> btmrvl-y := btmrvl_main.o
>>> btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
>>>
>>> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
>>> new file mode 100644
>>> index 0000000..c52f418
>>> --- /dev/null
>>> +++ b/drivers/bluetooth/btrsi.c
>>> @@ -0,0 +1,268 @@
>>> +/**
>>> + * Copyright (c) 2017 Redpine Signals Inc.
>>> + *
>>> + * Permission to use, copy, modify, and/or distribute this software for any
>>> + * purpose with or without fee is hereby granted, provided that the above
>>> + * copyright notice and this permission notice appear in all copies.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
>>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
>>> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
>>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
>>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>>> + */
>>> +#include <linux/version.h>
>>> +#include <linux/module.h>
>>> +#include <linux/kernel.h>
>>> +#include "rsi_hci.h"
>>> +
>>> +static struct rsi_mod_ops rsi_bt_ops = {
>>> + .attach = rsi_hci_attach,
>>> + .detach = rsi_hci_detach,
>>> + .recv_pkt = rsi_hci_recv_pkt,
>>> +};
>>> +
>>> +static int rsi_hci_open(struct hci_dev *hdev)
>>> +{
>>> + BT_INFO("%s open\n", hdev->name);
>>
>> No BT_INFO here. We are not spamming dmesg with pointless information. And this applies to all of these.
>>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int rsi_hci_close(struct hci_dev *hdev)
>>> +{
>>> + BT_INFO("%s closed\n", hdev->name);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int rsi_hci_flush(struct hci_dev *hdev)
>>> +{
>>> + BT_ERR("%s flush\n", hdev->name);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
>>> +{
>>> + struct rsi_hci_adapter *h_adapter;
>>
>> = hci_get_drvdata(dev);
>>
>> There is no need to do that separate.
>>
>>> + struct sk_buff *new_skb = NULL;
>>> +
>>> + int status = 0;
>>> +
>>> + h_adapter = hci_get_drvdata(hdev);
>>> + if (!h_adapter) {
>>> + status = -EFAULT;
>>> + goto fail;
>>> + }
>>
>> And this error check seems unneeded since the Bluetooth core will never call ->send unless it is all correctly set up.
>>
>>> +
>>> + if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
>>> + BT_INFO("BT Device not ready\n");
>>> + status = -ENODEV;
>>> + goto fail;
>>> + }
>>
>> Why are we registering a HCI device that might not be ready. This will be a massive bug in the whole system. Also one that is not recoverable. If something goes wrong, then lets unregister the HCI device.
>>
>>> +
>>> + if (!test_bit(HCI_RUNNING, &hdev->flags)) {
>>> + status = -EBUSY;
>>> + goto fail;
>>> + }
>>
>> This should no longer be needed. We moved this into the core and besides some old USB drivers, nobody is using this anymore.
>>
>>> +
>>> + switch (bt_cb(skb)->pkt_type) {
>>> + case HCI_COMMAND_PKT:
>>> + hdev->stat.cmd_tx++;
>>> + break;
>>> +
>>> + case HCI_ACLDATA_PKT:
>>> + hdev->stat.acl_tx++;
>>> + break;
>>> +
>>> + case HCI_SCODATA_PKT:
>>> + hdev->stat.sco_tx++;
>>> + break;
>>> +
>>> + default:
>>> + dev_kfree_skb(skb);
>>
>> Don’t use dev_kfree_skb() here. I think the Bluetooth subsystem is not ready for that.
>>
>>> + status = -EILSEQ;
>>> + goto fail;
>>> + }
>>> +
>>> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>>> + /* Re-allocate one more skb with sufficent headroom */
>>> + /* Space for Descriptor (16 bytes) is required in head room */
>>> + u16 new_len = skb->len + RSI_HEADROOM_FOR_BT_HAL;
>>> +
>>> + new_skb = dev_alloc_skb(new_len);
>>> + if (!new_skb) {
>>> + dev_kfree_skb(skb);
>>> + return -ENOMEM;
>>> + }
>>> + skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
>>> + skb_put(new_skb, skb->len);
>>> + memcpy(new_skb->data, skb->data, skb->len);
>>> + bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
>>> + dev_kfree_skb(skb);
>>> + skb = new_skb;
>>
>> Just allocate a new skb with proper headroom. The data part can be shared. Doing this fully manual is just a bad idea.
>>
>> I also get the feeling that long term we want to change the Bluetooth drivers to specify the required SKB headroom so that they always get SKBs that are large enough for their needs.
>>
>>> + }
>>> + if (h_adapter->proto_ops->coex_send_pkt)
>>> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
>>> + RSI_BT_Q);
>>
>> This is worrisome. You need to send. If this callback is not available, then better not register the HCI device at all.
>>
>>> +
>>> +fail:
>>> + dev_kfree_skb(skb);
>>> + return status;
>>> +}
>>> +
>>> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
>>> +{
>>> + struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
>>> + struct hci_dev *hdev = NULL;
>>> + struct sk_buff *skb;
>>> + int pkt_len = (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
>>> + u8 queue_no = (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
>>
>> We have get_unaligned_le16 helpers for this.
>>
>>> +
>>> + if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
>>> + BT_INFO("BT Device not ready\n");
>>> + return 0;
>>> + }
>>
>> Why call this function if the device is not ready? Can that not be checked and the HCI device not be registered.
>>
>>> +
>>> + if (queue_no == RSI_BT_MGMT_Q) {
>>> + u8 msg_type = pkt[14] & 0xFF;
>>> +
>>> + switch (msg_type) {
>>> + case RSI_RESULT_CONFIRM:
>>> + BT_INFO("BT Result Confirm\n");
>>> + return 0;
>>> + case RSI_BT_BER:
>>> + BT_INFO("BT Ber\n");
>>> + return 0;
>>> + case RSI_BT_CW:
>>> + BT_INFO("BT CW\n");
>>> + return 0;
>>> + default:
>>> + break;
>>> + }
>>> + }
>>
>> How noisy is this? Also no \n required for the BT_INFO functions. And here bt_dev_info is preferred anyway.
>>
>>> +
>>> + skb = dev_alloc_skb(pkt_len);
>>> + if (!skb)
>>> + return -ENOMEM;
>>> +
>>> + hdev = h_adapter->hdev;
>>> + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
>>> + skb_put(skb, pkt_len);
>>> + h_adapter->hdev->stat.byte_rx += skb->len;
>>> +
>>> + skb->dev = (void *)hdev;
>>> + bt_cb(skb)->pkt_type = pkt[14];
>>> +
>>> + return hci_recv_frame(hdev, skb);
>>> +}
>>> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
>>> +
>>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
>>> +{
>>> + struct rsi_hci_adapter *h_adapter = NULL;
>>> + struct hci_dev *hdev;
>>> + int status = 0;
>>> +
>>> + h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL);
>>> + if (!h_adapter)
>>> + return -ENOMEM;
>>> +
>>> + h_adapter->priv = priv;
>>> + ops->set_bt_context(priv, h_adapter);
>>> + h_adapter->proto_ops = ops;
>>> + ops->bt_ops = &rsi_bt_ops;
>>> + h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
>>> +
>>> + hdev = hci_alloc_dev();
>>> + if (!hdev) {
>>> + BT_ERR("Failed to alloc HCI device\n");
>>> + goto err;
>>> + }
>>> + h_adapter->hdev = hdev;
>>> +
>>> + if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO)
>>> + hdev->bus = HCI_SDIO;
>>> + else
>>> + hdev->bus = HCI_USB;
>>> +
>>> + hci_set_drvdata(hdev, h_adapter);
>>> + hdev->dev_type = HCI_PRIMARY;
>>> + hdev->open = rsi_hci_open;
>>> + hdev->close = rsi_hci_close;
>>> + hdev->flush = rsi_hci_flush;
>>> + hdev->send = rsi_hci_send_pkt;
>>> +
>>> + status = hci_register_dev(hdev);
>>> + if (status < 0) {
>>> + BT_ERR("%s: HCI registration failed with errcode %d\n",
>>> + __func__, status);
>>> + goto err;
>>> + }
>>> +
>>> + BT_INFO("%s interface created\n", hdev->name);
>>> +
>>> + h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
>>> +
>>> + return 0;
>>> +
>>> +err:
>>> + if (hdev) {
>>> + hci_unregister_dev(hdev);
>>> + hci_free_dev(hdev);
>>> + h_adapter->hdev = NULL;
>>> + }
>>> + kfree(h_adapter);
>>> +
>>> + return -EINVAL;
>>> +}
>>> +
>>> +void rsi_hci_detach(void *priv)
>>> +{
>>> + struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
>>> + struct hci_dev *hdev;
>>> +
>>> + if (!h_adapter)
>>> + return;
>>> +
>>> + hdev = h_adapter->hdev;
>>> +
>>> + BT_INFO("Detaching %s\n", hdev->name);
>>> +
>>> + if (hdev) {
>>> + hci_unregister_dev(hdev);
>>> + hci_free_dev(hdev);
>>> + h_adapter->hdev = NULL;
>>> + }
>>> +
>>> + kfree(h_adapter);
>>> + h_adapter->fsm_state = RSI_BT_FSM_DEVICE_NOT_READY;
>>> +}
>>> +
>>> +struct rsi_mod_ops *rsi_get_hci_ops(void)
>>> +{
>>> + return &rsi_bt_ops;
>>> +};
>>> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
>>> +
>>> +static int rsi_91x_bt_module_init(void)
>>> +{
>>> + BT_INFO("%s: BT Module init called\n", __func__);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void rsi_91x_bt_module_exit(void)
>>> +{
>>> + BT_INFO("%s: BT Module exit called\n", __func__);
>>> +}
>>> +
>>> +module_init(rsi_91x_bt_module_init);
>>> +module_exit(rsi_91x_bt_module_exit);
>>> +MODULE_AUTHOR("Redpine Signals Inc");
>>> +MODULE_DESCRIPTION("RSI BT driver");
>>> +MODULE_SUPPORTED_DEVICE("RSI-BT");
>>> +MODULE_LICENSE("Dual BSD/GPL");
>>> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
>>> new file mode 100644
>>> index 0000000..6f44231
>>> --- /dev/null
>>> +++ b/drivers/bluetooth/rsi_hci.h
>>> @@ -0,0 +1,51 @@
>>> +/**
>>> + * Copyright (c) 2017 Redpine Signals Inc.
>>> + *
>>> + * Permission to use, copy, modify, and/or distribute this software for any
>>> + * purpose with or without fee is hereby granted, provided that the above
>>> + * copyright notice and this permission notice appear in all copies.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
>>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
>>> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
>>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
>>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>>> + */
>>> +
>>> +#ifndef __RSI_HCI_H__
>>> +#define __RSI_HCI_H__
>>> +
>>> +#include <net/bluetooth/bluetooth.h>
>>> +#include <net/bluetooth/hci_core.h>
>>> +#include <linux/rsi_header.h>
>>> +#include <net/genetlink.h>
>>> +
>>> +/* RX frame types */
>>> +#define RSI_RESULT_CONFIRM 0x80
>>> +#define RSI_BT_PER 0x10
>>> +#define RSI_BT_BER 0x11
>>> +#define RSI_BT_CW 0x12
>>> +
>>> +#define RSI_HEADROOM_FOR_BT_HAL 16
>>> +
>>> +enum bt_fsm_state {
>>> + RSI_BT_FSM_DEVICE_NOT_READY = 0,
>>> + RSI_BT_FSM_DEVICE_READY,
>>> +};
>>> +
>>> +struct rsi_hci_adapter {
>>> + void *priv;
>>> + struct rsi_proto_ops *proto_ops;
>>> + enum bt_fsm_state fsm_state;
>>> + struct hci_dev *hdev;
>>> +};
>>
>> If they are btrsi.c specific, they should be in btrsi.c and not in a header file.
>>
>>> +
>>> +#define RSI_FRAME_DESC_SIZE 16
>>> +
>>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
>>> +void rsi_hci_detach(void *priv);
>>> +int rsi_hci_recv_pkt(void *data, u8 *pkt);
>>
>> And this is the part I do not get. What is the deal with the rsi_bt_ops. Having both exported is pointless.
>
> rsi core module initializes rsi_bt_ops by calling exported function
> rsi_get_hci_ops().

Still exporting both is pointless. There are a few too many exports / public functions here. Make as much static as possible.

Regards

Marcel

2017-11-15 07:28:44

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 6/8] rsi: handle BT traffic in driver

From: Siva Rebbagondla <[email protected]>

BT frames are passed through coex and hal modules to BUS.
After firmware is loaded, based on the operating mode CARD
READY frame comes for each protocol. When BT card ready is
received, BT attach is called.
Protocol operations are exchanged between the modules
at initialization time.

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_coex.c | 4 ++-
drivers/net/wireless/rsi/rsi_91x_core.c | 16 +++++++---
drivers/net/wireless/rsi/rsi_91x_hal.c | 39 ++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_main.c | 47 +++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 1 +
drivers/net/wireless/rsi/rsi_common.h | 1 +
drivers/net/wireless/rsi/rsi_hal.h | 10 ++++++
drivers/net/wireless/rsi/rsi_main.h | 5 +++
include/linux/rsi_header.h | 2 ++
9 files changed, 119 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c
index 914a0c5..f502cf9 100644
--- a/drivers/net/wireless/rsi/rsi_91x_coex.c
+++ b/drivers/net/wireless/rsi/rsi_91x_coex.c
@@ -48,8 +48,10 @@ static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
break;
}

- if (coex_q == RSI_COEX_Q_BT)
+ if (coex_q == RSI_COEX_Q_BT) {
skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]);
+ rsi_send_bt_pkt(coex_cb->priv, skb);
+ }
}
}

diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c
index d0d2201..046ace8 100644
--- a/drivers/net/wireless/rsi/rsi_91x_core.c
+++ b/drivers/net/wireless/rsi/rsi_91x_core.c
@@ -17,6 +17,7 @@
#include "rsi_mgmt.h"
#include "rsi_common.h"
#include "rsi_hal.h"
+#include "rsi_coex.h"

/**
* rsi_determine_min_weight_queue() - This function determines the queue with
@@ -301,14 +302,19 @@ void rsi_core_qos_processor(struct rsi_common *common)
mutex_unlock(&common->tx_lock);
break;
}
-
- if (q_num == MGMT_SOFT_Q) {
- status = rsi_send_mgmt_pkt(common, skb);
- } else if (q_num == MGMT_BEACON_Q) {
+ if (q_num == MGMT_BEACON_Q) {
status = rsi_send_pkt_to_bus(common, skb);
dev_kfree_skb(skb);
} else {
- status = rsi_send_data_pkt(common, skb);
+ if (common->coex_mode > 1) {
+ status = rsi_coex_send_pkt(common, skb,
+ RSI_WLAN_Q);
+ } else {
+ if (q_num == MGMT_SOFT_Q)
+ status = rsi_send_mgmt_pkt(common, skb);
+ else
+ status = rsi_send_data_pkt(common, skb);
+ }
}

if (status) {
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 8b30448..883dba1 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -15,6 +15,7 @@
*/

#include <linux/firmware.h>
+#include <net/bluetooth/bluetooth.h>
#include "rsi_mgmt.h"
#include "rsi_hal.h"
#include "rsi_sdio.h"
@@ -24,6 +25,7 @@
static struct ta_metadata metadata_flash_content[] = {
{"flash_content", 0x00010000},
{"rsi/rs9113_wlan_qspi.rps", 0x00010000},
+ {"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000},
};

int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
@@ -357,6 +359,43 @@ int rsi_send_mgmt_pkt(struct rsi_common *common,
return status;
}

+int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb)
+{
+ int status = -EINVAL;
+ u8 header_size = 0;
+ struct rsi_bt_desc *bt_desc;
+ u8 queueno = ((skb->data[1] >> 4) & 0xf);
+
+ if (queueno == RSI_BT_MGMT_Q) {
+ status = rsi_send_pkt_to_bus(common, skb);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n",
+ __func__);
+ goto out;
+ }
+ header_size = FRAME_DESC_SZ;
+ if (header_size > skb_headroom(skb)) {
+ rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
+ status = -ENOSPC;
+ goto out;
+ }
+ skb_push(skb, header_size);
+ memset(skb->data, 0, header_size);
+ bt_desc = (struct rsi_bt_desc *)skb->data;
+
+ rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
+ RSI_BT_DATA_Q);
+ bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type);
+
+ status = rsi_send_pkt_to_bus(common, skb);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__);
+
+out:
+ dev_kfree_skb(skb);
+ return status;
+}
+
int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
{
struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 7dce533..00f54c5 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -18,6 +18,7 @@

#include <linux/module.h>
#include <linux/firmware.h>
+#include <linux/rsi_header.h>
#include "rsi_mgmt.h"
#include "rsi_common.h"
#include "rsi_coex.h"
@@ -35,6 +36,13 @@ u32 rsi_zone_enabled = /* INFO_ZONE |
0;
EXPORT_SYMBOL_GPL(rsi_zone_enabled);

+static struct rsi_proto_ops g_proto_ops = {
+ .coex_send_pkt = rsi_coex_send_pkt,
+ .get_host_intf = rsi_get_host_intf,
+ .set_bt_context = rsi_set_bt_context,
+ .get_bt_context = rsi_get_bt_context,
+};
+
/**
* rsi_dbg() - This function outputs informational messages.
* @zone: Zone of interest for output message.
@@ -144,6 +152,8 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
u32 index, length = 0, queueno = 0;
u16 actual_length = 0, offset;
struct sk_buff *skb = NULL;
+ struct rsi_mod_ops *bt_ops = g_proto_ops.bt_ops;
+ u8 bt_pkt_type;

index = 0;
do {
@@ -183,6 +193,24 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
rsi_mgmt_pkt_recv(common, (frame_desc + offset));
break;

+ case RSI_BT_MGMT_Q:
+ case RSI_BT_DATA_Q:
+#define BT_RX_PKT_TYPE_OFST 14
+#define BT_CARD_READY_IND 0x89
+ bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
+ if (bt_pkt_type == BT_CARD_READY_IND &&
+ bt_ops && bt_ops->attach) {
+ rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
+ if (bt_ops->attach(common, &g_proto_ops))
+ rsi_dbg(ERR_ZONE,
+ "Failed to attach BT module\n");
+ } else {
+ if (bt_ops && bt_ops->recv_pkt)
+ bt_ops->recv_pkt(common->bt_adapter,
+ frame_desc + offset);
+ }
+ break;
+
default:
rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
__func__, queueno);
@@ -230,6 +258,20 @@ enum rsi_host_intf rsi_get_host_intf(void *priv)
return common->priv->rsi_host_intf;
}

+void rsi_set_bt_context(void *priv, void *bt_context)
+{
+ struct rsi_common *common = (struct rsi_common *)priv;
+
+ common->bt_adapter = bt_context;
+}
+
+void *rsi_get_bt_context(void *priv)
+{
+ struct rsi_common *common = (struct rsi_common *)priv;
+
+ return common->bt_adapter;
+}
+
/**
* rsi_91x_init() - This function initializes os interface operations.
* @void: Void.
@@ -339,6 +381,11 @@ EXPORT_SYMBOL_GPL(rsi_91x_deinit);
static int rsi_91x_hal_module_init(void)
{
rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
+
+ g_proto_ops.bt_ops = rsi_get_hci_ops();
+ if (!g_proto_ops.bt_ops)
+ rsi_dbg(ERR_ZONE, "Failed to get BT ops\n");
+
return 0;
}

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 9fbc0ef..26abe51 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -16,6 +16,7 @@
*/

#include <linux/firmware.h>
+#include <linux/rsi_header.h>
#include "rsi_sdio.h"
#include "rsi_common.h"

diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 1d8af41..4616585 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -62,6 +62,7 @@ static inline int rsi_create_kthread(struct rsi_common *common,
u8 *name)
{
init_completion(&thread->completion);
+ atomic_set(&thread->thread_done, 0);
thread->task = kthread_run(func_ptr, common, "%s", name);
if (IS_ERR(thread->task))
return (int)PTR_ERR(thread->task);
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
index a09d36b..e712223 100644
--- a/drivers/net/wireless/rsi/rsi_hal.h
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -145,8 +145,18 @@ struct rsi_data_desc {
u8 sta_id;
} __packed;

+struct rsi_bt_desc {
+ __le16 len_qno;
+ __le16 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
+ __le16 reserved4;
+ __le16 bt_pkt_type;
+} __packed;
+
int rsi_hal_device_init(struct rsi_hw *adapter);
int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb);
int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb);
+int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb);

#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index e1c1dc8..033cc8c 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -290,6 +290,9 @@ struct rsi_common {
bool p2p_enabled;
struct timer_list roc_timer;
struct ieee80211_vif *roc_vif;
+
+ /* BT params */
+ void *bt_adapter;
};

struct eepromrw_info {
@@ -363,5 +366,7 @@ struct rsi_host_intf_ops {
};

enum rsi_host_intf rsi_get_host_intf(void *priv);
+void rsi_set_bt_context(void *priv, void *bt_context);
+void *rsi_get_bt_context(void *priv);

#endif
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
index 277f748..8e87d55 100644
--- a/include/linux/rsi_header.h
+++ b/include/linux/rsi_header.h
@@ -53,4 +53,6 @@ struct rsi_mod_ops {
void (*detach)(void *priv);
int (*recv_pkt)(void *priv, u8 *msg);
};
+
+struct rsi_mod_ops *rsi_get_hci_ops(void);
#endif
--
2.7.4

2017-11-15 15:37:24

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver

Hi Amitkumar,

> Redpine bluetooth driver is a thin driver which depends on
> 'rsi_91x' driver for transmitting and receiving packets
> to/from device. It creates hci interface when attach() is
> called from 'rsi_91x' module.
>
> Signed-off-by: Prameela Rani Garnepudi <[email protected]>
> Signed-off-by: Siva Rebbagondla <[email protected]>
> Signed-off-by: Amitkumar Karwar <[email protected]>
> ---
> drivers/bluetooth/Kconfig | 12 ++
> drivers/bluetooth/Makefile | 2 +
> drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/rsi_hci.h | 51 +++++++++
> 4 files changed, 333 insertions(+)
> create mode 100644 drivers/bluetooth/btrsi.c
> create mode 100644 drivers/bluetooth/rsi_hci.h
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 60e1c7d..ca58d74 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -378,4 +378,16 @@ config BT_QCOMSMD
> Say Y here to compile support for HCI over Qualcomm SMD into the
> kernel or say M to compile as a module.
>
> +config BT_RSI
> + tristate "Redpine HCI support"
> + depends on BT && BT_RFCOMM

the depends on BT_RFCOMM is wrong. And even the depends on BT is unneeded since that is already covered with the above menu clause.


> + default m

No. New drivers are by default off.

> + help
> + Redpine BT driver.
> + This driver handles BT traffic from upper layers and pass
> + to the RSI_91x coex module for further scheduling to device
> +
> + Say Y here to compile support for HCI over Qualcomm SMD into the
> + kernel or say M to compile as a module.
> +

What I am missing is the depends on the RSI core piece that is needed.

> endmenu
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 4e4e44d..712af83a 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) += btqca.o
>
> obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
>
> +obj-$(CONFIG_BT_RSI) += btrsi.o
> +
> btmrvl-y := btmrvl_main.o
> btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
>
> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
> new file mode 100644
> index 0000000..c52f418
> --- /dev/null
> +++ b/drivers/bluetooth/btrsi.c
> @@ -0,0 +1,268 @@
> +/**
> + * Copyright (c) 2017 Redpine Signals Inc.
> + *
> + * Permission to use, copy, modify, and/or distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include "rsi_hci.h"
> +
> +static struct rsi_mod_ops rsi_bt_ops = {
> + .attach = rsi_hci_attach,
> + .detach = rsi_hci_detach,
> + .recv_pkt = rsi_hci_recv_pkt,
> +};
> +
> +static int rsi_hci_open(struct hci_dev *hdev)
> +{
> + BT_INFO("%s open\n", hdev->name);

No BT_INFO here. We are not spamming dmesg with pointless information. And this applies to all of these.

> +
> + return 0;
> +}
> +
> +static int rsi_hci_close(struct hci_dev *hdev)
> +{
> + BT_INFO("%s closed\n", hdev->name);
> +
> + return 0;
> +}
> +
> +static int rsi_hci_flush(struct hci_dev *hdev)
> +{
> + BT_ERR("%s flush\n", hdev->name);
> +
> + return 0;
> +}
> +
> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + struct rsi_hci_adapter *h_adapter;

= hci_get_drvdata(dev);

There is no need to do that separate.

> + struct sk_buff *new_skb = NULL;
> +
> + int status = 0;
> +
> + h_adapter = hci_get_drvdata(hdev);
> + if (!h_adapter) {
> + status = -EFAULT;
> + goto fail;
> + }

And this error check seems unneeded since the Bluetooth core will never call ->send unless it is all correctly set up.

> +
> + if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
> + BT_INFO("BT Device not ready\n");
> + status = -ENODEV;
> + goto fail;
> + }

Why are we registering a HCI device that might not be ready. This will be a massive bug in the whole system. Also one that is not recoverable. If something goes wrong, then lets unregister the HCI device.

> +
> + if (!test_bit(HCI_RUNNING, &hdev->flags)) {
> + status = -EBUSY;
> + goto fail;
> + }

This should no longer be needed. We moved this into the core and besides some old USB drivers, nobody is using this anymore.

> +
> + switch (bt_cb(skb)->pkt_type) {
> + case HCI_COMMAND_PKT:
> + hdev->stat.cmd_tx++;
> + break;
> +
> + case HCI_ACLDATA_PKT:
> + hdev->stat.acl_tx++;
> + break;
> +
> + case HCI_SCODATA_PKT:
> + hdev->stat.sco_tx++;
> + break;
> +
> + default:
> + dev_kfree_skb(skb);

Don’t use dev_kfree_skb() here. I think the Bluetooth subsystem is not ready for that.

> + status = -EILSEQ;
> + goto fail;
> + }
> +
> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
> + /* Re-allocate one more skb with sufficent headroom */
> + /* Space for Descriptor (16 bytes) is required in head room */
> + u16 new_len = skb->len + RSI_HEADROOM_FOR_BT_HAL;
> +
> + new_skb = dev_alloc_skb(new_len);
> + if (!new_skb) {
> + dev_kfree_skb(skb);
> + return -ENOMEM;
> + }
> + skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
> + skb_put(new_skb, skb->len);
> + memcpy(new_skb->data, skb->data, skb->len);
> + bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
> + dev_kfree_skb(skb);
> + skb = new_skb;

Just allocate a new skb with proper headroom. The data part can be shared. Doing this fully manual is just a bad idea.

I also get the feeling that long term we want to change the Bluetooth drivers to specify the required SKB headroom so that they always get SKBs that are large enough for their needs.

> + }
> + if (h_adapter->proto_ops->coex_send_pkt)
> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
> + RSI_BT_Q);

This is worrisome. You need to send. If this callback is not available, then better not register the HCI device at all.

> +
> +fail:
> + dev_kfree_skb(skb);
> + return status;
> +}
> +
> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
> +{
> + struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
> + struct hci_dev *hdev = NULL;
> + struct sk_buff *skb;
> + int pkt_len = (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
> + u8 queue_no = (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;

We have get_unaligned_le16 helpers for this.

> +
> + if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
> + BT_INFO("BT Device not ready\n");
> + return 0;
> + }

Why call this function if the device is not ready? Can that not be checked and the HCI device not be registered.

> +
> + if (queue_no == RSI_BT_MGMT_Q) {
> + u8 msg_type = pkt[14] & 0xFF;
> +
> + switch (msg_type) {
> + case RSI_RESULT_CONFIRM:
> + BT_INFO("BT Result Confirm\n");
> + return 0;
> + case RSI_BT_BER:
> + BT_INFO("BT Ber\n");
> + return 0;
> + case RSI_BT_CW:
> + BT_INFO("BT CW\n");
> + return 0;
> + default:
> + break;
> + }
> + }

How noisy is this? Also no \n required for the BT_INFO functions. And here bt_dev_info is preferred anyway.

> +
> + skb = dev_alloc_skb(pkt_len);
> + if (!skb)
> + return -ENOMEM;
> +
> + hdev = h_adapter->hdev;
> + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
> + skb_put(skb, pkt_len);
> + h_adapter->hdev->stat.byte_rx += skb->len;
> +
> + skb->dev = (void *)hdev;
> + bt_cb(skb)->pkt_type = pkt[14];
> +
> + return hci_recv_frame(hdev, skb);
> +}
> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
> +
> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
> +{
> + struct rsi_hci_adapter *h_adapter = NULL;
> + struct hci_dev *hdev;
> + int status = 0;
> +
> + h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL);
> + if (!h_adapter)
> + return -ENOMEM;
> +
> + h_adapter->priv = priv;
> + ops->set_bt_context(priv, h_adapter);
> + h_adapter->proto_ops = ops;
> + ops->bt_ops = &rsi_bt_ops;
> + h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
> +
> + hdev = hci_alloc_dev();
> + if (!hdev) {
> + BT_ERR("Failed to alloc HCI device\n");
> + goto err;
> + }
> + h_adapter->hdev = hdev;
> +
> + if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO)
> + hdev->bus = HCI_SDIO;
> + else
> + hdev->bus = HCI_USB;
> +
> + hci_set_drvdata(hdev, h_adapter);
> + hdev->dev_type = HCI_PRIMARY;
> + hdev->open = rsi_hci_open;
> + hdev->close = rsi_hci_close;
> + hdev->flush = rsi_hci_flush;
> + hdev->send = rsi_hci_send_pkt;
> +
> + status = hci_register_dev(hdev);
> + if (status < 0) {
> + BT_ERR("%s: HCI registration failed with errcode %d\n",
> + __func__, status);
> + goto err;
> + }
> +
> + BT_INFO("%s interface created\n", hdev->name);
> +
> + h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
> +
> + return 0;
> +
> +err:
> + if (hdev) {
> + hci_unregister_dev(hdev);
> + hci_free_dev(hdev);
> + h_adapter->hdev = NULL;
> + }
> + kfree(h_adapter);
> +
> + return -EINVAL;
> +}
> +
> +void rsi_hci_detach(void *priv)
> +{
> + struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
> + struct hci_dev *hdev;
> +
> + if (!h_adapter)
> + return;
> +
> + hdev = h_adapter->hdev;
> +
> + BT_INFO("Detaching %s\n", hdev->name);
> +
> + if (hdev) {
> + hci_unregister_dev(hdev);
> + hci_free_dev(hdev);
> + h_adapter->hdev = NULL;
> + }
> +
> + kfree(h_adapter);
> + h_adapter->fsm_state = RSI_BT_FSM_DEVICE_NOT_READY;
> +}
> +
> +struct rsi_mod_ops *rsi_get_hci_ops(void)
> +{
> + return &rsi_bt_ops;
> +};
> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
> +
> +static int rsi_91x_bt_module_init(void)
> +{
> + BT_INFO("%s: BT Module init called\n", __func__);
> +
> + return 0;
> +}
> +
> +static void rsi_91x_bt_module_exit(void)
> +{
> + BT_INFO("%s: BT Module exit called\n", __func__);
> +}
> +
> +module_init(rsi_91x_bt_module_init);
> +module_exit(rsi_91x_bt_module_exit);
> +MODULE_AUTHOR("Redpine Signals Inc");
> +MODULE_DESCRIPTION("RSI BT driver");
> +MODULE_SUPPORTED_DEVICE("RSI-BT");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
> new file mode 100644
> index 0000000..6f44231
> --- /dev/null
> +++ b/drivers/bluetooth/rsi_hci.h
> @@ -0,0 +1,51 @@
> +/**
> + * Copyright (c) 2017 Redpine Signals Inc.
> + *
> + * Permission to use, copy, modify, and/or distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef __RSI_HCI_H__
> +#define __RSI_HCI_H__
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <linux/rsi_header.h>
> +#include <net/genetlink.h>
> +
> +/* RX frame types */
> +#define RSI_RESULT_CONFIRM 0x80
> +#define RSI_BT_PER 0x10
> +#define RSI_BT_BER 0x11
> +#define RSI_BT_CW 0x12
> +
> +#define RSI_HEADROOM_FOR_BT_HAL 16
> +
> +enum bt_fsm_state {
> + RSI_BT_FSM_DEVICE_NOT_READY = 0,
> + RSI_BT_FSM_DEVICE_READY,
> +};
> +
> +struct rsi_hci_adapter {
> + void *priv;
> + struct rsi_proto_ops *proto_ops;
> + enum bt_fsm_state fsm_state;
> + struct hci_dev *hdev;
> +};

If they are btrsi.c specific, they should be in btrsi.c and not in a header file.

> +
> +#define RSI_FRAME_DESC_SIZE 16
> +
> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
> +void rsi_hci_detach(void *priv);
> +int rsi_hci_recv_pkt(void *data, u8 *pkt);

And this is the part I do not get. What is the deal with the rsi_bt_ops. Having both exported is pointless.

Regards

Marcel

2017-11-16 05:16:30

by Amitkumar Karwar

[permalink] [raw]
Subject: Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver

On Wed, Nov 15, 2017 at 9:07 PM, Marcel Holtmann <[email protected]> wrot=
e:
> Hi Amitkumar,
>
>> Redpine bluetooth driver is a thin driver which depends on
>> 'rsi_91x' driver for transmitting and receiving packets
>> to/from device. It creates hci interface when attach() is
>> called from 'rsi_91x' module.
>>
>> Signed-off-by: Prameela Rani Garnepudi <[email protected]>
>> Signed-off-by: Siva Rebbagondla <[email protected]>
>> Signed-off-by: Amitkumar Karwar <[email protected]>
>> ---
>> drivers/bluetooth/Kconfig | 12 ++
>> drivers/bluetooth/Makefile | 2 +
>> drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++++++++++++=
++++++
>> drivers/bluetooth/rsi_hci.h | 51 +++++++++
>> 4 files changed, 333 insertions(+)
>> create mode 100644 drivers/bluetooth/btrsi.c
>> create mode 100644 drivers/bluetooth/rsi_hci.h
>>
>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>> index 60e1c7d..ca58d74 100644
>> --- a/drivers/bluetooth/Kconfig
>> +++ b/drivers/bluetooth/Kconfig
>> @@ -378,4 +378,16 @@ config BT_QCOMSMD
>> Say Y here to compile support for HCI over Qualcomm SMD into the
>> kernel or say M to compile as a module.
>>
>> +config BT_RSI
>> + tristate "Redpine HCI support"
>> + depends on BT && BT_RFCOMM
>
> the depends on BT_RFCOMM is wrong. And even the depends on BT is unneeded=
since that is already covered with the above menu clause.
>
>
>> + default m
>
> No. New drivers are by default off.
>
>> + help
>> + Redpine BT driver.
>> + This driver handles BT traffic from upper layers and pass
>> + to the RSI_91x coex module for further scheduling to device
>> +
>> + Say Y here to compile support for HCI over Qualcomm SMD into the
>> + kernel or say M to compile as a module.
>> +
>
> What I am missing is the depends on the RSI core piece that is needed.
>
>> endmenu
>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>> index 4e4e44d..712af83a 100644
>> --- a/drivers/bluetooth/Makefile
>> +++ b/drivers/bluetooth/Makefile
>> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) +=3D btqca.o
>>
>> obj-$(CONFIG_BT_HCIUART_NOKIA) +=3D hci_nokia.o
>>
>> +obj-$(CONFIG_BT_RSI) +=3D btrsi.o
>> +
>> btmrvl-y :=3D btmrvl_main.o
>> btmrvl-$(CONFIG_DEBUG_FS) +=3D btmrvl_debugfs.o
>>
>> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
>> new file mode 100644
>> index 0000000..c52f418
>> --- /dev/null
>> +++ b/drivers/bluetooth/btrsi.c
>> @@ -0,0 +1,268 @@
>> +/**
>> + * Copyright (c) 2017 Redpine Signals Inc.
>> + *
>> + * Permission to use, copy, modify, and/or distribute this software for=
any
>> + * purpose with or without fee is hereby granted, provided that the abo=
ve
>> + * copyright notice and this permission notice appear in all copies.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRAN=
TIES
>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE =
FOR
>> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAG=
ES
>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN A=
N
>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT=
OF
>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +#include <linux/version.h>
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include "rsi_hci.h"
>> +
>> +static struct rsi_mod_ops rsi_bt_ops =3D {
>> + .attach =3D rsi_hci_attach,
>> + .detach =3D rsi_hci_detach,
>> + .recv_pkt =3D rsi_hci_recv_pkt,
>> +};
>> +
>> +static int rsi_hci_open(struct hci_dev *hdev)
>> +{
>> + BT_INFO("%s open\n", hdev->name);
>
> No BT_INFO here. We are not spamming dmesg with pointless information. An=
d this applies to all of these.
>
>> +
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_close(struct hci_dev *hdev)
>> +{
>> + BT_INFO("%s closed\n", hdev->name);
>> +
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_flush(struct hci_dev *hdev)
>> +{
>> + BT_ERR("%s flush\n", hdev->name);
>> +
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
>> +{
>> + struct rsi_hci_adapter *h_adapter;
>
> =3D hci_get_drvdata(dev);
>
> There is no need to do that separate.
>
>> + struct sk_buff *new_skb =3D NULL;
>> +
>> + int status =3D 0;
>> +
>> + h_adapter =3D hci_get_drvdata(hdev);
>> + if (!h_adapter) {
>> + status =3D -EFAULT;
>> + goto fail;
>> + }
>
> And this error check seems unneeded since the Bluetooth core will never c=
all ->send unless it is all correctly set up.
>
>> +
>> + if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>> + BT_INFO("BT Device not ready\n");
>> + status =3D -ENODEV;
>> + goto fail;
>> + }
>
> Why are we registering a HCI device that might not be ready. This will be=
a massive bug in the whole system. Also one that is not recoverable. If so=
mething goes wrong, then lets unregister the HCI device.
>
>> +
>> + if (!test_bit(HCI_RUNNING, &hdev->flags)) {
>> + status =3D -EBUSY;
>> + goto fail;
>> + }
>
> This should no longer be needed. We moved this into the core and besides =
some old USB drivers, nobody is using this anymore.
>
>> +
>> + switch (bt_cb(skb)->pkt_type) {
>> + case HCI_COMMAND_PKT:
>> + hdev->stat.cmd_tx++;
>> + break;
>> +
>> + case HCI_ACLDATA_PKT:
>> + hdev->stat.acl_tx++;
>> + break;
>> +
>> + case HCI_SCODATA_PKT:
>> + hdev->stat.sco_tx++;
>> + break;
>> +
>> + default:
>> + dev_kfree_skb(skb);
>
> Don=E2=80=99t use dev_kfree_skb() here. I think the Bluetooth subsystem i=
s not ready for that.
>
>> + status =3D -EILSEQ;
>> + goto fail;
>> + }
>> +
>> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>> + /* Re-allocate one more skb with sufficent headroom */
>> + /* Space for Descriptor (16 bytes) is required in head roo=
m */
>> + u16 new_len =3D skb->len + RSI_HEADROOM_FOR_BT_HAL;
>> +
>> + new_skb =3D dev_alloc_skb(new_len);
>> + if (!new_skb) {
>> + dev_kfree_skb(skb);
>> + return -ENOMEM;
>> + }
>> + skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
>> + skb_put(new_skb, skb->len);
>> + memcpy(new_skb->data, skb->data, skb->len);
>> + bt_cb(new_skb)->pkt_type =3D bt_cb(skb)->pkt_type;
>> + dev_kfree_skb(skb);
>> + skb =3D new_skb;
>
> Just allocate a new skb with proper headroom. The data part can be shared=
. Doing this fully manual is just a bad idea.
>
> I also get the feeling that long term we want to change the Bluetooth dri=
vers to specify the required SKB headroom so that they always get SKBs that=
are large enough for their needs.
>
>> + }
>> + if (h_adapter->proto_ops->coex_send_pkt)
>> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv=
, skb,
>> + RSI_BT_Q);
>
> This is worrisome. You need to send. If this callback is not available, t=
hen better not register the HCI device at all.
>
>> +
>> +fail:
>> + dev_kfree_skb(skb);
>> + return status;
>> +}
>> +
>> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
>> +{
>> + struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)pr=
iv;
>> + struct hci_dev *hdev =3D NULL;
>> + struct sk_buff *skb;
>> + int pkt_len =3D (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
>> + u8 queue_no =3D (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
>
> We have get_unaligned_le16 helpers for this.
>
>> +
>> + if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>> + BT_INFO("BT Device not ready\n");
>> + return 0;
>> + }
>
> Why call this function if the device is not ready? Can that not be checke=
d and the HCI device not be registered.
>
>> +
>> + if (queue_no =3D=3D RSI_BT_MGMT_Q) {
>> + u8 msg_type =3D pkt[14] & 0xFF;
>> +
>> + switch (msg_type) {
>> + case RSI_RESULT_CONFIRM:
>> + BT_INFO("BT Result Confirm\n");
>> + return 0;
>> + case RSI_BT_BER:
>> + BT_INFO("BT Ber\n");
>> + return 0;
>> + case RSI_BT_CW:
>> + BT_INFO("BT CW\n");
>> + return 0;
>> + default:
>> + break;
>> + }
>> + }
>
> How noisy is this? Also no \n required for the BT_INFO functions. And her=
e bt_dev_info is preferred anyway.
>
>> +
>> + skb =3D dev_alloc_skb(pkt_len);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + hdev =3D h_adapter->hdev;
>> + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
>> + skb_put(skb, pkt_len);
>> + h_adapter->hdev->stat.byte_rx +=3D skb->len;
>> +
>> + skb->dev =3D (void *)hdev;
>> + bt_cb(skb)->pkt_type =3D pkt[14];
>> +
>> + return hci_recv_frame(hdev, skb);
>> +}
>> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
>> +
>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
>> +{
>> + struct rsi_hci_adapter *h_adapter =3D NULL;
>> + struct hci_dev *hdev;
>> + int status =3D 0;
>> +
>> + h_adapter =3D kzalloc(sizeof(*h_adapter), GFP_KERNEL);
>> + if (!h_adapter)
>> + return -ENOMEM;
>> +
>> + h_adapter->priv =3D priv;
>> + ops->set_bt_context(priv, h_adapter);
>> + h_adapter->proto_ops =3D ops;
>> + ops->bt_ops =3D &rsi_bt_ops;
>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>> +
>> + hdev =3D hci_alloc_dev();
>> + if (!hdev) {
>> + BT_ERR("Failed to alloc HCI device\n");
>> + goto err;
>> + }
>> + h_adapter->hdev =3D hdev;
>> +
>> + if (ops->get_host_intf(priv) =3D=3D RSI_HOST_INTF_SDIO)
>> + hdev->bus =3D HCI_SDIO;
>> + else
>> + hdev->bus =3D HCI_USB;
>> +
>> + hci_set_drvdata(hdev, h_adapter);
>> + hdev->dev_type =3D HCI_PRIMARY;
>> + hdev->open =3D rsi_hci_open;
>> + hdev->close =3D rsi_hci_close;
>> + hdev->flush =3D rsi_hci_flush;
>> + hdev->send =3D rsi_hci_send_pkt;
>> +
>> + status =3D hci_register_dev(hdev);
>> + if (status < 0) {
>> + BT_ERR("%s: HCI registration failed with errcode %d\n",
>> + __func__, status);
>> + goto err;
>> + }
>> +
>> + BT_INFO("%s interface created\n", hdev->name);
>> +
>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>> +
>> + return 0;
>> +
>> +err:
>> + if (hdev) {
>> + hci_unregister_dev(hdev);
>> + hci_free_dev(hdev);
>> + h_adapter->hdev =3D NULL;
>> + }
>> + kfree(h_adapter);
>> +
>> + return -EINVAL;
>> +}
>> +
>> +void rsi_hci_detach(void *priv)
>> +{
>> + struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)pr=
iv;
>> + struct hci_dev *hdev;
>> +
>> + if (!h_adapter)
>> + return;
>> +
>> + hdev =3D h_adapter->hdev;
>> +
>> + BT_INFO("Detaching %s\n", hdev->name);
>> +
>> + if (hdev) {
>> + hci_unregister_dev(hdev);
>> + hci_free_dev(hdev);
>> + h_adapter->hdev =3D NULL;
>> + }
>> +
>> + kfree(h_adapter);
>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_NOT_READY;
>> +}
>> +
>> +struct rsi_mod_ops *rsi_get_hci_ops(void)
>> +{
>> + return &rsi_bt_ops;
>> +};
>> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
>> +
>> +static int rsi_91x_bt_module_init(void)
>> +{
>> + BT_INFO("%s: BT Module init called\n", __func__);
>> +
>> + return 0;
>> +}
>> +
>> +static void rsi_91x_bt_module_exit(void)
>> +{
>> + BT_INFO("%s: BT Module exit called\n", __func__);
>> +}
>> +
>> +module_init(rsi_91x_bt_module_init);
>> +module_exit(rsi_91x_bt_module_exit);
>> +MODULE_AUTHOR("Redpine Signals Inc");
>> +MODULE_DESCRIPTION("RSI BT driver");
>> +MODULE_SUPPORTED_DEVICE("RSI-BT");
>> +MODULE_LICENSE("Dual BSD/GPL");
>> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
>> new file mode 100644
>> index 0000000..6f44231
>> --- /dev/null
>> +++ b/drivers/bluetooth/rsi_hci.h
>> @@ -0,0 +1,51 @@
>> +/**
>> + * Copyright (c) 2017 Redpine Signals Inc.
>> + *
>> + * Permission to use, copy, modify, and/or distribute this software for=
any
>> + * purpose with or without fee is hereby granted, provided that the abo=
ve
>> + * copyright notice and this permission notice appear in all copies.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRAN=
TIES
>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE =
FOR
>> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAG=
ES
>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN A=
N
>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT=
OF
>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef __RSI_HCI_H__
>> +#define __RSI_HCI_H__
>> +
>> +#include <net/bluetooth/bluetooth.h>
>> +#include <net/bluetooth/hci_core.h>
>> +#include <linux/rsi_header.h>
>> +#include <net/genetlink.h>
>> +
>> +/* RX frame types */
>> +#define RSI_RESULT_CONFIRM 0x80
>> +#define RSI_BT_PER 0x10
>> +#define RSI_BT_BER 0x11
>> +#define RSI_BT_CW 0x12
>> +
>> +#define RSI_HEADROOM_FOR_BT_HAL 16
>> +
>> +enum bt_fsm_state {
>> + RSI_BT_FSM_DEVICE_NOT_READY =3D 0,
>> + RSI_BT_FSM_DEVICE_READY,
>> +};
>> +
>> +struct rsi_hci_adapter {
>> + void *priv;
>> + struct rsi_proto_ops *proto_ops;
>> + enum bt_fsm_state fsm_state;
>> + struct hci_dev *hdev;
>> +};
>
> If they are btrsi.c specific, they should be in btrsi.c and not in a head=
er file.
>
>> +
>> +#define RSI_FRAME_DESC_SIZE 16
>> +
>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
>> +void rsi_hci_detach(void *priv);
>> +int rsi_hci_recv_pkt(void *data, u8 *pkt);
>
> And this is the part I do not get. What is the deal with the rsi_bt_ops. =
Having both exported is pointless.

Thanks for your review.
We will prepare updated version which addresses these comments.

Regards,
Amitkumar Karwar

2017-11-15 15:23:51

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 2/8] rsi: add bluetooth rx endpoint

Hi Amitkumar,

> USB endpoint 1 is used for WLAN which is presently in use.
> USB endpoint 2 is introduced for BT Rx traffic. Enumeration
> of Rx BT endpoint and submitting Rx BT URB are added.

wouldn’t it be good to include the /sys/kernel/debug/usb/devices part here that shows how the USB device’s layout.

Regards

Marcel

2017-11-15 07:28:31

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 3/8] rsi: add header file rsi_header

From: Prameela Rani Garnepudi <[email protected]>

The common parameters used by wlan and bt modules are added
to a new header file "rsi_header.h" defined in '/include/linux'

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_main.h | 12 ++----------
include/linux/rsi_header.h | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+), 10 deletions(-)
create mode 100644 include/linux/rsi_header.h

diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index ee469dc..ca02a4b 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -20,6 +20,7 @@
#include <linux/string.h>
#include <linux/skbuff.h>
#include <net/mac80211.h>
+#include <linux/rsi_header.h>

struct rsi_sta {
struct ieee80211_sta *sta;
@@ -85,10 +86,6 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define MGMT_HW_Q 10
#define BEACON_HW_Q 11

-/* Queue information */
-#define RSI_COEX_Q 0x0
-#define RSI_WIFI_MGMT_Q 0x4
-#define RSI_WIFI_DATA_Q 0x5
#define IEEE80211_MGMT_FRAME 0x00
#define IEEE80211_CTL_FRAME 0x04

@@ -293,11 +290,6 @@ struct rsi_common {
struct ieee80211_vif *roc_vif;
};

-enum host_intf {
- RSI_HOST_INTF_SDIO = 0,
- RSI_HOST_INTF_USB
-};
-
struct eepromrw_info {
u32 offset;
u32 length;
@@ -322,7 +314,7 @@ struct rsi_hw {
struct device *device;
u8 sc_nvifs;

- enum host_intf rsi_host_intf;
+ enum rsi_host_intf rsi_host_intf;
u16 block_size;
enum ps_state ps_state;
struct rsi_ps_info ps_info;
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
new file mode 100644
index 0000000..16a447b
--- /dev/null
+++ b/include/linux/rsi_header.h
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_HEADER_H__
+#define __RSI_HEADER_H__
+
+/* HAL queue information */
+#define RSI_COEX_Q 0x0
+#define RSI_BT_Q 0x2
+#define RSI_WLAN_Q 0x3
+#define RSI_WIFI_MGMT_Q 0x4
+#define RSI_WIFI_DATA_Q 0x5
+#define RSI_BT_MGMT_Q 0x6
+#define RSI_BT_DATA_Q 0x7
+
+enum rsi_host_intf {
+ RSI_HOST_INTF_SDIO = 0,
+ RSI_HOST_INTF_USB
+};
+
+#endif
--
2.7.4

2017-11-15 07:28:40

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver

From: Prameela Rani Garnepudi <[email protected]>

Redpine bluetooth driver is a thin driver which depends on
'rsi_91x' driver for transmitting and receiving packets
to/from device. It creates hci interface when attach() is
called from 'rsi_91x' module.

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/bluetooth/Kconfig | 12 ++
drivers/bluetooth/Makefile | 2 +
drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/rsi_hci.h | 51 +++++++++
4 files changed, 333 insertions(+)
create mode 100644 drivers/bluetooth/btrsi.c
create mode 100644 drivers/bluetooth/rsi_hci.h

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 60e1c7d..ca58d74 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -378,4 +378,16 @@ config BT_QCOMSMD
Say Y here to compile support for HCI over Qualcomm SMD into the
kernel or say M to compile as a module.

+config BT_RSI
+ tristate "Redpine HCI support"
+ depends on BT && BT_RFCOMM
+ default m
+ help
+ Redpine BT driver.
+ This driver handles BT traffic from upper layers and pass
+ to the RSI_91x coex module for further scheduling to device
+
+ Say Y here to compile support for HCI over Qualcomm SMD into the
+ kernel or say M to compile as a module.
+
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 4e4e44d..712af83a 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) += btqca.o

obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o

+obj-$(CONFIG_BT_RSI) += btrsi.o
+
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o

diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
new file mode 100644
index 0000000..c52f418
--- /dev/null
+++ b/drivers/bluetooth/btrsi.c
@@ -0,0 +1,268 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include "rsi_hci.h"
+
+static struct rsi_mod_ops rsi_bt_ops = {
+ .attach = rsi_hci_attach,
+ .detach = rsi_hci_detach,
+ .recv_pkt = rsi_hci_recv_pkt,
+};
+
+static int rsi_hci_open(struct hci_dev *hdev)
+{
+ BT_INFO("%s open\n", hdev->name);
+
+ return 0;
+}
+
+static int rsi_hci_close(struct hci_dev *hdev)
+{
+ BT_INFO("%s closed\n", hdev->name);
+
+ return 0;
+}
+
+static int rsi_hci_flush(struct hci_dev *hdev)
+{
+ BT_ERR("%s flush\n", hdev->name);
+
+ return 0;
+}
+
+static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct rsi_hci_adapter *h_adapter;
+ struct sk_buff *new_skb = NULL;
+
+ int status = 0;
+
+ h_adapter = hci_get_drvdata(hdev);
+ if (!h_adapter) {
+ status = -EFAULT;
+ goto fail;
+ }
+
+ if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
+ BT_INFO("BT Device not ready\n");
+ status = -ENODEV;
+ goto fail;
+ }
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ status = -EBUSY;
+ goto fail;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+
+ default:
+ dev_kfree_skb(skb);
+ status = -EILSEQ;
+ goto fail;
+ }
+
+ if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
+ /* Re-allocate one more skb with sufficent headroom */
+ /* Space for Descriptor (16 bytes) is required in head room */
+ u16 new_len = skb->len + RSI_HEADROOM_FOR_BT_HAL;
+
+ new_skb = dev_alloc_skb(new_len);
+ if (!new_skb) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+ skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
+ skb_put(new_skb, skb->len);
+ memcpy(new_skb->data, skb->data, skb->len);
+ bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
+ dev_kfree_skb(skb);
+ skb = new_skb;
+ }
+ if (h_adapter->proto_ops->coex_send_pkt)
+ return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
+ RSI_BT_Q);
+
+fail:
+ dev_kfree_skb(skb);
+ return status;
+}
+
+int rsi_hci_recv_pkt(void *priv, u8 *pkt)
+{
+ struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
+ struct hci_dev *hdev = NULL;
+ struct sk_buff *skb;
+ int pkt_len = (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
+ u8 queue_no = (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
+
+ if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
+ BT_INFO("BT Device not ready\n");
+ return 0;
+ }
+
+ if (queue_no == RSI_BT_MGMT_Q) {
+ u8 msg_type = pkt[14] & 0xFF;
+
+ switch (msg_type) {
+ case RSI_RESULT_CONFIRM:
+ BT_INFO("BT Result Confirm\n");
+ return 0;
+ case RSI_BT_BER:
+ BT_INFO("BT Ber\n");
+ return 0;
+ case RSI_BT_CW:
+ BT_INFO("BT CW\n");
+ return 0;
+ default:
+ break;
+ }
+ }
+
+ skb = dev_alloc_skb(pkt_len);
+ if (!skb)
+ return -ENOMEM;
+
+ hdev = h_adapter->hdev;
+ memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
+ skb_put(skb, pkt_len);
+ h_adapter->hdev->stat.byte_rx += skb->len;
+
+ skb->dev = (void *)hdev;
+ bt_cb(skb)->pkt_type = pkt[14];
+
+ return hci_recv_frame(hdev, skb);
+}
+EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
+
+int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
+{
+ struct rsi_hci_adapter *h_adapter = NULL;
+ struct hci_dev *hdev;
+ int status = 0;
+
+ h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL);
+ if (!h_adapter)
+ return -ENOMEM;
+
+ h_adapter->priv = priv;
+ ops->set_bt_context(priv, h_adapter);
+ h_adapter->proto_ops = ops;
+ ops->bt_ops = &rsi_bt_ops;
+ h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ BT_ERR("Failed to alloc HCI device\n");
+ goto err;
+ }
+ h_adapter->hdev = hdev;
+
+ if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO)
+ hdev->bus = HCI_SDIO;
+ else
+ hdev->bus = HCI_USB;
+
+ hci_set_drvdata(hdev, h_adapter);
+ hdev->dev_type = HCI_PRIMARY;
+ hdev->open = rsi_hci_open;
+ hdev->close = rsi_hci_close;
+ hdev->flush = rsi_hci_flush;
+ hdev->send = rsi_hci_send_pkt;
+
+ status = hci_register_dev(hdev);
+ if (status < 0) {
+ BT_ERR("%s: HCI registration failed with errcode %d\n",
+ __func__, status);
+ goto err;
+ }
+
+ BT_INFO("%s interface created\n", hdev->name);
+
+ h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
+
+ return 0;
+
+err:
+ if (hdev) {
+ hci_unregister_dev(hdev);
+ hci_free_dev(hdev);
+ h_adapter->hdev = NULL;
+ }
+ kfree(h_adapter);
+
+ return -EINVAL;
+}
+
+void rsi_hci_detach(void *priv)
+{
+ struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
+ struct hci_dev *hdev;
+
+ if (!h_adapter)
+ return;
+
+ hdev = h_adapter->hdev;
+
+ BT_INFO("Detaching %s\n", hdev->name);
+
+ if (hdev) {
+ hci_unregister_dev(hdev);
+ hci_free_dev(hdev);
+ h_adapter->hdev = NULL;
+ }
+
+ kfree(h_adapter);
+ h_adapter->fsm_state = RSI_BT_FSM_DEVICE_NOT_READY;
+}
+
+struct rsi_mod_ops *rsi_get_hci_ops(void)
+{
+ return &rsi_bt_ops;
+};
+EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
+
+static int rsi_91x_bt_module_init(void)
+{
+ BT_INFO("%s: BT Module init called\n", __func__);
+
+ return 0;
+}
+
+static void rsi_91x_bt_module_exit(void)
+{
+ BT_INFO("%s: BT Module exit called\n", __func__);
+}
+
+module_init(rsi_91x_bt_module_init);
+module_exit(rsi_91x_bt_module_exit);
+MODULE_AUTHOR("Redpine Signals Inc");
+MODULE_DESCRIPTION("RSI BT driver");
+MODULE_SUPPORTED_DEVICE("RSI-BT");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
new file mode 100644
index 0000000..6f44231
--- /dev/null
+++ b/drivers/bluetooth/rsi_hci.h
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_HCI_H__
+#define __RSI_HCI_H__
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <linux/rsi_header.h>
+#include <net/genetlink.h>
+
+/* RX frame types */
+#define RSI_RESULT_CONFIRM 0x80
+#define RSI_BT_PER 0x10
+#define RSI_BT_BER 0x11
+#define RSI_BT_CW 0x12
+
+#define RSI_HEADROOM_FOR_BT_HAL 16
+
+enum bt_fsm_state {
+ RSI_BT_FSM_DEVICE_NOT_READY = 0,
+ RSI_BT_FSM_DEVICE_READY,
+};
+
+struct rsi_hci_adapter {
+ void *priv;
+ struct rsi_proto_ops *proto_ops;
+ enum bt_fsm_state fsm_state;
+ struct hci_dev *hdev;
+};
+
+#define RSI_FRAME_DESC_SIZE 16
+
+int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
+void rsi_hci_detach(void *priv);
+int rsi_hci_recv_pkt(void *data, u8 *pkt);
+
+#endif
--
2.7.4

2017-11-15 07:28:27

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 2/8] rsi: add bluetooth rx endpoint

From: Siva Rebbagondla <[email protected]>

USB endpoint 1 is used for WLAN which is presently in use.
USB endpoint 2 is introduced for BT Rx traffic. Enumeration
of Rx BT endpoint and submitting Rx BT URB are added.

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_usb.c | 37 ++++++++++++++++++++--------------
drivers/net/wireless/rsi/rsi_usb.h | 6 +++---
2 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 147fcee2..b212a15 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -103,41 +103,42 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
__le16 buffer_size;
- int ii, bep_found = 0;
+ int ii, bin_found = 0, bout_found = 0;

iface_desc = &(interface->altsetting[0]);

for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) {
endpoint = &(iface_desc->endpoint[ii].desc);

- if ((!(dev->bulkin_endpoint_addr)) &&
+ if (!dev->bulkin_endpoint_addr[bin_found] &&
(endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes &
- USB_ENDPOINT_XFERTYPE_MASK) ==
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK)) {
buffer_size = endpoint->wMaxPacketSize;
- dev->bulkin_size = buffer_size;
- dev->bulkin_endpoint_addr =
+ dev->bulkin_size[bin_found] = buffer_size;
+ dev->bulkin_endpoint_addr[bin_found] =
endpoint->bEndpointAddress;
+ bin_found++;
}

- if (!dev->bulkout_endpoint_addr[bep_found] &&
+ if (!dev->bulkout_endpoint_addr[bout_found] &&
!(endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_BULK)) {
- dev->bulkout_endpoint_addr[bep_found] =
+ USB_ENDPOINT_XFER_BULK)) {
+ buffer_size = endpoint->wMaxPacketSize;
+ dev->bulkout_endpoint_addr[bout_found] =
endpoint->bEndpointAddress;
buffer_size = endpoint->wMaxPacketSize;
- dev->bulkout_size[bep_found] = buffer_size;
- bep_found++;
+ dev->bulkout_size[bout_found] = buffer_size;
+ bout_found++;
}

- if (bep_found >= MAX_BULK_EP)
+ if (bin_found >= MAX_BULK_EP || bout_found >= MAX_BULK_EP)
break;
}

- if (!(dev->bulkin_endpoint_addr) &&
- (dev->bulkout_endpoint_addr[0]))
+ if (!(dev->bulkin_endpoint_addr[0]) &&
+ dev->bulkout_endpoint_addr[0])
return -EINVAL;

return 0;
@@ -273,7 +274,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
usb_fill_bulk_urb(urb,
dev->usbdev,
usb_rcvbulkpipe(dev->usbdev,
- dev->bulkin_endpoint_addr),
+ dev->bulkin_endpoint_addr[ep_num - 1]),
urb->transfer_buffer,
3000,
rsi_rx_done_handler,
@@ -745,6 +746,12 @@ static int rsi_probe(struct usb_interface *pfunction,
if (status)
goto err1;

+ if (adapter->priv->coex_mode > 1) {
+ status = rsi_rx_urb_submit(adapter, BT_EP);
+ if (status)
+ goto err1;
+ }
+
return 0;
err1:
rsi_deinit_usb_interface(adapter);
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index 7e781d5..0fda14c 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -31,7 +31,7 @@
#define USB_VENDOR_REGISTER_WRITE 0x16
#define RSI_USB_TX_HEAD_ROOM 128

-#define MAX_RX_URBS 1
+#define MAX_RX_URBS 2
#define MAX_BULK_EP 8
#define WLAN_EP 1
#define BT_EP 2
@@ -54,8 +54,8 @@ struct rsi_91x_usbdev {
struct usb_interface *pfunction;
struct rx_usb_ctrl_block rx_cb[MAX_RX_URBS];
u8 *tx_buffer;
- __le16 bulkin_size;
- u8 bulkin_endpoint_addr;
+ __le16 bulkin_size[MAX_BULK_EP];
+ u8 bulkin_endpoint_addr[MAX_BULK_EP];
__le16 bulkout_size[MAX_BULK_EP];
u8 bulkout_endpoint_addr[MAX_BULK_EP];
u32 tx_blk_size;
--
2.7.4

2017-11-29 12:49:48

by Amitkumar Karwar

[permalink] [raw]
Subject: Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver

On Wed, Nov 15, 2017 at 9:07 PM, Marcel Holtmann <[email protected]> wrot=
e:
> Hi Amitkumar,
>
>> Redpine bluetooth driver is a thin driver which depends on
>> 'rsi_91x' driver for transmitting and receiving packets
>> to/from device. It creates hci interface when attach() is
>> called from 'rsi_91x' module.
>>
>> Signed-off-by: Prameela Rani Garnepudi <[email protected]>
>> Signed-off-by: Siva Rebbagondla <[email protected]>
>> Signed-off-by: Amitkumar Karwar <[email protected]>
>> ---
>> drivers/bluetooth/Kconfig | 12 ++
>> drivers/bluetooth/Makefile | 2 +
>> drivers/bluetooth/btrsi.c | 268 ++++++++++++++++++++++++++++++++++++++=
++++++
>> drivers/bluetooth/rsi_hci.h | 51 +++++++++
>> 4 files changed, 333 insertions(+)
>> create mode 100644 drivers/bluetooth/btrsi.c
>> create mode 100644 drivers/bluetooth/rsi_hci.h
>>
>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>> index 60e1c7d..ca58d74 100644
>> --- a/drivers/bluetooth/Kconfig
>> +++ b/drivers/bluetooth/Kconfig
>> @@ -378,4 +378,16 @@ config BT_QCOMSMD
>> Say Y here to compile support for HCI over Qualcomm SMD into the
>> kernel or say M to compile as a module.
>>
>> +config BT_RSI
>> + tristate "Redpine HCI support"
>> + depends on BT && BT_RFCOMM
>
> the depends on BT_RFCOMM is wrong. And even the depends on BT is unneeded=
since that is already covered with the above menu clause.
>
>
>> + default m
>
> No. New drivers are by default off.

We made it by default on, as RSI core module depends on this.

>
>> + help
>> + Redpine BT driver.
>> + This driver handles BT traffic from upper layers and pass
>> + to the RSI_91x coex module for further scheduling to device
>> +
>> + Say Y here to compile support for HCI over Qualcomm SMD into the
>> + kernel or say M to compile as a module.
>> +
>
> What I am missing is the depends on the RSI core piece that is needed.

Actually RSI core module depends on RSI BT module as per our design.
As soon as firmware is downloaded by RSI core module, we get WLAN and
BT card ready frames from firmware. BT initialization has to happen at
this point. So btrsi module should be loaded first.

>
>> endmenu
>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>> index 4e4e44d..712af83a 100644
>> --- a/drivers/bluetooth/Makefile
>> +++ b/drivers/bluetooth/Makefile
>> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) +=3D btqca.o
>>
>> obj-$(CONFIG_BT_HCIUART_NOKIA) +=3D hci_nokia.o
>>
>> +obj-$(CONFIG_BT_RSI) +=3D btrsi.o
>> +
>> btmrvl-y :=3D btmrvl_main.o
>> btmrvl-$(CONFIG_DEBUG_FS) +=3D btmrvl_debugfs.o
>>
>> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
>> new file mode 100644
>> index 0000000..c52f418
>> --- /dev/null
>> +++ b/drivers/bluetooth/btrsi.c
>> @@ -0,0 +1,268 @@
>> +/**
>> + * Copyright (c) 2017 Redpine Signals Inc.
>> + *
>> + * Permission to use, copy, modify, and/or distribute this software for=
any
>> + * purpose with or without fee is hereby granted, provided that the abo=
ve
>> + * copyright notice and this permission notice appear in all copies.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRAN=
TIES
>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE =
FOR
>> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAG=
ES
>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN A=
N
>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT=
OF
>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +#include <linux/version.h>
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include "rsi_hci.h"
>> +
>> +static struct rsi_mod_ops rsi_bt_ops =3D {
>> + .attach =3D rsi_hci_attach,
>> + .detach =3D rsi_hci_detach,
>> + .recv_pkt =3D rsi_hci_recv_pkt,
>> +};
>> +
>> +static int rsi_hci_open(struct hci_dev *hdev)
>> +{
>> + BT_INFO("%s open\n", hdev->name);
>
> No BT_INFO here. We are not spamming dmesg with pointless information. An=
d this applies to all of these.
>
>> +
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_close(struct hci_dev *hdev)
>> +{
>> + BT_INFO("%s closed\n", hdev->name);
>> +
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_flush(struct hci_dev *hdev)
>> +{
>> + BT_ERR("%s flush\n", hdev->name);
>> +
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
>> +{
>> + struct rsi_hci_adapter *h_adapter;
>
> =3D hci_get_drvdata(dev);
>
> There is no need to do that separate.
>
>> + struct sk_buff *new_skb =3D NULL;
>> +
>> + int status =3D 0;
>> +
>> + h_adapter =3D hci_get_drvdata(hdev);
>> + if (!h_adapter) {
>> + status =3D -EFAULT;
>> + goto fail;
>> + }
>
> And this error check seems unneeded since the Bluetooth core will never c=
all ->send unless it is all correctly set up.
>
>> +
>> + if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>> + BT_INFO("BT Device not ready\n");
>> + status =3D -ENODEV;
>> + goto fail;
>> + }
>
> Why are we registering a HCI device that might not be ready. This will be=
a massive bug in the whole system. Also one that is not recoverable. If so=
mething goes wrong, then lets unregister the HCI device.
>
>> +
>> + if (!test_bit(HCI_RUNNING, &hdev->flags)) {
>> + status =3D -EBUSY;
>> + goto fail;
>> + }
>
> This should no longer be needed. We moved this into the core and besides =
some old USB drivers, nobody is using this anymore.
>
>> +
>> + switch (bt_cb(skb)->pkt_type) {
>> + case HCI_COMMAND_PKT:
>> + hdev->stat.cmd_tx++;
>> + break;
>> +
>> + case HCI_ACLDATA_PKT:
>> + hdev->stat.acl_tx++;
>> + break;
>> +
>> + case HCI_SCODATA_PKT:
>> + hdev->stat.sco_tx++;
>> + break;
>> +
>> + default:
>> + dev_kfree_skb(skb);
>
> Don=E2=80=99t use dev_kfree_skb() here. I think the Bluetooth subsystem i=
s not ready for that.
>
>> + status =3D -EILSEQ;
>> + goto fail;
>> + }
>> +
>> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>> + /* Re-allocate one more skb with sufficent headroom */
>> + /* Space for Descriptor (16 bytes) is required in head roo=
m */
>> + u16 new_len =3D skb->len + RSI_HEADROOM_FOR_BT_HAL;
>> +
>> + new_skb =3D dev_alloc_skb(new_len);
>> + if (!new_skb) {
>> + dev_kfree_skb(skb);
>> + return -ENOMEM;
>> + }
>> + skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
>> + skb_put(new_skb, skb->len);
>> + memcpy(new_skb->data, skb->data, skb->len);
>> + bt_cb(new_skb)->pkt_type =3D bt_cb(skb)->pkt_type;
>> + dev_kfree_skb(skb);
>> + skb =3D new_skb;
>
> Just allocate a new skb with proper headroom. The data part can be shared=
. Doing this fully manual is just a bad idea.
>
> I also get the feeling that long term we want to change the Bluetooth dri=
vers to specify the required SKB headroom so that they always get SKBs that=
are large enough for their needs.
>
>> + }
>> + if (h_adapter->proto_ops->coex_send_pkt)
>> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv=
, skb,
>> + RSI_BT_Q);
>
> This is worrisome. You need to send. If this callback is not available, t=
hen better not register the HCI device at all.
>
>> +
>> +fail:
>> + dev_kfree_skb(skb);
>> + return status;
>> +}
>> +
>> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
>> +{
>> + struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)pr=
iv;
>> + struct hci_dev *hdev =3D NULL;
>> + struct sk_buff *skb;
>> + int pkt_len =3D (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
>> + u8 queue_no =3D (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
>
> We have get_unaligned_le16 helpers for this.
>
>> +
>> + if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>> + BT_INFO("BT Device not ready\n");
>> + return 0;
>> + }
>
> Why call this function if the device is not ready? Can that not be checke=
d and the HCI device not be registered.
>
>> +
>> + if (queue_no =3D=3D RSI_BT_MGMT_Q) {
>> + u8 msg_type =3D pkt[14] & 0xFF;
>> +
>> + switch (msg_type) {
>> + case RSI_RESULT_CONFIRM:
>> + BT_INFO("BT Result Confirm\n");
>> + return 0;
>> + case RSI_BT_BER:
>> + BT_INFO("BT Ber\n");
>> + return 0;
>> + case RSI_BT_CW:
>> + BT_INFO("BT CW\n");
>> + return 0;
>> + default:
>> + break;
>> + }
>> + }
>
> How noisy is this? Also no \n required for the BT_INFO functions. And her=
e bt_dev_info is preferred anyway.
>
>> +
>> + skb =3D dev_alloc_skb(pkt_len);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + hdev =3D h_adapter->hdev;
>> + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
>> + skb_put(skb, pkt_len);
>> + h_adapter->hdev->stat.byte_rx +=3D skb->len;
>> +
>> + skb->dev =3D (void *)hdev;
>> + bt_cb(skb)->pkt_type =3D pkt[14];
>> +
>> + return hci_recv_frame(hdev, skb);
>> +}
>> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
>> +
>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
>> +{
>> + struct rsi_hci_adapter *h_adapter =3D NULL;
>> + struct hci_dev *hdev;
>> + int status =3D 0;
>> +
>> + h_adapter =3D kzalloc(sizeof(*h_adapter), GFP_KERNEL);
>> + if (!h_adapter)
>> + return -ENOMEM;
>> +
>> + h_adapter->priv =3D priv;
>> + ops->set_bt_context(priv, h_adapter);
>> + h_adapter->proto_ops =3D ops;
>> + ops->bt_ops =3D &rsi_bt_ops;
>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>> +
>> + hdev =3D hci_alloc_dev();
>> + if (!hdev) {
>> + BT_ERR("Failed to alloc HCI device\n");
>> + goto err;
>> + }
>> + h_adapter->hdev =3D hdev;
>> +
>> + if (ops->get_host_intf(priv) =3D=3D RSI_HOST_INTF_SDIO)
>> + hdev->bus =3D HCI_SDIO;
>> + else
>> + hdev->bus =3D HCI_USB;
>> +
>> + hci_set_drvdata(hdev, h_adapter);
>> + hdev->dev_type =3D HCI_PRIMARY;
>> + hdev->open =3D rsi_hci_open;
>> + hdev->close =3D rsi_hci_close;
>> + hdev->flush =3D rsi_hci_flush;
>> + hdev->send =3D rsi_hci_send_pkt;
>> +
>> + status =3D hci_register_dev(hdev);
>> + if (status < 0) {
>> + BT_ERR("%s: HCI registration failed with errcode %d\n",
>> + __func__, status);
>> + goto err;
>> + }
>> +
>> + BT_INFO("%s interface created\n", hdev->name);
>> +
>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>> +
>> + return 0;
>> +
>> +err:
>> + if (hdev) {
>> + hci_unregister_dev(hdev);
>> + hci_free_dev(hdev);
>> + h_adapter->hdev =3D NULL;
>> + }
>> + kfree(h_adapter);
>> +
>> + return -EINVAL;
>> +}
>> +
>> +void rsi_hci_detach(void *priv)
>> +{
>> + struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)pr=
iv;
>> + struct hci_dev *hdev;
>> +
>> + if (!h_adapter)
>> + return;
>> +
>> + hdev =3D h_adapter->hdev;
>> +
>> + BT_INFO("Detaching %s\n", hdev->name);
>> +
>> + if (hdev) {
>> + hci_unregister_dev(hdev);
>> + hci_free_dev(hdev);
>> + h_adapter->hdev =3D NULL;
>> + }
>> +
>> + kfree(h_adapter);
>> + h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_NOT_READY;
>> +}
>> +
>> +struct rsi_mod_ops *rsi_get_hci_ops(void)
>> +{
>> + return &rsi_bt_ops;
>> +};
>> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
>> +
>> +static int rsi_91x_bt_module_init(void)
>> +{
>> + BT_INFO("%s: BT Module init called\n", __func__);
>> +
>> + return 0;
>> +}
>> +
>> +static void rsi_91x_bt_module_exit(void)
>> +{
>> + BT_INFO("%s: BT Module exit called\n", __func__);
>> +}
>> +
>> +module_init(rsi_91x_bt_module_init);
>> +module_exit(rsi_91x_bt_module_exit);
>> +MODULE_AUTHOR("Redpine Signals Inc");
>> +MODULE_DESCRIPTION("RSI BT driver");
>> +MODULE_SUPPORTED_DEVICE("RSI-BT");
>> +MODULE_LICENSE("Dual BSD/GPL");
>> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
>> new file mode 100644
>> index 0000000..6f44231
>> --- /dev/null
>> +++ b/drivers/bluetooth/rsi_hci.h
>> @@ -0,0 +1,51 @@
>> +/**
>> + * Copyright (c) 2017 Redpine Signals Inc.
>> + *
>> + * Permission to use, copy, modify, and/or distribute this software for=
any
>> + * purpose with or without fee is hereby granted, provided that the abo=
ve
>> + * copyright notice and this permission notice appear in all copies.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRAN=
TIES
>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE =
FOR
>> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAG=
ES
>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN A=
N
>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT=
OF
>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef __RSI_HCI_H__
>> +#define __RSI_HCI_H__
>> +
>> +#include <net/bluetooth/bluetooth.h>
>> +#include <net/bluetooth/hci_core.h>
>> +#include <linux/rsi_header.h>
>> +#include <net/genetlink.h>
>> +
>> +/* RX frame types */
>> +#define RSI_RESULT_CONFIRM 0x80
>> +#define RSI_BT_PER 0x10
>> +#define RSI_BT_BER 0x11
>> +#define RSI_BT_CW 0x12
>> +
>> +#define RSI_HEADROOM_FOR_BT_HAL 16
>> +
>> +enum bt_fsm_state {
>> + RSI_BT_FSM_DEVICE_NOT_READY =3D 0,
>> + RSI_BT_FSM_DEVICE_READY,
>> +};
>> +
>> +struct rsi_hci_adapter {
>> + void *priv;
>> + struct rsi_proto_ops *proto_ops;
>> + enum bt_fsm_state fsm_state;
>> + struct hci_dev *hdev;
>> +};
>
> If they are btrsi.c specific, they should be in btrsi.c and not in a head=
er file.
>
>> +
>> +#define RSI_FRAME_DESC_SIZE 16
>> +
>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
>> +void rsi_hci_detach(void *priv);
>> +int rsi_hci_recv_pkt(void *data, u8 *pkt);
>
> And this is the part I do not get. What is the deal with the rsi_bt_ops. =
Having both exported is pointless.

rsi core module initializes rsi_bt_ops by calling exported function
rsi_get_hci_ops().

Regards,
Amitkumar

2017-11-15 07:28:23

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 1/8] rsi: add rx control block to handle rx packets in USB

From: Prameela Rani Garnepudi <[email protected]>

Rx bluetooth endpoint shall be added in further patches. Rx control
block is introduced here to handle Rx packets properly. Separate
function is written to initialize the RX control blocks.

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_main.c | 4 +-
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 2 +-
drivers/net/wireless/rsi/rsi_91x_usb.c | 75 +++++++++++++++++++++++------
drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 35 +++++++++-----
drivers/net/wireless/rsi/rsi_common.h | 2 +-
drivers/net/wireless/rsi/rsi_main.h | 2 +-
drivers/net/wireless/rsi/rsi_usb.h | 10 +++-
7 files changed, 96 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 0cb8e68..0413af8 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -137,7 +137,7 @@ static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
*
* Return: 0 on success, -1 on failure.
*/
-int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
+int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
{
u8 *frame_desc = NULL, extended_desc = 0;
u32 index, length = 0, queueno = 0;
@@ -146,7 +146,7 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)

index = 0;
do {
- frame_desc = &common->rx_data_pkt[index];
+ frame_desc = &rx_pkt[index];
actual_length = *(u16 *)&frame_desc[0];
offset = *(u16 *)&frame_desc[2];

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 8e2a95c..9fbc0ef 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -118,7 +118,7 @@ static int rsi_process_pkt(struct rsi_common *common)
goto fail;
}

- status = rsi_read_pkt(common, rcv_pkt_len);
+ status = rsi_read_pkt(common, common->rx_data_pkt, rcv_pkt_len);

fail:
kfree(common->rx_data_pkt);
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 0873022..147fcee2 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -247,12 +247,13 @@ static int rsi_usb_reg_write(struct usb_device *usbdev,
*/
static void rsi_rx_done_handler(struct urb *urb)
{
- struct rsi_hw *adapter = urb->context;
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rx_usb_ctrl_block *rx_cb = urb->context;
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data;

if (urb->status)
return;

+ rx_cb->pend = 1;
rsi_set_event(&dev->rx_thread.event);
}

@@ -262,10 +263,11 @@ static void rsi_rx_done_handler(struct urb *urb)
*
* Return: 0 on success, a negative error code on failure.
*/
-static int rsi_rx_urb_submit(struct rsi_hw *adapter)
+static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
{
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
- struct urb *urb = dev->rx_usb_urb[0];
+ struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1];
+ struct urb *urb = rx_cb->rx_urb;
int status;

usb_fill_bulk_urb(urb,
@@ -275,7 +277,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter)
urb->transfer_buffer,
3000,
rsi_rx_done_handler,
- adapter);
+ rx_cb);

status = usb_submit_urb(urb, GFP_KERNEL);
if (status)
@@ -484,14 +486,54 @@ static struct rsi_host_intf_ops usb_host_intf_ops = {
*/
static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
{
+ u8 idx;
+
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;

rsi_kill_thread(&dev->rx_thread);
- usb_free_urb(dev->rx_usb_urb[0]);
+
+ for (idx = 0; idx < MAX_RX_URBS; idx++) {
+ usb_free_urb(dev->rx_cb[idx].rx_urb);
+ kfree(dev->rx_cb[idx].rx_buffer);
+ }
+
kfree(adapter->priv->rx_data_pkt);
kfree(dev->tx_buffer);
}

+static int rsi_usb_init_rx(struct rsi_hw *adapter)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rx_usb_ctrl_block *rx_cb;
+ u8 idx;
+
+ for (idx = 0; idx < MAX_RX_URBS; idx++) {
+ rx_cb = &dev->rx_cb[idx];
+
+ rx_cb->rx_buffer = kzalloc(RSI_USB_BUF_SIZE * 2,
+ GFP_KERNEL | GFP_DMA);
+ if (!rx_cb->rx_buffer)
+ goto err;
+
+ rx_cb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rx_cb->rx_urb) {
+ rsi_dbg(ERR_ZONE, "Failed alloc rx urb[%d]\n", idx);
+ goto err;
+ }
+ rx_cb->rx_urb->transfer_buffer = rx_cb->rx_buffer;
+ rx_cb->ep_num = idx + 1;
+ rx_cb->data = (void *)dev;
+ }
+ return 0;
+
+err:
+ for (idx = 0; idx < MAX_RX_URBS; idx++) {
+ kfree(dev->rx_cb[idx].rx_buffer);
+ kfree(dev->rx_cb[idx].rx_urb);
+ }
+ return -1;
+}
+
/**
* rsi_init_usb_interface() - This function initializes the usb interface.
* @adapter: Pointer to the adapter structure.
@@ -504,7 +546,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
{
struct rsi_91x_usbdev *rsi_dev;
struct rsi_common *common = adapter->priv;
- int status;
+ int status, i;

rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL);
if (!rsi_dev)
@@ -531,12 +573,12 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
status = -ENOMEM;
goto fail_tx;
}
- rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL);
- if (!rsi_dev->rx_usb_urb[0]) {
- status = -ENOMEM;
- goto fail_rx;
+
+ if (rsi_usb_init_rx(adapter)) {
+ rsi_dbg(ERR_ZONE, "Failed to init RX handle\n");
+ return -ENOMEM;
}
- rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt;
+
rsi_dev->tx_blk_size = 252;
adapter->block_size = rsi_dev->tx_blk_size;

@@ -564,9 +606,10 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
return 0;

fail_thread:
- usb_free_urb(rsi_dev->rx_usb_urb[0]);
-fail_rx:
- kfree(rsi_dev->tx_buffer);
+ for (i = 0; i < MAX_RX_URBS; i++) {
+ kfree(rsi_dev->rx_cb[i].rx_buffer);
+ kfree(rsi_dev->rx_cb[i].rx_urb);
+ }
fail_tx:
kfree(common->rx_data_pkt);
return status;
@@ -698,7 +741,7 @@ static int rsi_probe(struct usb_interface *pfunction,
rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__);
}

- status = rsi_rx_urb_submit(adapter);
+ status = rsi_rx_urb_submit(adapter, WLAN_EP);
if (status)
goto err1;

diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
index 465692b..d0650ea 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
@@ -29,7 +29,8 @@ void rsi_usb_rx_thread(struct rsi_common *common)
{
struct rsi_hw *adapter = common->priv;
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
- int status;
+ struct rx_usb_ctrl_block *rx_cb;
+ int status, idx;

do {
rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER);
@@ -37,20 +38,30 @@ void rsi_usb_rx_thread(struct rsi_common *common)
if (atomic_read(&dev->rx_thread.thread_done))
goto out;

- mutex_lock(&common->rx_lock);
- status = rsi_read_pkt(common, 0);
- if (status) {
- rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__);
+ for (idx = 0; idx < MAX_RX_URBS; idx++) {
+ rx_cb = &dev->rx_cb[idx];
+ if (!rx_cb->pend)
+ continue;
+
+ mutex_lock(&common->rx_lock);
+ status = rsi_read_pkt(common, rx_cb->rx_buffer, 0);
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Failed To read data",
+ __func__);
+ mutex_unlock(&common->rx_lock);
+ break;
+ }
+ rx_cb->pend = 0;
mutex_unlock(&common->rx_lock);
- return;
+
+ if (adapter->rx_urb_submit(adapter, rx_cb->ep_num)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed in urb submission",
+ __func__);
+ return;
+ }
}
- mutex_unlock(&common->rx_lock);
rsi_reset_event(&dev->rx_thread.event);
- if (adapter->rx_urb_submit(adapter)) {
- rsi_dbg(ERR_ZONE,
- "%s: Failed in urb submission", __func__);
- return;
- }
} while (1);

out:
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index d07dbba..1d8af41 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -82,7 +82,7 @@ void rsi_mac80211_detach(struct rsi_hw *hw);
u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
struct rsi_hw *rsi_91x_init(void);
void rsi_91x_deinit(struct rsi_hw *adapter);
-int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len);
+int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len);
#ifdef CONFIG_PM
int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan);
#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 8cab630..ee469dc 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -343,7 +343,7 @@ struct rsi_hw {
void *rsi_dev;
struct rsi_host_intf_ops *host_intf_ops;
int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num);
- int (*rx_urb_submit)(struct rsi_hw *adapter);
+ int (*rx_urb_submit)(struct rsi_hw *adapter, u8 ep_num);
int (*determine_event_timeout)(struct rsi_hw *adapter);
};

diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index 891daea..7e781d5 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -39,12 +39,20 @@
#define RSI_USB_BUF_SIZE 4096
#define RSI_USB_CTRL_BUF_SIZE 0x04

+struct rx_usb_ctrl_block {
+ u8 *data;
+ struct urb *rx_urb;
+ u8 *rx_buffer;
+ u8 ep_num;
+ u8 pend;
+};
+
struct rsi_91x_usbdev {
struct rsi_thread rx_thread;
u8 endpoint;
struct usb_device *usbdev;
struct usb_interface *pfunction;
- struct urb *rx_usb_urb[MAX_RX_URBS];
+ struct rx_usb_ctrl_block rx_cb[MAX_RX_URBS];
u8 *tx_buffer;
__le16 bulkin_size;
u8 bulkin_endpoint_addr;
--
2.7.4

2017-11-15 07:28:52

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 8/8] rsi: sdio changes to support BT

From: Prameela Rani Garnepudi <[email protected]>

Queue number is correctly updated for BT traffic. Also, kzalloc
instead of kmalloc is used for Rx packet allocation.

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 ++
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 5722736..beb18d0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -763,6 +763,8 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
int status;

queueno = ((pkt[1] >> 4) & 0xf);
+ if (queueno == RSI_BT_MGMT_Q || queueno == RSI_BT_DATA_Q)
+ queueno = RSI_BT_Q;

num_blocks = len / block_size;

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 26abe51..83652bd 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -103,7 +103,7 @@ static int rsi_process_pkt(struct rsi_common *common)

rcv_pkt_len = (num_blks * 256);

- common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL);
+ common->rx_data_pkt = kzalloc(rcv_pkt_len, GFP_KERNEL);
if (!common->rx_data_pkt) {
rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n",
__func__);
--
2.7.4

2017-11-15 07:28:48

by Amitkumar Karwar

[permalink] [raw]
Subject: [PATCH 7/8] rsi: add module parameter operating mode

From: Prameela Rani Garnepudi <[email protected]>

Operating mode determines the support for other protocols.
This is made as module parameter for better usage.

Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_main.c | 58 ++++++++++++++++++++++++++++-----
drivers/net/wireless/rsi/rsi_91x_sdio.c | 10 +++++-
drivers/net/wireless/rsi/rsi_91x_usb.c | 10 +++++-
drivers/net/wireless/rsi/rsi_common.h | 2 +-
drivers/net/wireless/rsi/rsi_hal.h | 11 +++++++
5 files changed, 80 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 00f54c5..084b779 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -69,8 +69,24 @@ EXPORT_SYMBOL_GPL(rsi_dbg);
static char *opmode_str(int oper_mode)
{
switch (oper_mode) {
- case RSI_DEV_OPMODE_WIFI_ALONE:
+ case DEV_OPMODE_WIFI_ALONE:
return "Wi-Fi alone";
+ case DEV_OPMODE_BT_ALONE:
+ return "BT EDR alone";
+ case DEV_OPMODE_BT_LE_ALONE:
+ return "BT LE alone";
+ case DEV_OPMODE_BT_DUAL:
+ return "BT Dual";
+ case DEV_OPMODE_STA_BT:
+ return "Wi-Fi STA + BT EDR";
+ case DEV_OPMODE_STA_BT_LE:
+ return "Wi-Fi STA + BT LE";
+ case DEV_OPMODE_STA_BT_DUAL:
+ return "Wi-Fi STA + BT DUAL";
+ case DEV_OPMODE_AP_BT:
+ return "Wi-Fi AP + BT EDR";
+ case DEV_OPMODE_AP_BT_DUAL:
+ return "Wi-Fi AP + BT DUAL";
}

return "Unknown";
@@ -278,7 +294,7 @@ void *rsi_get_bt_context(void *priv)
*
* Return: Pointer to the adapter structure on success, NULL on failure .
*/
-struct rsi_hw *rsi_91x_init(void)
+struct rsi_hw *rsi_91x_init(u16 oper_mode)
{
struct rsi_hw *adapter = NULL;
struct rsi_common *common = NULL;
@@ -320,11 +336,34 @@ struct rsi_hw *rsi_91x_init(void)
spin_lock_init(&adapter->ps_lock);
timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
init_completion(&common->wlan_init_completion);
+ common->oper_mode = oper_mode;
common->init_done = true;
-
- common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
- common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
adapter->device_model = RSI_DEV_9113;
+
+ /* Determine coex mode */
+ switch (common->oper_mode) {
+ case DEV_OPMODE_STA_BT_DUAL:
+ case DEV_OPMODE_STA_BT:
+ case DEV_OPMODE_STA_BT_LE:
+ case DEV_OPMODE_BT_ALONE:
+ case DEV_OPMODE_BT_LE_ALONE:
+ case DEV_OPMODE_BT_DUAL:
+ common->coex_mode = 2;
+ break;
+ case DEV_OPMODE_AP_BT_DUAL:
+ case DEV_OPMODE_AP_BT:
+ common->coex_mode = 4;
+ break;
+ case DEV_OPMODE_WIFI_ALONE:
+ common->coex_mode = 1;
+ break;
+ default:
+ common->oper_mode = 1;
+ common->coex_mode = 1;
+ }
+ rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
+ __func__, common->oper_mode, common->coex_mode);
+
if (common->coex_mode > 1) {
if (rsi_coex_attach(common)) {
rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
@@ -359,10 +398,13 @@ void rsi_91x_deinit(struct rsi_hw *adapter)
for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
skb_queue_purge(&common->tx_queue[ii]);

- common->init_done = false;
-
- if (common->coex_mode > 1)
+ if (common->coex_mode > 1) {
rsi_coex_detach(common);
+ if (g_proto_ops.bt_ops->detach)
+ g_proto_ops.bt_ops->detach(common->bt_adapter);
+ }
+
+ common->init_done = false;

kfree(common);
kfree(adapter->rsi_dev);
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index ba38c6d..5722736 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -21,6 +21,14 @@
#include "rsi_coex.h"
#include "rsi_hal.h"

+/* Default operating mode is wlan STA + BT */
+static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
+module_param(dev_oper_mode, ushort, 0444);
+MODULE_PARM_DESC(dev_oper_mode,
+ "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
+ "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
+ "6[AP + BT classic], 14[AP + BT classic + BT LE]");
+
/**
* rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg.
* @rw: Read/write
@@ -926,7 +934,7 @@ static int rsi_probe(struct sdio_func *pfunction,

rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);

- adapter = rsi_91x_init();
+ adapter = rsi_91x_init(dev_oper_mode);
if (!adapter) {
rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
__func__);
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index b09c7da..a30305e 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -21,6 +21,14 @@
#include "rsi_hal.h"
#include "rsi_coex.h"

+/* Default operating mode is wlan STA + BT */
+static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
+module_param(dev_oper_mode, ushort, 0444);
+MODULE_PARM_DESC(dev_oper_mode,
+ "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
+ "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
+ "6[AP + BT classic], 14[AP + BT classic + BT LE]");
+
/**
* rsi_usb_card_write() - This function writes to the USB Card.
* @adapter: Pointer to the adapter structure.
@@ -708,7 +716,7 @@ static int rsi_probe(struct usb_interface *pfunction,

rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);

- adapter = rsi_91x_init();
+ adapter = rsi_91x_init(dev_oper_mode);
if (!adapter) {
rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
__func__);
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 4616585..d9ff3b8 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -81,7 +81,7 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)

void rsi_mac80211_detach(struct rsi_hw *hw);
u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
-struct rsi_hw *rsi_91x_init(void);
+struct rsi_hw *rsi_91x_init(u16 oper_mode);
void rsi_91x_deinit(struct rsi_hw *adapter);
int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len);
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
index e712223..a7d3011 100644
--- a/drivers/net/wireless/rsi/rsi_hal.h
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -17,6 +17,17 @@
#ifndef __RSI_HAL_H__
#define __RSI_HAL_H__

+/* Device Operating modes */
+#define DEV_OPMODE_WIFI_ALONE 1
+#define DEV_OPMODE_BT_ALONE 4
+#define DEV_OPMODE_BT_LE_ALONE 8
+#define DEV_OPMODE_BT_DUAL 12
+#define DEV_OPMODE_STA_BT 5
+#define DEV_OPMODE_STA_BT_LE 9
+#define DEV_OPMODE_STA_BT_DUAL 13
+#define DEV_OPMODE_AP_BT 6
+#define DEV_OPMODE_AP_BT_DUAL 14
+
#define FLASH_WRITE_CHUNK_SIZE (4 * 1024)
#define FLASH_SECTOR_SIZE (4 * 1024)

--
2.7.4