From ace31982585a323afb194f56b9e0486f7bc6570c Mon Sep 17 00:00:00 2001 From: "Kim, Ben Young Tae" Date: Sun, 15 Feb 2015 23:06:14 +0000 Subject: Bluetooth: btusb: Add setup callback for chip init on USB Some of chipset does not allow to send a patch or config files through HCI VS channel at early stage as well as they don't support to send USB patch files to other channel except USB bulk path. New callback added is for initialization of BT controller through USB Signed-off-by: Ben Young Tae Kim Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3ca2e1bf7bfa..73e1066cd38b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -337,6 +337,8 @@ struct btusb_data { int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb); int (*recv_bulk)(struct btusb_data *data, void *buffer, int count); + + int (*setup_on_usb)(struct hci_dev *hdev); }; static inline void btusb_free_frags(struct btusb_data *data) @@ -878,6 +880,15 @@ static int btusb_open(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + /* Patching USB firmware files prior to starting any URBs of HCI path + * It is more safe to use USB bulk channel for downloading USB patch + */ + if (data->setup_on_usb) { + err = data->setup_on_usb(hdev); + if (err <0) + return err; + } + err = usb_autopm_get_interface(data->intf); if (err < 0) return err; -- cgit v1.2.3 From 3267c884cefa86c6d48c4d7c5571c20435271ecf Mon Sep 17 00:00:00 2001 From: "Kim, Ben Young Tae" Date: Sun, 15 Feb 2015 23:07:33 +0000 Subject: Bluetooth: btusb: Add support for QCA ROME chipset family This patch supports ROME Bluetooth family from Qualcomm Atheros, e.g. QCA61x4 or QCA6574. New chipset have similar firmware downloading sequences to previous chipset from Atheros, however, it doesn't support vid/pid switching after downloading the patch so that firmware needs to be handled by btusb module directly. ROME chipset can be differentiated from previous version by reading ROM version. T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 16 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e300 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 8 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e360 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Ben Young Tae Kim Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 73e1066cd38b..08330548f7fe 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -52,6 +52,7 @@ static struct usb_driver btusb_driver; #define BTUSB_SWAVE 0x1000 #define BTUSB_INTEL_NEW 0x2000 #define BTUSB_AMP 0x4000 +#define BTUSB_QCA_ROME 0x8000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -213,6 +214,10 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, + /* QCA ROME chipset */ + { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME}, + { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME}, + /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, @@ -2638,6 +2643,250 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev, return 0; } +#define QCA_DFU_PACKET_LEN 4096 + +#define QCA_GET_TARGET_VERSION 0x09 +#define QCA_CHECK_STATUS 0x05 +#define QCA_DFU_DOWNLOAD 0x01 + +#define QCA_SYSCFG_UPDATED 0x40 +#define QCA_PATCH_UPDATED 0x80 +#define QCA_DFU_TIMEOUT 3000 + +struct qca_version { + __le32 rom_version; + __le32 patch_version; + __le32 ram_version; + __le32 ref_clock; + __u8 reserved[4]; +} __packed; + +struct qca_rampatch_version { + __le16 rom_version; + __le16 patch_version; +} __packed; + +struct qca_device_info { + __le32 rom_version; + __u8 rampatch_hdr; /* length of header in rampatch */ + __u8 nvm_hdr; /* length of header in NVM */ + __u8 ver_offset; /* offset of version structure in rampatch */ +}; + +static const struct qca_device_info qca_devices_table[] = { + { 0x00000100, 20, 4, 10 }, /* Rome 1.0 */ + { 0x00000101, 20, 4, 10 }, /* Rome 1.1 */ + { 0x00000201, 28, 4, 18 }, /* Rome 2.1 */ + { 0x00000300, 28, 4, 18 }, /* Rome 3.0 */ + { 0x00000302, 28, 4, 18 }, /* Rome 3.2 */ +}; + +static int btusb_qca_send_vendor_req(struct hci_dev *hdev, u8 request, + void *data, u16 size) +{ + struct btusb_data *btdata = hci_get_drvdata(hdev); + struct usb_device *udev = btdata->udev; + int pipe, err; + u8 *buf; + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Found some of USB hosts have IOT issues with ours so that we should + * not wait until HCI layer is ready. + */ + pipe = usb_rcvctrlpipe(udev, 0); + err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN, + 0, 0, buf, size, USB_CTRL_SET_TIMEOUT); + if (err < 0) { + BT_ERR("%s: Failed to access otp area (%d)", hdev->name, err); + goto done; + } + + memcpy(data, buf, size); + +done: + kfree(buf); + + return err; +} + +static int btusb_setup_qca_download_fw(struct hci_dev *hdev, + const struct firmware *firmware, + size_t hdr_size) +{ + struct btusb_data *btdata = hci_get_drvdata(hdev); + struct usb_device *udev = btdata->udev; + size_t count, size, sent = 0; + int pipe, len, err; + u8 *buf; + + buf = kmalloc(QCA_DFU_PACKET_LEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + count = firmware->size; + + size = min_t(size_t, count, hdr_size); + memcpy(buf, firmware->data, size); + + /* USB patches should go down to controller through USB path + * because binary format fits to go down through USB channel. + * USB control path is for patching headers and USB bulk is for + * patch body. + */ + pipe = usb_sndctrlpipe(udev, 0); + err = usb_control_msg(udev, pipe, QCA_DFU_DOWNLOAD, USB_TYPE_VENDOR, + 0, 0, buf, size, USB_CTRL_SET_TIMEOUT); + if (err < 0) { + BT_ERR("%s: Failed to send headers (%d)", hdev->name, err); + goto done; + } + + sent += size; + count -= size; + + while (count) { + size = min_t(size_t, count, QCA_DFU_PACKET_LEN); + + memcpy(buf, firmware->data + sent, size); + + pipe = usb_sndbulkpipe(udev, 0x02); + err = usb_bulk_msg(udev, pipe, buf, size, &len, + QCA_DFU_TIMEOUT); + if (err < 0) { + BT_ERR("%s: Failed to send body at %zd of %zd (%d)", + hdev->name, sent, firmware->size, err); + break; + } + + if (size != len) { + BT_ERR("%s: Failed to get bulk buffer", hdev->name); + err = -EILSEQ; + break; + } + + sent += size; + count -= size; + } + +done: + kfree(buf); + return err; +} + +static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, + struct qca_version *ver, + const struct qca_device_info *info) +{ + struct qca_rampatch_version *rver; + const struct firmware *fw; + char fwname[64]; + int err; + + snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", + le32_to_cpu(ver->rom_version)); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err) { + BT_ERR("%s: failed to request rampatch file: %s (%d)", + hdev->name, fwname, err); + return err; + } + + BT_INFO("%s: using rampatch file: %s", hdev->name, fwname); + rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset); + BT_INFO("%s: QCA: patch rome 0x%x build 0x%x, firmware rome 0x%x " + "build 0x%x", hdev->name, le16_to_cpu(rver->rom_version), + le16_to_cpu(rver->patch_version), le32_to_cpu(ver->rom_version), + le32_to_cpu(ver->patch_version)); + + if (rver->rom_version != ver->rom_version || + rver->patch_version <= ver->patch_version) { + BT_ERR("%s: rampatch file version did not match with firmware", + hdev->name); + err = -EINVAL; + goto done; + } + + err = btusb_setup_qca_download_fw(hdev, fw, info->rampatch_hdr); + +done: + release_firmware(fw); + + return err; +} + +static int btusb_setup_qca_load_nvm(struct hci_dev *hdev, + struct qca_version *ver, + const struct qca_device_info *info) +{ + const struct firmware *fw; + char fwname[64]; + int err; + + snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin", + le32_to_cpu(ver->rom_version)); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err) { + BT_ERR("%s: failed to request NVM file: %s (%d)", + hdev->name, fwname, err); + return err; + } + + BT_INFO("%s: using NVM file: %s", hdev->name, fwname); + + err = btusb_setup_qca_download_fw(hdev, fw, info->nvm_hdr); + + release_firmware(fw); + + return err; +} + +static int btusb_setup_qca(struct hci_dev *hdev) +{ + const struct qca_device_info *info = NULL; + struct qca_version ver; + u8 status; + int i, err; + + err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver, + sizeof(ver)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) { + if (ver.rom_version == qca_devices_table[i].rom_version) + info = &qca_devices_table[i]; + } + if (!info) { + BT_ERR("%s: don't support firmware rome 0x%x", hdev->name, + le32_to_cpu(ver.rom_version)); + return -ENODEV; + } + + err = btusb_qca_send_vendor_req(hdev, QCA_CHECK_STATUS, &status, + sizeof(status)); + if (err < 0) + return err; + + if (!(status & QCA_PATCH_UPDATED)) { + err = btusb_setup_qca_load_rampatch(hdev, &ver, info); + if (err < 0) + return err; + } + + if (!(status & QCA_SYSCFG_UPDATED)) { + err = btusb_setup_qca_load_nvm(hdev, &ver, info); + if (err < 0) + return err; + } + + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -2791,6 +3040,11 @@ static int btusb_probe(struct usb_interface *intf, set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } + if (id->driver_info & BTUSB_QCA_ROME) { + data->setup_on_usb = btusb_setup_qca; + hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + } + if (id->driver_info & BTUSB_AMP) { /* AMP controllers do not support SCO packets */ data->isoc = NULL; -- cgit v1.2.3 From ba6d22393284b703e6174278c31858bf59337ed2 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:28 +0100 Subject: at86rf230: add transmit retry support This patch introduce a transmit retry handling into at86rf230 transmit path. Current behaviour is to wait the normal receive time if we want to go into STATE_TX_ON when the transceiver is in STATE_BUSY_RX_AACK which indicates that a frame is currently receiving. A non force state change will not interrupt the the receiving state. The current behaviour is that after the normal receive time we will start a force change into STATE_TX_ON. With this patch we do seven retries to go into STATE_TX_ON without forcing. After we hit the AT86RF2XX_MAX_TX_RETRIES we will start the force state change. This is a polling like method to go into STATE_TX_ON in times of maximum receiving time. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 1d438bc54189..503fabddd431 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -52,7 +52,13 @@ struct at86rf2xx_chip_data { int (*get_desense_steps)(struct at86rf230_local *, s32); }; -#define AT86RF2XX_MAX_BUF (127 + 3) +#define AT86RF2XX_MAX_BUF (127 + 3) +/* tx retries to access the TX_ON state + * if it's above then force change will be started. + * + * We assume the max_frame_retries (7) value of 802.15.4 here. + */ +#define AT86RF2XX_MAX_TX_RETRIES 7 struct at86rf230_state_change { struct at86rf230_local *lp; @@ -85,6 +91,7 @@ struct at86rf230_local { bool is_tx; /* spinlock for is_tx protection */ spinlock_t lock; + u8 tx_retry; struct sk_buff *tx_skb; struct at86rf230_state_change tx; }; @@ -512,10 +519,20 @@ at86rf230_async_state_assert(void *context) * in STATE_BUSY_RX_AACK, we run a force state change * to STATE_TX_ON. This is a timeout handling, if the * transceiver stucks in STATE_BUSY_RX_AACK. + * + * Additional we do several retries to try to get into + * TX_ON state without forcing. If the retries are + * higher or equal than AT86RF2XX_MAX_TX_RETRIES we + * will do a force change. */ if (ctx->to_state == STATE_TX_ON) { - at86rf230_async_state_change(lp, ctx, - STATE_FORCE_TX_ON, + u8 state = STATE_TX_ON; + + if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) + state = STATE_FORCE_TX_ON; + lp->tx_retry++; + + at86rf230_async_state_change(lp, ctx, state, ctx->complete, ctx->irq_enable); return; @@ -963,6 +980,7 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) if (lp->tx_aret) tx_complete = at86rf230_xmit_tx_on; + lp->tx_retry = 0; at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); return 0; -- cgit v1.2.3 From ef5428a1386d472939c763abc68a9d0f1fb18dce Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:29 +0100 Subject: at86rf230: cleanup and squash stack variable I had this variable because I thought it would be protected by disable/enable irq but this is not true. It's protected by stop/wake netdev queue which is called by ieee802154_xmit_complete. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 503fabddd431..85012201eaf5 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -725,11 +725,10 @@ at86rf230_tx_complete(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - struct sk_buff *skb = lp->tx_skb; enable_irq(lp->spi->irq); - ieee802154_xmit_complete(lp->hw, skb, !lp->tx_aret); + ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret); } static void -- cgit v1.2.3 From 74de4c804c53f612ef1287e4241d8d06f8e794c7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:30 +0100 Subject: at86rf230: refactor receive handling This patch refactor the receive handling into one function. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 85012201eaf5..8e93ea415149 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -781,13 +781,23 @@ at86rf230_tx_trac_status(void *context) } static void -at86rf230_rx(struct at86rf230_local *lp, - const u8 *data, const u8 len, const u8 lqi) +at86rf230_rx_read_frame_complete(void *context) { - struct sk_buff *skb; + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; u8 rx_local_buf[AT86RF2XX_MAX_BUF]; + const u8 *buf = lp->irq.buf; + struct sk_buff *skb; + u8 len, lqi; - memcpy(rx_local_buf, data, len); + len = buf[1]; + if (!ieee802154_is_valid_psdu_len(len)) { + dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); + len = IEEE802154_MTU; + } + lqi = buf[2 + len]; + + memcpy(rx_local_buf, buf + 2, len); enable_irq(lp->spi->irq); skb = dev_alloc_skb(IEEE802154_MTU); @@ -800,22 +810,6 @@ at86rf230_rx(struct at86rf230_local *lp, ieee802154_rx_irqsafe(lp->hw, skb, lqi); } -static void -at86rf230_rx_read_frame_complete(void *context) -{ - struct at86rf230_state_change *ctx = context; - struct at86rf230_local *lp = ctx->lp; - const u8 *buf = lp->irq.buf; - u8 len = buf[1]; - - if (!ieee802154_is_valid_psdu_len(len)) { - dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); - len = IEEE802154_MTU; - } - - at86rf230_rx(lp, buf + 2, len, buf[2 + len]); -} - static void at86rf230_rx_read_frame(struct at86rf230_local *lp) { -- cgit v1.2.3 From cca990c85d37a9ed42d2cac53c619abec7faa12f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:31 +0100 Subject: at86rf230: remove multiple dereferencing for irq By holding the irq variable inside at86rf230_state_change we can squash some multiple dereferencing for getting irq num. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 8e93ea415149..7f27fa35bde3 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -62,6 +62,7 @@ struct at86rf2xx_chip_data { struct at86rf230_state_change { struct at86rf230_local *lp; + int irq; struct spi_message msg; struct spi_transfer trx; @@ -483,7 +484,7 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, rc = spi_async(lp->spi, &ctx->msg); if (rc) { if (irq_enable) - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } @@ -667,7 +668,7 @@ at86rf230_async_state_change_start(void *context) rc = spi_async(lp->spi, &ctx->msg); if (rc) { if (ctx->irq_enable) - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } @@ -726,7 +727,7 @@ at86rf230_tx_complete(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret); } @@ -798,7 +799,7 @@ at86rf230_rx_read_frame_complete(void *context) lqi = buf[2 + len]; memcpy(rx_local_buf, buf + 2, len); - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); skb = dev_alloc_skb(IEEE802154_MTU); if (!skb) { @@ -811,8 +812,10 @@ at86rf230_rx_read_frame_complete(void *context) } static void -at86rf230_rx_read_frame(struct at86rf230_local *lp) +at86rf230_rx_read_frame(void *context) { + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; int rc; u8 *buf = lp->irq.buf; @@ -822,7 +825,7 @@ at86rf230_rx_read_frame(struct at86rf230_local *lp) lp->irq.msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &lp->irq.msg); if (rc) { - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); at86rf230_async_error(lp, &lp->irq, rc); } } @@ -830,16 +833,13 @@ at86rf230_rx_read_frame(struct at86rf230_local *lp) static void at86rf230_rx_trac_check(void *context) { - struct at86rf230_state_change *ctx = context; - struct at86rf230_local *lp = ctx->lp; - /* Possible check on trac status here. This could be useful to make * some stats why receive is failed. Not used at the moment, but it's * maybe timing relevant. Datasheet doesn't say anything about this. * The programming guide say do it so. */ - at86rf230_rx_read_frame(lp); + at86rf230_rx_read_frame(context); } static void @@ -878,7 +878,7 @@ at86rf230_irq_status(void *context) if (irq & IRQ_TRX_END) { at86rf230_irq_trx_end(lp); } else { - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); dev_err(&lp->spi->dev, "not supported irq %02x received\n", irq); } @@ -1539,6 +1539,7 @@ static void at86rf230_setup_spi_messages(struct at86rf230_local *lp) { lp->state.lp = lp; + lp->state.irq = lp->spi->irq; spi_message_init(&lp->state.msg); lp->state.msg.context = &lp->state; lp->state.trx.tx_buf = lp->state.buf; @@ -1546,6 +1547,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) spi_message_add_tail(&lp->state.trx, &lp->state.msg); lp->irq.lp = lp; + lp->irq.irq = lp->spi->irq; spi_message_init(&lp->irq.msg); lp->irq.msg.context = &lp->irq; lp->irq.trx.tx_buf = lp->irq.buf; @@ -1553,6 +1555,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); lp->tx.lp = lp; + lp->tx.irq = lp->spi->irq; spi_message_init(&lp->tx.msg); lp->tx.msg.context = &lp->tx; lp->tx.trx.tx_buf = lp->tx.buf; -- cgit v1.2.3 From 31fa74344c1e75fd66f7b43f456ae9e0a137ba69 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:32 +0100 Subject: at86rf230: remove multiple dereferencing for ctx This patch cleanups the referencing for the state change context variable. The state change context should only set once and this is by initial a state change. This patch will use the initial state change variable in the complete handler of the state change by using the ctx context which should be always the same like the initial state change context. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 7f27fa35bde3..216c80c3532c 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -738,7 +738,7 @@ at86rf230_tx_on(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, + at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, at86rf230_tx_complete, true); } @@ -787,7 +787,7 @@ at86rf230_rx_read_frame_complete(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 rx_local_buf[AT86RF2XX_MAX_BUF]; - const u8 *buf = lp->irq.buf; + const u8 *buf = ctx->buf; struct sk_buff *skb; u8 len, lqi; @@ -816,17 +816,16 @@ at86rf230_rx_read_frame(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; + u8 *buf = ctx->buf; int rc; - u8 *buf = lp->irq.buf; - buf[0] = CMD_FB; - lp->irq.trx.len = AT86RF2XX_MAX_BUF; - lp->irq.msg.complete = at86rf230_rx_read_frame_complete; - rc = spi_async(lp->spi, &lp->irq.msg); + ctx->trx.len = AT86RF2XX_MAX_BUF; + ctx->msg.complete = at86rf230_rx_read_frame_complete; + rc = spi_async(lp->spi, &ctx->msg); if (rc) { enable_irq(ctx->irq); - at86rf230_async_error(lp, &lp->irq, rc); + at86rf230_async_error(lp, ctx, rc); } } @@ -872,7 +871,7 @@ at86rf230_irq_status(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - const u8 *buf = lp->irq.buf; + const u8 *buf = ctx->buf; const u8 irq = buf[1]; if (irq & IRQ_TRX_END) { @@ -929,7 +928,7 @@ at86rf230_write_frame(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; struct sk_buff *skb = lp->tx_skb; - u8 *buf = lp->tx.buf; + u8 *buf = ctx->buf; int rc; spin_lock(&lp->lock); @@ -939,9 +938,9 @@ at86rf230_write_frame(void *context) buf[0] = CMD_FB | CMD_WRITE; buf[1] = skb->len + 2; memcpy(buf + 2, skb->data, skb->len); - lp->tx.trx.len = skb->len + 2; - lp->tx.msg.complete = at86rf230_write_frame_complete; - rc = spi_async(lp->spi, &lp->tx.msg); + ctx->trx.len = skb->len + 2; + ctx->msg.complete = at86rf230_write_frame_complete; + rc = spi_async(lp->spi, &ctx->msg); if (rc) at86rf230_async_error(lp, ctx, rc); } -- cgit v1.2.3 From 263be3326b89a1a4994b29cbe898637fd72e6f0b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:33 +0100 Subject: at86rf230: restore trx len when needed In the most cases the spi messages has a length of two. Currently we always set the the len field to two before transmit a spi message. In cases for read out/write in the frame buffer we need another len. This patch use trx len two as default. For the frame buffer cases we restore the trx len to two on success and failure. This will reduce the len setting of two when it's already two. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 216c80c3532c..088fa68f5098 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -478,7 +478,6 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, u8 *tx_buf = ctx->buf; tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; - ctx->trx.len = 2; ctx->msg.complete = complete; ctx->irq_enable = irq_enable; rc = spi_async(lp->spi, &ctx->msg); @@ -663,7 +662,6 @@ at86rf230_async_state_change_start(void *context) */ buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; buf[1] = ctx->to_state; - ctx->trx.len = 2; ctx->msg.complete = at86rf230_async_state_delay; rc = spi_async(lp->spi, &ctx->msg); if (rc) { @@ -799,6 +797,7 @@ at86rf230_rx_read_frame_complete(void *context) lqi = buf[2 + len]; memcpy(rx_local_buf, buf + 2, len); + ctx->trx.len = 2; enable_irq(ctx->irq); skb = dev_alloc_skb(IEEE802154_MTU); @@ -824,6 +823,7 @@ at86rf230_rx_read_frame(void *context) ctx->msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &ctx->msg); if (rc) { + ctx->trx.len = 2; enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } @@ -893,7 +893,6 @@ static irqreturn_t at86rf230_isr(int irq, void *data) disable_irq_nosync(irq); buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG; - ctx->trx.len = 2; ctx->msg.complete = at86rf230_irq_status; rc = spi_async(lp->spi, &ctx->msg); if (rc) { @@ -941,8 +940,10 @@ at86rf230_write_frame(void *context) ctx->trx.len = skb->len + 2; ctx->msg.complete = at86rf230_write_frame_complete; rc = spi_async(lp->spi, &ctx->msg); - if (rc) + if (rc) { + ctx->trx.len = 2; at86rf230_async_error(lp, ctx, rc); + } } static void @@ -1541,6 +1542,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->state.irq = lp->spi->irq; spi_message_init(&lp->state.msg); lp->state.msg.context = &lp->state; + lp->state.trx.len = 2; lp->state.trx.tx_buf = lp->state.buf; lp->state.trx.rx_buf = lp->state.buf; spi_message_add_tail(&lp->state.trx, &lp->state.msg); @@ -1549,6 +1551,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->irq.irq = lp->spi->irq; spi_message_init(&lp->irq.msg); lp->irq.msg.context = &lp->irq; + lp->irq.trx.len = 2; lp->irq.trx.tx_buf = lp->irq.buf; lp->irq.trx.rx_buf = lp->irq.buf; spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); @@ -1557,6 +1560,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->tx.irq = lp->spi->irq; spi_message_init(&lp->tx.msg); lp->tx.msg.context = &lp->tx; + lp->tx.trx.len = 2; lp->tx.trx.tx_buf = lp->tx.buf; lp->tx.trx.rx_buf = lp->tx.buf; spi_message_add_tail(&lp->tx.trx, &lp->tx.msg); -- cgit v1.2.3 From bf906b3db3c2b4f5d4db1db5f35796629c531ac4 Mon Sep 17 00:00:00 2001 From: "Kim, Ben Young Tae" Date: Tue, 10 Mar 2015 23:34:58 +0000 Subject: Bluetooth: btusb: Fix incorrect type in qca_device_info While qca_device_info is not coming from outside communication, no reason to use specific endian type inside and fix the wrong version comparison on big-endian platform. Signed-off-by: Ben Young Tae Kim Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 08330548f7fe..c34a875aaf60 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2667,10 +2667,10 @@ struct qca_rampatch_version { } __packed; struct qca_device_info { - __le32 rom_version; - __u8 rampatch_hdr; /* length of header in rampatch */ - __u8 nvm_hdr; /* length of header in NVM */ - __u8 ver_offset; /* offset of version structure in rampatch */ + u32 rom_version; + u8 rampatch_hdr; /* length of header in rampatch */ + u8 nvm_hdr; /* length of header in NVM */ + u8 ver_offset; /* offset of version structure in rampatch */ }; static const struct qca_device_info qca_devices_table[] = { @@ -2782,11 +2782,15 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, { struct qca_rampatch_version *rver; const struct firmware *fw; + u32 ver_rom, ver_patch; + u16 rver_rom, rver_patch; char fwname[64]; int err; - snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", - le32_to_cpu(ver->rom_version)); + ver_rom = le32_to_cpu(ver->rom_version); + ver_patch = le32_to_cpu(ver->patch_version); + + snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom); err = request_firmware(&fw, fwname, &hdev->dev); if (err) { @@ -2796,14 +2800,16 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, } BT_INFO("%s: using rampatch file: %s", hdev->name, fwname); + rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset); + rver_rom = le16_to_cpu(rver->rom_version); + rver_patch = le16_to_cpu(rver->patch_version); + BT_INFO("%s: QCA: patch rome 0x%x build 0x%x, firmware rome 0x%x " - "build 0x%x", hdev->name, le16_to_cpu(rver->rom_version), - le16_to_cpu(rver->patch_version), le32_to_cpu(ver->rom_version), - le32_to_cpu(ver->patch_version)); + "build 0x%x", hdev->name, rver_rom, rver_patch, ver_rom, + ver_patch); - if (rver->rom_version != ver->rom_version || - rver->patch_version <= ver->patch_version) { + if (rver_rom != ver_rom || rver_patch <= ver_patch) { BT_ERR("%s: rampatch file version did not match with firmware", hdev->name); err = -EINVAL; @@ -2849,6 +2855,7 @@ static int btusb_setup_qca(struct hci_dev *hdev) { const struct qca_device_info *info = NULL; struct qca_version ver; + u32 ver_rom; u8 status; int i, err; @@ -2857,13 +2864,14 @@ static int btusb_setup_qca(struct hci_dev *hdev) if (err < 0) return err; + ver_rom = le32_to_cpu(ver.rom_version); for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) { - if (ver.rom_version == qca_devices_table[i].rom_version) + if (ver_rom == qca_devices_table[i].rom_version) info = &qca_devices_table[i]; } if (!info) { BT_ERR("%s: don't support firmware rome 0x%x", hdev->name, - le32_to_cpu(ver.rom_version)); + ver_rom); return -ENODEV; } -- cgit v1.2.3 From 6576fe4afc1203d27a5f4c8f5511f44203f4e333 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 23 Feb 2015 18:16:47 -0600 Subject: Bluetooth: btusb: Add helper for READ_LOCAL_VERSION command Multiple codepaths duplicate some simple code to read and sanity-check local version information. Before I add a couple more such codepaths, add a helper to reduce duplication. Signed-off-by: Daniel Drake Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 60 ++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c34a875aaf60..bb5fd693414f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1269,6 +1269,28 @@ static void btusb_waker(struct work_struct *work) usb_autopm_put_interface(data->intf); } +static struct sk_buff *btusb_read_local_version(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", + hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + static int btusb_setup_bcm92035(struct hci_dev *hdev) { struct sk_buff *skb; @@ -1293,12 +1315,9 @@ static int btusb_setup_csr(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb)); + skb = btusb_read_local_version(hdev); + if (IS_ERR(skb)) return -PTR_ERR(skb); - } rp = (struct hci_rp_read_local_version *)skb->data; @@ -2429,21 +2448,9 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) kfree_skb(skb); /* Read Local Version Info */ - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); - return ret; - } - - if (skb->len != sizeof(*ver)) { - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); - kfree_skb(skb); - return -EIO; - } + skb = btusb_read_local_version(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); ver = (struct hci_rp_read_local_version *)skb->data; rev = le16_to_cpu(ver->hci_rev); @@ -2531,20 +2538,9 @@ reset_fw: kfree_skb(skb); /* Read Local Version Info */ - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); + skb = btusb_read_local_version(hdev); if (IS_ERR(skb)) { ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); - goto done; - } - - if (skb->len != sizeof(*ver)) { - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); - kfree_skb(skb); - ret = -EIO; goto done; } -- cgit v1.2.3 From e3721749000e11ba3f315efc5c98bf4cd5662f99 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 7 Mar 2015 22:07:07 +0100 Subject: at86rf230: init xtal_trim with zero This patch initialize xtal_trim value to zero. The xtal_trim property is an optional device tree value. Currently if no xtal_trim property is given the xtal_trim value can be contain random data, because it's a stack variable. This patch init the xtal_trim value to zero which is also the default value after reset for at86rf230 transceivers. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 088fa68f5098..edf575c88345 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1572,7 +1572,7 @@ static int at86rf230_probe(struct spi_device *spi) struct at86rf230_local *lp; unsigned int status; int rc, irq_type, rstn, slp_tr; - u8 xtal_trim; + u8 xtal_trim = 0; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); -- cgit v1.2.3 From eb3b435ecdb84d05698db862ce316b3c682f9a95 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 9 Mar 2015 13:56:10 +0100 Subject: at86rf230: replace state change sleeps with hrtimer This patch replace the state change timing relevant sleeps with hrtimers. Currently the sleeps are done in the complete handler of spi_async. The relation of doing the state change timing sleep with a timer will get the sleep functionality out of spi_async complete handler context. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 39 ++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index edf575c88345..4030fa69f176 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ struct at86rf230_state_change { struct at86rf230_local *lp; int irq; + struct hrtimer timer; struct spi_message msg; struct spi_transfer trx; u8 buf[AT86RF2XX_MAX_BUF]; @@ -548,6 +550,19 @@ done: ctx->complete(context); } +static enum hrtimer_restart at86rf230_async_state_timer(struct hrtimer *timer) +{ + struct at86rf230_state_change *ctx = + container_of(timer, struct at86rf230_state_change, timer); + struct at86rf230_local *lp = ctx->lp; + + at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, + at86rf230_async_state_assert, + ctx->irq_enable); + + return HRTIMER_NORESTART; +} + /* Do state change timing delay. */ static void at86rf230_async_state_delay(void *context) @@ -556,6 +571,7 @@ at86rf230_async_state_delay(void *context) struct at86rf230_local *lp = ctx->lp; struct at86rf2xx_chip_data *c = lp->data; bool force = false; + ktime_t tim; /* The force state changes are will show as normal states in the * state status subregister. We change the to_state to the @@ -579,11 +595,10 @@ at86rf230_async_state_delay(void *context) case STATE_TRX_OFF: switch (ctx->to_state) { case STATE_RX_AACK_ON: - usleep_range(c->t_off_to_aack, c->t_off_to_aack + 10); + tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC); goto change; case STATE_TX_ON: - usleep_range(c->t_off_to_tx_on, - c->t_off_to_tx_on + 10); + tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); goto change; default: break; @@ -597,8 +612,8 @@ at86rf230_async_state_delay(void *context) * to TX_ON. */ if (!force) { - usleep_range(c->t_frame + c->t_p_ack, - c->t_frame + c->t_p_ack + 1000); + tim = ktime_set(0, (c->t_frame + c->t_p_ack) * + NSEC_PER_USEC); goto change; } break; @@ -610,7 +625,7 @@ at86rf230_async_state_delay(void *context) case STATE_P_ON: switch (ctx->to_state) { case STATE_TRX_OFF: - usleep_range(c->t_reset_to_off, c->t_reset_to_off + 10); + tim = ktime_set(0, c->t_reset_to_off * NSEC_PER_USEC); goto change; default: break; @@ -621,12 +636,10 @@ at86rf230_async_state_delay(void *context) } /* Default delay is 1us in the most cases */ - udelay(1); + tim = ktime_set(0, NSEC_PER_USEC); change: - at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, - at86rf230_async_state_assert, - ctx->irq_enable); + hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL); } static void @@ -1546,6 +1559,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->state.trx.tx_buf = lp->state.buf; lp->state.trx.rx_buf = lp->state.buf; spi_message_add_tail(&lp->state.trx, &lp->state.msg); + hrtimer_init(&lp->state.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lp->state.timer.function = at86rf230_async_state_timer; lp->irq.lp = lp; lp->irq.irq = lp->spi->irq; @@ -1555,6 +1570,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->irq.trx.tx_buf = lp->irq.buf; lp->irq.trx.rx_buf = lp->irq.buf; spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); + hrtimer_init(&lp->irq.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lp->irq.timer.function = at86rf230_async_state_timer; lp->tx.lp = lp; lp->tx.irq = lp->spi->irq; @@ -1564,6 +1581,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->tx.trx.tx_buf = lp->tx.buf; lp->tx.trx.rx_buf = lp->tx.buf; spi_message_add_tail(&lp->tx.trx, &lp->tx.msg); + hrtimer_init(&lp->tx.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lp->tx.timer.function = at86rf230_async_state_timer; } static int at86rf230_probe(struct spi_device *spi) -- cgit v1.2.3 From dce481e63dc18ece7c86c607aa17b7c753fce0b7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 9 Mar 2015 13:56:11 +0100 Subject: at86rf230: add support for calibration timeout This patch adds a handling for calibration if we are 5 minutes in PLL state. I first tried to implement the calibration functionality in TX_ON state via register values CF_START and DCU_START, but this occurs a one second delay at each calibration time. An another solution to start a calibration is to switch from TRX_OFF state into TX_ON, then a calibration is done automatically by transceiver. This method will be used in this patch, after each transmit of a frame we check with jiffies if the PLL is set 5 minutes without doing a TRX_OFF->(TX_ON || RX_AACK_ON) or channel switch. The worst case would be a transceiver in receiving mode only, but this is under normal operation very unlikely. Signed-off-by: Alexander Aring Cc: Phoebe Buckheister Cc: Werner Almesberger Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 72 ++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 4030fa69f176..795106c23097 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,8 @@ struct at86rf2xx_chip_data { * We assume the max_frame_retries (7) value of 802.15.4 here. */ #define AT86RF2XX_MAX_TX_RETRIES 7 +/* We use the recommended 5 minutes timeout to recalibrate */ +#define AT86RF2XX_CAL_LOOP_TIMEOUT (5 * 60 * HZ) struct at86rf230_state_change { struct at86rf230_local *lp; @@ -90,6 +93,7 @@ struct at86rf230_local { struct at86rf230_state_change irq; bool tx_aret; + unsigned long cal_timeout; s8 max_frame_retries; bool is_tx; /* spinlock for is_tx protection */ @@ -491,6 +495,14 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, } } +static inline u8 at86rf230_state_to_force(u8 state) +{ + if (state == STATE_TX_ON) + return STATE_FORCE_TX_ON; + else + return STATE_FORCE_TRX_OFF; +} + static void at86rf230_async_state_assert(void *context) { @@ -527,11 +539,12 @@ at86rf230_async_state_assert(void *context) * higher or equal than AT86RF2XX_MAX_TX_RETRIES we * will do a force change. */ - if (ctx->to_state == STATE_TX_ON) { - u8 state = STATE_TX_ON; + if (ctx->to_state == STATE_TX_ON || + ctx->to_state == STATE_TRX_OFF) { + u8 state = ctx->to_state; if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) - state = STATE_FORCE_TX_ON; + state = at86rf230_state_to_force(state); lp->tx_retry++; at86rf230_async_state_change(lp, ctx, state, @@ -599,6 +612,11 @@ at86rf230_async_state_delay(void *context) goto change; case STATE_TX_ON: tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); + /* state change from TRX_OFF to TX_ON to do a + * calibration, we need to reset the timeout for the + * next one. + */ + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; goto change; default: break; @@ -606,10 +624,11 @@ at86rf230_async_state_delay(void *context) break; case STATE_BUSY_RX_AACK: switch (ctx->to_state) { + case STATE_TRX_OFF: case STATE_TX_ON: /* Wait for worst case receiving time if we * didn't make a force change from BUSY_RX_AACK - * to TX_ON. + * to TX_ON or TRX_OFF. */ if (!force) { tim = ktime_set(0, (c->t_frame + c->t_p_ack) * @@ -969,25 +988,45 @@ at86rf230_xmit_tx_on(void *context) at86rf230_write_frame, false); } -static int -at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +static void +at86rf230_xmit_start(void *context) { - struct at86rf230_local *lp = hw->priv; - struct at86rf230_state_change *ctx = &lp->tx; - - void (*tx_complete)(void *context) = at86rf230_write_frame; - - lp->tx_skb = skb; + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; /* In ARET mode we need to go into STATE_TX_ARET_ON after we * are in STATE_TX_ON. The pfad differs here, so we change * the complete handler. */ if (lp->tx_aret) - tx_complete = at86rf230_xmit_tx_on; + at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_xmit_tx_on, false); + else + at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_write_frame, false); +} + +static int +at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +{ + struct at86rf230_local *lp = hw->priv; + struct at86rf230_state_change *ctx = &lp->tx; + lp->tx_skb = skb; lp->tx_retry = 0; - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); + + /* After 5 minutes in PLL and the same frequency we run again the + * calibration loops which is recommended by at86rf2xx datasheets. + * + * The calibration is initiate by a state change from TRX_OFF + * to TX_ON, the lp->cal_timeout should be reinit by state_delay + * function then to start in the next 5 minutes. + */ + if (time_is_before_jiffies(lp->cal_timeout)) + at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF, + at86rf230_xmit_start, false); + else + at86rf230_xmit_start(ctx); return 0; } @@ -1003,6 +1042,9 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level) static int at86rf230_start(struct ieee802154_hw *hw) { + struct at86rf230_local *lp = hw->priv; + + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); } @@ -1083,6 +1125,8 @@ at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel) /* Wait for PLL */ usleep_range(lp->data->t_channel_switch, lp->data->t_channel_switch + 10); + + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; return rc; } -- cgit v1.2.3 From 51b3b2cfc64dbfa91d08077abf0791e36c44f916 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 9 Mar 2015 13:56:12 +0100 Subject: at86rf230: fix volatile regmap registers These registers are also changed by transceiver and should be volatile for right accessing via regmap debugfs. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 795106c23097..b64c5c7b2a50 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -421,6 +421,8 @@ at86rf230_reg_volatile(struct device *dev, unsigned int reg) case RG_PHY_ED_LEVEL: case RG_IRQ_STATUS: case RG_VREG_CTRL: + case RG_PLL_CF: + case RG_PLL_DCU: return true; default: return false; -- cgit v1.2.3