Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 250fbf12 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next



Johan Hedberg says:

====================
pull request: bluetooth-next 2016-01-08

Here's one more bluetooth-next pull request for the 4.5 kernel:

 - Support for CRC check and promiscuous mode for CC2520
 - Fixes to btmrvl driver
 - New ACPI IDs for hci_bcm driver
 - Limited Discovery support for the Bluetooth mgmt interface
 - Minor other cleanups here and there

Please let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a33ad9ac 8cf60cf2
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -89,6 +89,7 @@ struct btmrvl_adapter {
	wait_queue_head_t event_hs_wait_q;
	wait_queue_head_t event_hs_wait_q;
	u8 cmd_complete;
	u8 cmd_complete;
	bool is_suspended;
	bool is_suspended;
	bool is_suspending;
};
};


struct btmrvl_private {
struct btmrvl_private {
+10 −3
Original line number Original line Diff line number Diff line
@@ -436,6 +436,11 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)


	BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len);
	BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len);


	if (priv->adapter->is_suspending || priv->adapter->is_suspended) {
		BT_ERR("%s: Device is suspending or suspended", __func__);
		return -EBUSY;
	}

	switch (hci_skb_pkt_type(skb)) {
	switch (hci_skb_pkt_type(skb)) {
	case HCI_COMMAND_PKT:
	case HCI_COMMAND_PKT:
		hdev->stat.cmd_tx++;
		hdev->stat.cmd_tx++;
@@ -452,6 +457,7 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)


	skb_queue_tail(&priv->adapter->tx_queue, skb);
	skb_queue_tail(&priv->adapter->tx_queue, skb);


	if (!priv->adapter->is_suspended)
		wake_up_interruptible(&priv->main_thread.wait_q);
		wake_up_interruptible(&priv->main_thread.wait_q);


	return 0;
	return 0;
@@ -543,7 +549,7 @@ static int btmrvl_setup(struct hci_dev *hdev)
	if (ret)
	if (ret)
		return ret;
		return ret;


	priv->btmrvl_dev.gpio_gap = 0xffff;
	priv->btmrvl_dev.gpio_gap = 0xfffe;


	btmrvl_check_device_tree(priv);
	btmrvl_check_device_tree(priv);


@@ -643,7 +649,8 @@ static int btmrvl_service_main_thread(void *data)
		if (adapter->ps_state == PS_SLEEP)
		if (adapter->ps_state == PS_SLEEP)
			continue;
			continue;


		if (!priv->btmrvl_dev.tx_dnld_rdy)
		if (!priv->btmrvl_dev.tx_dnld_rdy ||
		    priv->adapter->is_suspended)
			continue;
			continue;


		skb = skb_dequeue(&adapter->tx_queue);
		skb = skb_dequeue(&adapter->tx_queue);
+4 −2
Original line number Original line Diff line number Diff line
@@ -1112,7 +1112,8 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
	 */
	 */
	if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
	if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
		BT_ERR("FW failed to be active in time!");
		BT_ERR("FW failed to be active in time!");
		return -ETIMEDOUT;
		ret = -ETIMEDOUT;
		goto done;
	}
	}


	sdio_release_host(card->func);
	sdio_release_host(card->func);
@@ -1544,10 +1545,10 @@ static int btmrvl_sdio_suspend(struct device *dev)
	}
	}


	priv = card->priv;
	priv = card->priv;
	priv->adapter->is_suspending = true;
	hcidev = priv->btmrvl_dev.hcidev;
	hcidev = priv->btmrvl_dev.hcidev;
	BT_DBG("%s: SDIO suspend", hcidev->name);
	BT_DBG("%s: SDIO suspend", hcidev->name);
	hci_suspend_dev(hcidev);
	hci_suspend_dev(hcidev);
	skb_queue_purge(&priv->adapter->tx_queue);


	if (priv->adapter->hs_state != HS_ACTIVATED) {
	if (priv->adapter->hs_state != HS_ACTIVATED) {
		if (btmrvl_enable_hs(priv)) {
		if (btmrvl_enable_hs(priv)) {
@@ -1556,6 +1557,7 @@ static int btmrvl_sdio_suspend(struct device *dev)
		}
		}
	}
	}


	priv->adapter->is_suspending = false;
	priv->adapter->is_suspended = true;
	priv->adapter->is_suspended = true;


	/* We will keep the power when hs enabled successfully */
	/* We will keep the power when hs enabled successfully */
+7 −0
Original line number Original line Diff line number Diff line
@@ -814,9 +814,16 @@ static const struct hci_uart_proto bcm_proto = {


#ifdef CONFIG_ACPI
#ifdef CONFIG_ACPI
static const struct acpi_device_id bcm_acpi_match[] = {
static const struct acpi_device_id bcm_acpi_match[] = {
	{ "BCM2E1A", 0 },
	{ "BCM2E39", 0 },
	{ "BCM2E39", 0 },
	{ "BCM2E3A", 0 },
	{ "BCM2E3D", 0 },
	{ "BCM2E3F", 0 },
	{ "BCM2E40", 0 },
	{ "BCM2E64", 0 },
	{ "BCM2E65", 0 },
	{ "BCM2E65", 0 },
	{ "BCM2E67", 0 },
	{ "BCM2E67", 0 },
	{ "BCM2E7B", 0 },
	{ },
	{ },
};
};
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
+122 −23
Original line number Original line Diff line number Diff line
@@ -21,6 +21,8 @@
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/of_gpio.h>
#include <linux/of_gpio.h>
#include <linux/ieee802154.h>
#include <linux/ieee802154.h>
#include <linux/crc-ccitt.h>
#include <asm/unaligned.h>


#include <net/mac802154.h>
#include <net/mac802154.h>
#include <net/cfg802154.h>
#include <net/cfg802154.h>
@@ -189,6 +191,18 @@
#define	CC2520_RXFIFOCNT		0x3E
#define	CC2520_RXFIFOCNT		0x3E
#define	CC2520_TXFIFOCNT		0x3F
#define	CC2520_TXFIFOCNT		0x3F


/* CC2520_FRMFILT0 */
#define FRMFILT0_FRAME_FILTER_EN	BIT(0)
#define FRMFILT0_PAN_COORDINATOR	BIT(1)

/* CC2520_FRMCTRL0 */
#define FRMCTRL0_AUTOACK		BIT(5)
#define FRMCTRL0_AUTOCRC		BIT(6)

/* CC2520_FRMCTRL1 */
#define FRMCTRL1_SET_RXENMASK_ON_TX	BIT(0)
#define FRMCTRL1_IGNORE_TX_UNDERF	BIT(1)

/* Driver private information */
/* Driver private information */
struct cc2520_private {
struct cc2520_private {
	struct spi_device *spi;		/* SPI device structure */
	struct spi_device *spi;		/* SPI device structure */
@@ -201,6 +215,7 @@ struct cc2520_private {
	struct work_struct fifop_irqwork;/* Workqueue for FIFOP */
	struct work_struct fifop_irqwork;/* Workqueue for FIFOP */
	spinlock_t lock;		/* Lock for is_tx*/
	spinlock_t lock;		/* Lock for is_tx*/
	struct completion tx_complete;	/* Work completion for Tx */
	struct completion tx_complete;	/* Work completion for Tx */
	bool promiscuous;               /* Flag for promiscuous mode */
};
};


/* Generic Functions */
/* Generic Functions */
@@ -367,14 +382,14 @@ cc2520_read_register(struct cc2520_private *priv, u8 reg, u8 *data)
}
}


static int
static int
cc2520_write_txfifo(struct cc2520_private *priv, u8 *data, u8 len)
cc2520_write_txfifo(struct cc2520_private *priv, u8 pkt_len, u8 *data, u8 len)
{
{
	int status;
	int status;


	/* length byte must include FCS even
	/* length byte must include FCS even
	 * if it is calculated in the hardware
	 * if it is calculated in the hardware
	 */
	 */
	int len_byte = len + 2;
	int len_byte = pkt_len;


	struct spi_message msg;
	struct spi_message msg;


@@ -414,7 +429,7 @@ cc2520_write_txfifo(struct cc2520_private *priv, u8 *data, u8 len)
}
}


static int
static int
cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len, u8 *lqi)
cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len)
{
{
	int status;
	int status;
	struct spi_message msg;
	struct spi_message msg;
@@ -470,12 +485,25 @@ cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
	unsigned long flags;
	unsigned long flags;
	int rc;
	int rc;
	u8 status = 0;
	u8 status = 0;
	u8 pkt_len;

	/* In promiscuous mode we disable AUTOCRC so we can get the raw CRC
	 * values on RX. This means we need to manually add the CRC on TX.
	 */
	if (priv->promiscuous) {
		u16 crc = crc_ccitt(0, skb->data, skb->len);

		put_unaligned_le16(crc, skb_put(skb, 2));
		pkt_len = skb->len;
	} else {
		pkt_len = skb->len + 2;
	}


	rc = cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX);
	rc = cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX);
	if (rc)
	if (rc)
		goto err_tx;
		goto err_tx;


	rc = cc2520_write_txfifo(priv, skb->data, skb->len);
	rc = cc2520_write_txfifo(priv, pkt_len, skb->data, skb->len);
	if (rc)
	if (rc)
		goto err_tx;
		goto err_tx;


@@ -518,22 +546,62 @@ static int cc2520_rx(struct cc2520_private *priv)
	u8 len = 0, lqi = 0, bytes = 1;
	u8 len = 0, lqi = 0, bytes = 1;
	struct sk_buff *skb;
	struct sk_buff *skb;


	cc2520_read_rxfifo(priv, &len, bytes, &lqi);
	/* Read single length byte from the radio. */
	cc2520_read_rxfifo(priv, &len, bytes);


	if (len < 2 || len > IEEE802154_MTU)
	if (!ieee802154_is_valid_psdu_len(len)) {
		return -EINVAL;
		/* Corrupted frame received, clear frame buffer by
		 * reading entire buffer.
		 */
		dev_dbg(&priv->spi->dev, "corrupted frame received\n");
		len = IEEE802154_MTU;
	}


	skb = dev_alloc_skb(len);
	skb = dev_alloc_skb(len);
	if (!skb)
	if (!skb)
		return -ENOMEM;
		return -ENOMEM;


	if (cc2520_read_rxfifo(priv, skb_put(skb, len), len, &lqi)) {
	if (cc2520_read_rxfifo(priv, skb_put(skb, len), len)) {
		dev_dbg(&priv->spi->dev, "frame reception failed\n");
		dev_dbg(&priv->spi->dev, "frame reception failed\n");
		kfree_skb(skb);
		kfree_skb(skb);
		return -EINVAL;
		return -EINVAL;
	}
	}


	skb_trim(skb, skb->len - 2);
	/* In promiscuous mode, we configure the radio to include the
	 * CRC (AUTOCRC==0) and we pass on the packet unconditionally. If not
	 * in promiscuous mode, we check the CRC here, but leave the
	 * RSSI/LQI/CRC_OK bytes as they will get removed in the mac layer.
	 */
	if (!priv->promiscuous) {
		bool crc_ok;

		/* Check if the CRC is valid. With AUTOCRC set, the most
		 * significant bit of the last byte returned from the CC2520
		 * is CRC_OK flag. See section 20.3.4 of the datasheet.
		 */
		crc_ok = skb->data[len - 1] & BIT(7);

		/* If we failed CRC drop the packet in the driver layer. */
		if (!crc_ok) {
			dev_dbg(&priv->spi->dev, "CRC check failed\n");
			kfree_skb(skb);
			return -EINVAL;
		}

		/* To calculate LQI, the lower 7 bits of the last byte (the
		 * correlation value provided by the radio) must be scaled to
		 * the range 0-255. According to section 20.6, the correlation
		 * value ranges from 50-110. Ideally this would be calibrated
		 * per hardware design, but we use roughly the datasheet values
		 * to get close enough while avoiding floating point.
		 */
		lqi = skb->data[len - 1] & 0x7f;
		if (lqi < 50)
			lqi = 50;
		else if (lqi > 113)
			lqi = 113;
		lqi = (lqi - 50) * 4;
	}


	ieee802154_rx_irqsafe(priv->hw, skb, lqi);
	ieee802154_rx_irqsafe(priv->hw, skb, lqi);


@@ -619,14 +687,19 @@ cc2520_filter(struct ieee802154_hw *hw,
	}
	}


	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
		u8 frmfilt0;

		dev_vdbg(&priv->spi->dev,
		dev_vdbg(&priv->spi->dev,
			 "cc2520_filter called for panc change\n");
			 "cc2520_filter called for panc change\n");

		cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0);

		if (filt->pan_coord)
		if (filt->pan_coord)
			ret = cc2520_write_register(priv, CC2520_FRMFILT0,
			frmfilt0 |= FRMFILT0_PAN_COORDINATOR;
						    0x02);
		else
		else
			ret = cc2520_write_register(priv, CC2520_FRMFILT0,
			frmfilt0 &= ~FRMFILT0_PAN_COORDINATOR;
						    0x00);

		ret = cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0);
	}
	}


	return ret;
	return ret;
@@ -723,6 +796,30 @@ cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm)
	return cc2520_cc2591_set_tx_power(priv, mbm);
	return cc2520_cc2591_set_tx_power(priv, mbm);
}
}


static int
cc2520_set_promiscuous_mode(struct ieee802154_hw *hw, bool on)
{
	struct cc2520_private *priv = hw->priv;
	u8 frmfilt0;

	dev_dbg(&priv->spi->dev, "%s : mode %d\n", __func__, on);

	priv->promiscuous = on;

	cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0);

	if (on) {
		/* Disable automatic ACK, automatic CRC, and frame filtering. */
		cc2520_write_register(priv, CC2520_FRMCTRL0, 0);
		frmfilt0 &= ~FRMFILT0_FRAME_FILTER_EN;
	} else {
		cc2520_write_register(priv, CC2520_FRMCTRL0, FRMCTRL0_AUTOACK |
							     FRMCTRL0_AUTOCRC);
		frmfilt0 |= FRMFILT0_FRAME_FILTER_EN;
	}
	return cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0);
}

static const struct ieee802154_ops cc2520_ops = {
static const struct ieee802154_ops cc2520_ops = {
	.owner = THIS_MODULE,
	.owner = THIS_MODULE,
	.start = cc2520_start,
	.start = cc2520_start,
@@ -732,6 +829,7 @@ static const struct ieee802154_ops cc2520_ops = {
	.set_channel = cc2520_set_channel,
	.set_channel = cc2520_set_channel,
	.set_hw_addr_filt = cc2520_filter,
	.set_hw_addr_filt = cc2520_filter,
	.set_txpower = cc2520_set_txpower,
	.set_txpower = cc2520_set_txpower,
	.set_promiscuous_mode = cc2520_set_promiscuous_mode,
};
};


static int cc2520_register(struct cc2520_private *priv)
static int cc2520_register(struct cc2520_private *priv)
@@ -749,7 +847,8 @@ static int cc2520_register(struct cc2520_private *priv)


	/* We do support only 2.4 Ghz */
	/* We do support only 2.4 Ghz */
	priv->hw->phy->supported.channels[0] = 0x7FFF800;
	priv->hw->phy->supported.channels[0] = 0x7FFF800;
	priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT;
	priv->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
			  IEEE802154_HW_PROMISCUOUS;


	priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;
	priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;


@@ -919,6 +1018,11 @@ static int cc2520_hw_init(struct cc2520_private *priv)
	}
	}


	/* Registers default value: section 28.1 in Datasheet */
	/* Registers default value: section 28.1 in Datasheet */

	/* Set the CCA threshold to -50 dBm. This seems to have been copied
	 * from the TinyOS CC2520 driver and is much higher than the -84 dBm
	 * threshold suggested in the datasheet.
	 */
	ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A);
	ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A);
	if (ret)
	if (ret)
		goto err_ret;
		goto err_ret;
@@ -955,15 +1059,10 @@ static int cc2520_hw_init(struct cc2520_private *priv)
	if (ret)
	if (ret)
		goto err_ret;
		goto err_ret;


	ret = cc2520_write_register(priv, CC2520_FRMCTRL0, 0x60);
	/* Configure registers correctly for this driver. */
	if (ret)
	ret = cc2520_write_register(priv, CC2520_FRMCTRL1,
		goto err_ret;
				    FRMCTRL1_SET_RXENMASK_ON_TX |

				    FRMCTRL1_IGNORE_TX_UNDERF);
	ret = cc2520_write_register(priv, CC2520_FRMCTRL1, 0x03);
	if (ret)
		goto err_ret;

	ret = cc2520_write_register(priv, CC2520_FRMFILT0, 0x00);
	if (ret)
	if (ret)
		goto err_ret;
		goto err_ret;


Loading