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.
Changes in v3: 5/8 and 6/8 patches are modified
Changes in v2: 2/8, 5/8 and 6/8 patches are modified
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 | 11 ++
drivers/bluetooth/Makefile | 2 +
drivers/bluetooth/btrsi.c | 211 ++++++++++++++++++++++++++++
drivers/bluetooth/rsi_hci.h | 40 ++++++
drivers/net/wireless/rsi/Kconfig | 2 +-
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 | 110 ++++++++++++++-
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 | 20 +--
drivers/net/wireless/rsi/rsi_mgmt.h | 3 +
drivers/net/wireless/rsi/rsi_usb.h | 16 ++-
include/linux/rsi_header.h | 56 ++++++++
22 files changed, 888 insertions(+), 83 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
On Fri, Dec 1, 2017 at 4:24 PM, Marcel Holtmann <[email protected]> wrote=
:
> 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]>
>> ---
>> v3: Made BT_RSI module by default off(Marcel)
>> Removed redundant exported function rsi_get_hci_ops()(Marcel)
>> v2: Addressed review comments from Marcel
>> Removed unnecessary 'depends on BT && BT_RFOMM' line in Kconfig
>> Removed redundant BT_INFO messages
>> h_adapter initialization and declaration in a single line.
>> Removed unnecessary error checks for HCI_RUNNING and fsm_state
>> Allocated new skb with skb_realloc_headroom() API if headroom is not =
sufficient
>> Used get_unaligned_le16 helpers
>> Moved a structure and union from header file to btrsi.c file
>> ---
>> drivers/bluetooth/Kconfig | 11 +++
>> drivers/bluetooth/Makefile | 2 +
>> drivers/bluetooth/btrsi.c | 211 ++++++++++++++++++++++++++++++++++++++=
++++++
>> drivers/bluetooth/rsi_hci.h | 40 +++++++++
>> include/linux/rsi_header.h | 2 +
>> 5 files changed, 266 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..33d7514 100644
>> --- a/drivers/bluetooth/Kconfig
>> +++ b/drivers/bluetooth/Kconfig
>> @@ -378,4 +378,15 @@ 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"
>> + default n
>> + 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 Redpine 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) +=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..71f6f4e
>> --- /dev/null
>> +++ b/drivers/bluetooth/btrsi.c
>> @@ -0,0 +1,211 @@
>> +/**
>> + * 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"
>> +
>> +struct rsi_hci_adapter {
>> + void *priv;
>> + struct rsi_proto_ops *proto_ops;
>> + struct hci_dev *hdev;
>> +};
>> +
>> +const 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,
>> +};
>> +EXPORT_SYMBOL(rsi_bt_ops);
>> +
>> +static int rsi_hci_open(struct hci_dev *hdev)
>> +{
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_close(struct hci_dev *hdev)
>> +{
>> + return 0;
>> +}
>> +
>> +static int rsi_hci_flush(struct hci_dev *hdev)
>> +{
>> + 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(hdev);
>> + struct sk_buff *new_skb =3D NULL;
>> +
>> + 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;
>> + }
>> +
>> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>> + /* Insufficient skb headroom - allocate a new skb */
>> + new_skb =3D skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_=
HAL);
>> + if (unlikely(!new_skb))
>> + return -ENOMEM;
>> + bt_cb(new_skb)->pkt_type =3D bt_cb(skb)->pkt_type;
>> + kfree_skb(skb);
>> + skb =3D new_skb;
>> + }
>> +
>> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
>> + RSI_BT_Q);
>> +}
>> +
>> +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 h_adapter->hdev;
>> + struct sk_buff *skb;
>> +
>> + int pkt_len =3D get_unaligned_le16(pkt) & 0x0fff;
>> + u8 queue_no =3D (get_unaligned_le16(pkt) & 0x7000) >> 12;
>> +
>> + if (queue_no =3D=3D RSI_BT_MGMT_Q) {
>> + u8 msg_type =3D pkt[14] & 0xFF;
>> +
>> + switch (msg_type) {
>> + case RSI_RESULT_CONFIRM:
>> + bt_dev_info(hdev, "BT Result Confirm");
>> + return 0;
>> + case RSI_BT_BER:
>> + bt_dev_info(hdev, "BT Ber");
>> + return 0;
>> + case RSI_BT_CW:
>> + bt_dev_info(hdev, "BT CW");
>> + return 0;
>> + default:
>> + break;
>> + }
>> + }
>> +
>> + skb =3D dev_alloc_skb(pkt_len);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + 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);
>> +}
>> +
>> +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;
>> +
>> + 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;
>> + }
>> +
>> + 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;
>> + if (hdev) {
>> + hci_unregister_dev(hdev);
>> + hci_free_dev(hdev);
>> + h_adapter->hdev =3D NULL;
>> + }
>> +
>> + kfree(h_adapter);
>> +}
>> +
>> +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..6fc7757
>> --- /dev/null
>> +++ b/drivers/bluetooth/rsi_hci.h
>> @@ -0,0 +1,40 @@
>> +/**
>> + * 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/unaligned/le_byteshift.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
>
> I still like to see changes to the BT core that allows the driver to spec=
ify how headroom it needs. This can be follow up patches, but we should do =
that since reallocating the SKBs all the time is also pointless.
Ok. I will prepare follow up patch for this.
>
>> +
>> +#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
>
> I have no idea why this header file is needed at all. Fold this into btrs=
i.c and make the rsi_hci_* functions static.
I will take care of this in v4.
>
>> diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
>> index 737ab4e..07d9574 100644
>> --- a/include/linux/rsi_header.h
>> +++ b/include/linux/rsi_header.h
>> @@ -51,4 +51,6 @@ struct rsi_mod_ops {
>> void (*detach)(void *priv);
>> int (*recv_pkt)(void *priv, u8 *msg);
>> };
>> +
>> +extern const struct rsi_mod_ops rsi_bt_ops;
>
> If you expose rsi_hci_attach via rsi_bt_ops, then there is no need for ma=
king rsi_hci_attach also public. I mentioned this in the first review as we=
ll. I do not get it. Either you expose rsi_bt_ops from this module or you e=
xpose the rsi_hci_* function, but both is totally pointless.
>
Got it. I will get rid of header file and make these functions static
Regards,
Amitkumar
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]>
> ---
> v3: Made BT_RSI module by default off(Marcel)
> Removed redundant exported function rsi_get_hci_ops()(Marcel)
> v2: Addressed review comments from Marcel
> Removed unnecessary 'depends on BT && BT_RFOMM' line in Kconfig
> Removed redundant BT_INFO messages
> h_adapter initialization and declaration in a single line.
> Removed unnecessary error checks for HCI_RUNNING and fsm_state
> Allocated new skb with skb_realloc_headroom() API if headroom is not sufficient
> Used get_unaligned_le16 helpers
> Moved a structure and union from header file to btrsi.c file
> ---
> drivers/bluetooth/Kconfig | 11 +++
> drivers/bluetooth/Makefile | 2 +
> drivers/bluetooth/btrsi.c | 211 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/rsi_hci.h | 40 +++++++++
> include/linux/rsi_header.h | 2 +
> 5 files changed, 266 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..33d7514 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -378,4 +378,15 @@ 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"
> + default n
> + 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 Redpine 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..71f6f4e
> --- /dev/null
> +++ b/drivers/bluetooth/btrsi.c
> @@ -0,0 +1,211 @@
> +/**
> + * 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"
> +
> +struct rsi_hci_adapter {
> + void *priv;
> + struct rsi_proto_ops *proto_ops;
> + struct hci_dev *hdev;
> +};
> +
> +const struct rsi_mod_ops rsi_bt_ops = {
> + .attach = rsi_hci_attach,
> + .detach = rsi_hci_detach,
> + .recv_pkt = rsi_hci_recv_pkt,
> +};
> +EXPORT_SYMBOL(rsi_bt_ops);
> +
> +static int rsi_hci_open(struct hci_dev *hdev)
> +{
> + return 0;
> +}
> +
> +static int rsi_hci_close(struct hci_dev *hdev)
> +{
> + return 0;
> +}
> +
> +static int rsi_hci_flush(struct hci_dev *hdev)
> +{
> + 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(hdev);
> + struct sk_buff *new_skb = NULL;
> +
> + 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;
> + }
> +
> + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
> + /* Insufficient skb headroom - allocate a new skb */
> + new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL);
> + if (unlikely(!new_skb))
> + return -ENOMEM;
> + bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
> + kfree_skb(skb);
> + skb = new_skb;
> + }
> +
> + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
> + RSI_BT_Q);
> +}
> +
> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
> +{
> + struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
> + struct hci_dev *hdev = h_adapter->hdev;
> + struct sk_buff *skb;
> +
> + int pkt_len = get_unaligned_le16(pkt) & 0x0fff;
> + u8 queue_no = (get_unaligned_le16(pkt) & 0x7000) >> 12;
> +
> + if (queue_no == RSI_BT_MGMT_Q) {
> + u8 msg_type = pkt[14] & 0xFF;
> +
> + switch (msg_type) {
> + case RSI_RESULT_CONFIRM:
> + bt_dev_info(hdev, "BT Result Confirm");
> + return 0;
> + case RSI_BT_BER:
> + bt_dev_info(hdev, "BT Ber");
> + return 0;
> + case RSI_BT_CW:
> + bt_dev_info(hdev, "BT CW");
> + return 0;
> + default:
> + break;
> + }
> + }
> +
> + skb = dev_alloc_skb(pkt_len);
> + if (!skb)
> + return -ENOMEM;
> +
> + 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);
> +}
> +
> +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;
> +
> + 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;
> + }
> +
> + 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;
> + if (hdev) {
> + hci_unregister_dev(hdev);
> + hci_free_dev(hdev);
> + h_adapter->hdev = NULL;
> + }
> +
> + kfree(h_adapter);
> +}
> +
> +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..6fc7757
> --- /dev/null
> +++ b/drivers/bluetooth/rsi_hci.h
> @@ -0,0 +1,40 @@
> +/**
> + * 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/unaligned/le_byteshift.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
I still like to see changes to the BT core that allows the driver to specify how headroom it needs. This can be follow up patches, but we should do that since reallocating the SKBs all the time is also pointless.
> +
> +#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
I have no idea why this header file is needed at all. Fold this into btrsi.c and make the rsi_hci_* functions static.
> diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
> index 737ab4e..07d9574 100644
> --- a/include/linux/rsi_header.h
> +++ b/include/linux/rsi_header.h
> @@ -51,4 +51,6 @@ struct rsi_mod_ops {
> void (*detach)(void *priv);
> int (*recv_pkt)(void *priv, u8 *msg);
> };
> +
> +extern const struct rsi_mod_ops rsi_bt_ops;
If you expose rsi_hci_attach via rsi_bt_ops, then there is no need for making rsi_hci_attach also public. I mentioned this in the first review as well. I do not get it. Either you expose rsi_bt_ops from this module or you expose the rsi_hci_* function, but both is totally pointless.
Regards
Marcel
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
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 | 57 ++++++++++++++++++++++++++++-----
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, 79 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 375b725..4a0f5a18 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -68,8 +68,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";
@@ -267,7 +283,7 @@ void rsi_set_bt_context(void *priv, void *bt_context)
*
* 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;
@@ -309,11 +325,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");
@@ -348,10 +387,12 @@ 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);
+ rsi_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
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: Siva Rebbagondla <[email protected]>
Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
v3: bt_ops need not be present structure g_proto_ops. It is removed.
v2: WLAN module depends on BT module. Updated in Kconfig
---
drivers/net/wireless/rsi/Kconfig | 2 +-
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 | 31 +++++++++++++++++++++++
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 | 3 +++
9 files changed, 100 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig
index 7c5e4ca..ad72c80 100644
--- a/drivers/net/wireless/rsi/Kconfig
+++ b/drivers/net/wireless/rsi/Kconfig
@@ -13,7 +13,7 @@ if WLAN_VENDOR_RSI
config RSI_91X
tristate "Redpine Signals Inc 91x WLAN driver support"
- depends on MAC80211
+ depends on MAC80211 && BT_RSI
---help---
This option enabes support for RSI 1x1 devices.
Select M (recommended), if you have a RSI 1x1 wireless module.
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..375b725 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,12 @@ 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,
+};
+
/**
* rsi_dbg() - This function outputs informational messages.
* @zone: Zone of interest for output message.
@@ -144,6 +151,7 @@ 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;
+ u8 bt_pkt_type;
index = 0;
do {
@@ -183,6 +191,22 @@ 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) {
+ rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
+ if (rsi_bt_ops.attach(common, &g_proto_ops))
+ rsi_dbg(ERR_ZONE,
+ "Failed to attach BT module\n");
+ } else {
+ rsi_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 +254,13 @@ 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;
+}
+
/**
* rsi_91x_init() - This function initializes os interface operations.
* @void: Void.
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..69a604e 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -290,6 +290,8 @@ struct rsi_common {
bool p2p_enabled;
struct timer_list roc_timer;
struct ieee80211_vif *roc_vif;
+
+ void *bt_adapter;
};
struct eepromrw_info {
@@ -363,5 +365,6 @@ 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);
#endif
--
2.7.4
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]>
---
v3: Made BT_RSI module by default off(Marcel)
Removed redundant exported function rsi_get_hci_ops()(Marcel)
v2: Addressed review comments from Marcel
Removed unnecessary 'depends on BT && BT_RFOMM' line in Kconfig
Removed redundant BT_INFO messages
h_adapter initialization and declaration in a single line.
Removed unnecessary error checks for HCI_RUNNING and fsm_state
Allocated new skb with skb_realloc_headroom() API if headroom is not sufficient
Used get_unaligned_le16 helpers
Moved a structure and union from header file to btrsi.c file
---
drivers/bluetooth/Kconfig | 11 +++
drivers/bluetooth/Makefile | 2 +
drivers/bluetooth/btrsi.c | 211 ++++++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/rsi_hci.h | 40 +++++++++
include/linux/rsi_header.h | 2 +
5 files changed, 266 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..33d7514 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -378,4 +378,15 @@ 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"
+ default n
+ 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 Redpine 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..71f6f4e
--- /dev/null
+++ b/drivers/bluetooth/btrsi.c
@@ -0,0 +1,211 @@
+/**
+ * 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"
+
+struct rsi_hci_adapter {
+ void *priv;
+ struct rsi_proto_ops *proto_ops;
+ struct hci_dev *hdev;
+};
+
+const struct rsi_mod_ops rsi_bt_ops = {
+ .attach = rsi_hci_attach,
+ .detach = rsi_hci_detach,
+ .recv_pkt = rsi_hci_recv_pkt,
+};
+EXPORT_SYMBOL(rsi_bt_ops);
+
+static int rsi_hci_open(struct hci_dev *hdev)
+{
+ return 0;
+}
+
+static int rsi_hci_close(struct hci_dev *hdev)
+{
+ return 0;
+}
+
+static int rsi_hci_flush(struct hci_dev *hdev)
+{
+ 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(hdev);
+ struct sk_buff *new_skb = NULL;
+
+ 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;
+ }
+
+ if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL);
+ if (unlikely(!new_skb))
+ return -ENOMEM;
+ bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
+ kfree_skb(skb);
+ skb = new_skb;
+ }
+
+ return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
+ RSI_BT_Q);
+}
+
+int rsi_hci_recv_pkt(void *priv, u8 *pkt)
+{
+ struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
+ struct hci_dev *hdev = h_adapter->hdev;
+ struct sk_buff *skb;
+
+ int pkt_len = get_unaligned_le16(pkt) & 0x0fff;
+ u8 queue_no = (get_unaligned_le16(pkt) & 0x7000) >> 12;
+
+ if (queue_no == RSI_BT_MGMT_Q) {
+ u8 msg_type = pkt[14] & 0xFF;
+
+ switch (msg_type) {
+ case RSI_RESULT_CONFIRM:
+ bt_dev_info(hdev, "BT Result Confirm");
+ return 0;
+ case RSI_BT_BER:
+ bt_dev_info(hdev, "BT Ber");
+ return 0;
+ case RSI_BT_CW:
+ bt_dev_info(hdev, "BT CW");
+ return 0;
+ default:
+ break;
+ }
+ }
+
+ skb = dev_alloc_skb(pkt_len);
+ if (!skb)
+ return -ENOMEM;
+
+ 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);
+}
+
+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;
+
+ 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;
+ }
+
+ 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;
+ if (hdev) {
+ hci_unregister_dev(hdev);
+ hci_free_dev(hdev);
+ h_adapter->hdev = NULL;
+ }
+
+ kfree(h_adapter);
+}
+
+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..6fc7757
--- /dev/null
+++ b/drivers/bluetooth/rsi_hci.h
@@ -0,0 +1,40 @@
+/**
+ * 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/unaligned/le_byteshift.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
+
+#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
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
index 737ab4e..07d9574 100644
--- a/include/linux/rsi_header.h
+++ b/include/linux/rsi_header.h
@@ -51,4 +51,6 @@ struct rsi_mod_ops {
void (*detach)(void *priv);
int (*recv_pkt)(void *priv, u8 *msg);
};
+
+extern const struct rsi_mod_ops rsi_bt_ops;
#endif
--
2.7.4
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 | 20 ++++
11 files changed, 291 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..737ab4e 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,27 @@
#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);
+};
+
+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
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
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.
>From /sys/kernel/debug/usb/devices,
Ad=81(I) is for WLAN EP IN and Ad=01(O) is for Wlan EP OUT.
Ad=82(I) is for BT EP IN and Ad=02(O) is for BT EP OUT.
T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=03 Dev#= 4 Spd=480 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=1618 ProdID=9113 Rev= 0.02
S: Manufacturer=Redpine Signals, Inc.
S: Product=Wireless USB Network Module
S: SerialNumber=000000000001
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr= 2mA
I:* If#= 0 Alt= 0 #EPs= 6 Cls=00(>ifc ) Sub=00 Prot=00 Driver=(none)
E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
Signed-off-by: Siva Rebbagondla <[email protected]>
Signed-off-by: Prameela Rani Garnepudi <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
v3: Same as v2
v2: Included '/sys/kernel/debug/usb/devices' info in patch description(Marcel)
---
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
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