Browse Source

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

John W. Linville 11 years ago
parent
commit
f6cd071891

+ 2 - 2
drivers/bluetooth/Kconfig

@@ -201,7 +201,7 @@ config BT_MRVL
 	  The core driver to support Marvell Bluetooth devices.
 	  The core driver to support Marvell Bluetooth devices.
 
 
 	  This driver is required if you want to support
 	  This driver is required if you want to support
-	  Marvell Bluetooth devices, such as 8688/8787/8797/8897.
+	  Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897.
 
 
 	  Say Y here to compile Marvell Bluetooth driver
 	  Say Y here to compile Marvell Bluetooth driver
 	  into the kernel or say M to compile it as module.
 	  into the kernel or say M to compile it as module.
@@ -214,7 +214,7 @@ config BT_MRVL_SDIO
 	  The driver for Marvell Bluetooth chipsets with SDIO interface.
 	  The driver for Marvell Bluetooth chipsets with SDIO interface.
 
 
 	  This driver is required if you want to use Marvell Bluetooth
 	  This driver is required if you want to use Marvell Bluetooth
-	  devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897
+	  devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897
 	  chipsets are supported.
 	  chipsets are supported.
 
 
 	  Say Y here to compile support for Marvell BT-over-SDIO driver
 	  Say Y here to compile support for Marvell BT-over-SDIO driver

+ 34 - 2
drivers/bluetooth/btmrvl_sdio.c

@@ -84,7 +84,27 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
 	.int_read_to_clear = false,
 	.int_read_to_clear = false,
 };
 };
 
 
-static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = {
+	.cfg = 0x00,
+	.host_int_mask = 0x08,
+	.host_intstatus = 0x0C,
+	.card_status = 0x5C,
+	.sq_read_base_addr_a0 = 0x6C,
+	.sq_read_base_addr_a1 = 0x6D,
+	.card_revision = 0xC8,
+	.card_fw_status0 = 0x88,
+	.card_fw_status1 = 0x89,
+	.card_rx_len = 0x8A,
+	.card_rx_unit = 0x8B,
+	.io_port_0 = 0xE4,
+	.io_port_1 = 0xE5,
+	.io_port_2 = 0xE6,
+	.int_read_to_clear = true,
+	.host_int_rsr = 0x04,
+	.card_misc_cfg = 0xD8,
+};
+
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
 	.cfg = 0x00,
 	.cfg = 0x00,
 	.host_int_mask = 0x02,
 	.host_int_mask = 0x02,
 	.host_intstatus = 0x03,
 	.host_intstatus = 0x03,
@@ -128,10 +148,18 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
 	.sd_blksz_fw_dl	= 256,
 	.sd_blksz_fw_dl	= 256,
 };
 };
 
 
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
+	.helper		= NULL,
+	.firmware	= "mrvl/sd8887_uapsta.bin",
+	.reg		= &btmrvl_reg_8887,
+	.support_pscan_win_report = true,
+	.sd_blksz_fw_dl	= 256,
+};
+
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
 	.helper		= NULL,
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8897_uapsta.bin",
 	.firmware	= "mrvl/sd8897_uapsta.bin",
-	.reg		= &btmrvl_reg_88xx,
+	.reg		= &btmrvl_reg_8897,
 	.support_pscan_win_report = true,
 	.support_pscan_win_report = true,
 	.sd_blksz_fw_dl	= 256,
 	.sd_blksz_fw_dl	= 256,
 };
 };
@@ -149,6 +177,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
 	/* Marvell SD8797 Bluetooth device */
 	/* Marvell SD8797 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
+	/* Marvell SD8887 Bluetooth device */
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
+			.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
 	/* Marvell SD8897 Bluetooth device */
 	/* Marvell SD8897 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
@@ -1280,4 +1311,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");

+ 0 - 4
drivers/bluetooth/btusb.c

@@ -268,8 +268,6 @@ struct btusb_data {
 	struct usb_interface *intf;
 	struct usb_interface *intf;
 	struct usb_interface *isoc;
 	struct usb_interface *isoc;
 
 
-	spinlock_t lock;
-
 	unsigned long flags;
 	unsigned long flags;
 
 
 	struct work_struct work;
 	struct work_struct work;
@@ -2002,8 +2000,6 @@ static int btusb_probe(struct usb_interface *intf,
 	data->udev = interface_to_usbdev(intf);
 	data->udev = interface_to_usbdev(intf);
 	data->intf = intf;
 	data->intf = intf;
 
 
-	spin_lock_init(&data->lock);
-
 	INIT_WORK(&data->work, btusb_work);
 	INIT_WORK(&data->work, btusb_work);
 	INIT_WORK(&data->waker, btusb_waker);
 	INIT_WORK(&data->waker, btusb_waker);
 	init_usb_anchor(&data->deferred);
 	init_usb_anchor(&data->deferred);

+ 95 - 50
net/bluetooth/6lowpan.c

@@ -426,38 +426,33 @@ static void convert_dest_bdaddr(struct in6_addr *ip6_daddr,
 	*addr_type = get_addr_type_from_eui64(addr->b[5]);
 	*addr_type = get_addr_type_from_eui64(addr->b[5]);
 }
 }
 
 
-static int header_create(struct sk_buff *skb, struct net_device *netdev,
-		         unsigned short type, const void *_daddr,
-		         const void *_saddr, unsigned int len)
+static int setup_header(struct sk_buff *skb, struct net_device *netdev,
+			bdaddr_t *peer_addr, u8 *peer_addr_type)
 {
 {
-	struct ipv6hdr *hdr;
+	struct in6_addr ipv6_daddr;
 	struct lowpan_dev *dev;
 	struct lowpan_dev *dev;
 	struct lowpan_peer *peer;
 	struct lowpan_peer *peer;
 	bdaddr_t addr, *any = BDADDR_ANY;
 	bdaddr_t addr, *any = BDADDR_ANY;
-	u8 *saddr, *daddr = any->b;
-	u8 addr_type;
-
-	if (type != ETH_P_IPV6)
-		return -EINVAL;
-
-	hdr = ipv6_hdr(skb);
+	u8 *daddr = any->b;
+	int err, status = 0;
 
 
 	dev = lowpan_dev(netdev);
 	dev = lowpan_dev(netdev);
 
 
-	if (ipv6_addr_is_multicast(&hdr->daddr)) {
-		memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
-		       sizeof(struct in6_addr));
+	memcpy(&ipv6_daddr, &lowpan_cb(skb)->addr, sizeof(ipv6_daddr));
+
+	if (ipv6_addr_is_multicast(&ipv6_daddr)) {
 		lowpan_cb(skb)->chan = NULL;
 		lowpan_cb(skb)->chan = NULL;
 	} else {
 	} else {
 		unsigned long flags;
 		unsigned long flags;
+		u8 addr_type;
 
 
 		/* Get destination BT device from skb.
 		/* Get destination BT device from skb.
 		 * If there is no such peer then discard the packet.
 		 * If there is no such peer then discard the packet.
 		 */
 		 */
-		convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
+		convert_dest_bdaddr(&ipv6_daddr, &addr, &addr_type);
 
 
 		BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
 		BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
-		       addr_type, &hdr->daddr);
+		       addr_type, &ipv6_daddr);
 
 
 		read_lock_irqsave(&devices_lock, flags);
 		read_lock_irqsave(&devices_lock, flags);
 		peer = peer_lookup_ba(dev, &addr, addr_type);
 		peer = peer_lookup_ba(dev, &addr, addr_type);
@@ -470,7 +465,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
 			 * the destination address.
 			 * the destination address.
 			 */
 			 */
 			read_lock_irqsave(&devices_lock, flags);
 			read_lock_irqsave(&devices_lock, flags);
-			peer = peer_lookup_dst(dev, &hdr->daddr, skb);
+			peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
 			read_unlock_irqrestore(&devices_lock, flags);
 			read_unlock_irqrestore(&devices_lock, flags);
 			if (!peer) {
 			if (!peer) {
 				BT_DBG("no such peer %pMR found", &addr);
 				BT_DBG("no such peer %pMR found", &addr);
@@ -479,15 +474,37 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
 		}
 		}
 
 
 		daddr = peer->eui64_addr;
 		daddr = peer->eui64_addr;
-
-		memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
-		       sizeof(struct in6_addr));
+		*peer_addr = addr;
+		*peer_addr_type = addr_type;
 		lowpan_cb(skb)->chan = peer->chan;
 		lowpan_cb(skb)->chan = peer->chan;
+
+		status = 1;
 	}
 	}
 
 
-	saddr = dev->netdev->dev_addr;
+	lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr,
+			       dev->netdev->dev_addr, skb->len);
 
 
-	return lowpan_header_compress(skb, netdev, type, daddr, saddr, len);
+	err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
+	if (err < 0)
+		return err;
+
+	return status;
+}
+
+static int header_create(struct sk_buff *skb, struct net_device *netdev,
+			 unsigned short type, const void *_daddr,
+			 const void *_saddr, unsigned int len)
+{
+	struct ipv6hdr *hdr;
+
+	if (type != ETH_P_IPV6)
+		return -EINVAL;
+
+	hdr = ipv6_hdr(skb);
+
+	memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr));
+
+	return 0;
 }
 }
 
 
 /* Packet to BT LE device */
 /* Packet to BT LE device */
@@ -529,11 +546,12 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
 	return err;
 	return err;
 }
 }
 
 
-static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
+static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 {
 {
 	struct sk_buff *local_skb;
 	struct sk_buff *local_skb;
 	struct lowpan_dev *entry, *tmp;
 	struct lowpan_dev *entry, *tmp;
 	unsigned long flags;
 	unsigned long flags;
+	int err = 0;
 
 
 	read_lock_irqsave(&devices_lock, flags);
 	read_lock_irqsave(&devices_lock, flags);
 
 
@@ -547,57 +565,77 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 		dev = lowpan_dev(entry->netdev);
 		dev = lowpan_dev(entry->netdev);
 
 
 		list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
 		list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+			int ret;
+
 			local_skb = skb_clone(skb, GFP_ATOMIC);
 			local_skb = skb_clone(skb, GFP_ATOMIC);
 
 
-			send_pkt(pentry->chan, local_skb, netdev);
+			BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
+			       netdev->name,
+			       &pentry->chan->dst, pentry->chan->dst_type,
+			       &pentry->peer_addr, pentry->chan);
+			ret = send_pkt(pentry->chan, local_skb, netdev);
+			if (ret < 0)
+				err = ret;
 
 
 			kfree_skb(local_skb);
 			kfree_skb(local_skb);
 		}
 		}
 	}
 	}
 
 
 	read_unlock_irqrestore(&devices_lock, flags);
 	read_unlock_irqrestore(&devices_lock, flags);
+
+	return err;
 }
 }
 
 
 static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
 static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 {
 	int err = 0;
 	int err = 0;
-	struct lowpan_dev *dev;
-	struct lowpan_peer *peer;
 	bdaddr_t addr;
 	bdaddr_t addr;
 	u8 addr_type;
 	u8 addr_type;
+	struct sk_buff *tmpskb;
 
 
-	if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
-		/* We need to send the packet to every device
-		 * behind this interface.
-		 */
-		send_mcast_pkt(skb, netdev);
-	} else {
-		unsigned long flags;
-
-		convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
-		dev = lowpan_dev(netdev);
-
-		read_lock_irqsave(&devices_lock, flags);
-		peer = peer_lookup_ba(dev, &addr, addr_type);
-		if (!peer)
-			peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb);
-		read_unlock_irqrestore(&devices_lock, flags);
+	/* We must take a copy of the skb before we modify/replace the ipv6
+	 * header as the header could be used elsewhere
+	 */
+	tmpskb = skb_unshare(skb, GFP_ATOMIC);
+	if (!tmpskb) {
+		kfree_skb(skb);
+		return NET_XMIT_DROP;
+	}
+	skb = tmpskb;
 
 
-		BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p",
-		       netdev->name, &addr, addr_type,
-		       &lowpan_cb(skb)->addr, peer);
+	/* Return values from setup_header()
+	 *  <0 - error, packet is dropped
+	 *   0 - this is a multicast packet
+	 *   1 - this is unicast packet
+	 */
+	err = setup_header(skb, netdev, &addr, &addr_type);
+	if (err < 0) {
+		kfree_skb(skb);
+		return NET_XMIT_DROP;
+	}
 
 
-		if (peer && peer->chan)
-			err = send_pkt(peer->chan, skb, netdev);
-		else
+	if (err) {
+		if (lowpan_cb(skb)->chan) {
+			BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
+			       netdev->name, &addr, addr_type,
+			       &lowpan_cb(skb)->addr, lowpan_cb(skb)->chan);
+			err = send_pkt(lowpan_cb(skb)->chan, skb, netdev);
+		} else {
 			err = -ENOENT;
 			err = -ENOENT;
+		}
+	} else {
+		/* We need to send the packet to every device behind this
+		 * interface.
+		 */
+		err = send_mcast_pkt(skb, netdev);
 	}
 	}
+
 	dev_kfree_skb(skb);
 	dev_kfree_skb(skb);
 
 
 	if (err)
 	if (err)
 		BT_DBG("ERROR: xmit failed (%d)", err);
 		BT_DBG("ERROR: xmit failed (%d)", err);
 
 
-	return (err < 0) ? NET_XMIT_DROP : err;
+	return err < 0 ? NET_XMIT_DROP : err;
 }
 }
 
 
 static const struct net_device_ops netdev_ops = {
 static const struct net_device_ops netdev_ops = {
@@ -617,7 +655,8 @@ static void netdev_setup(struct net_device *dev)
 	dev->needed_tailroom	= 0;
 	dev->needed_tailroom	= 0;
 	dev->mtu		= IPV6_MIN_MTU;
 	dev->mtu		= IPV6_MIN_MTU;
 	dev->tx_queue_len	= 0;
 	dev->tx_queue_len	= 0;
-	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT;
+	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT |
+				  IFF_MULTICAST;
 	dev->watchdog_timeo	= 0;
 	dev->watchdog_timeo	= 0;
 
 
 	dev->netdev_ops		= &netdev_ops;
 	dev->netdev_ops		= &netdev_ops;
@@ -950,6 +989,9 @@ static void chan_suspend_cb(struct l2cap_chan *chan)
 
 
 	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
 	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
 
 
+	if (!skb)
+		return;
+
 	lowpan_cb(skb)->status = -EAGAIN;
 	lowpan_cb(skb)->status = -EAGAIN;
 }
 }
 
 
@@ -959,6 +1001,9 @@ static void chan_resume_cb(struct l2cap_chan *chan)
 
 
 	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
 	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
 
 
+	if (!skb)
+		return;
+
 	lowpan_cb(skb)->status = 0;
 	lowpan_cb(skb)->status = 0;
 }
 }
 
 

+ 8 - 5
net/bluetooth/l2cap_core.c

@@ -6980,8 +6980,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	l2cap_chan_lock(chan);
-
 	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
 	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
 	    chan->chan_type != L2CAP_CHAN_RAW) {
 	    chan->chan_type != L2CAP_CHAN_RAW) {
 		err = -EINVAL;
 		err = -EINVAL;
@@ -7078,17 +7076,20 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		goto done;
 		goto done;
 	}
 	}
 
 
+	mutex_lock(&conn->chan_lock);
+	l2cap_chan_lock(chan);
+
 	if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
 	if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
 		hci_conn_drop(hcon);
 		hci_conn_drop(hcon);
 		err = -EBUSY;
 		err = -EBUSY;
-		goto done;
+		goto chan_unlock;
 	}
 	}
 
 
 	/* Update source addr of the socket */
 	/* Update source addr of the socket */
 	bacpy(&chan->src, &hcon->src);
 	bacpy(&chan->src, &hcon->src);
 	chan->src_type = bdaddr_type(hcon, hcon->src_type);
 	chan->src_type = bdaddr_type(hcon, hcon->src_type);
 
 
-	l2cap_chan_add(conn, chan);
+	__l2cap_chan_add(conn, chan);
 
 
 	/* l2cap_chan_add takes its own ref so we can drop this one */
 	/* l2cap_chan_add takes its own ref so we can drop this one */
 	hci_conn_drop(hcon);
 	hci_conn_drop(hcon);
@@ -7114,8 +7115,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
 
 	err = 0;
 	err = 0;
 
 
-done:
+chan_unlock:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_unlock(chan);
+	mutex_unlock(&conn->chan_lock);
+done:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 	hci_dev_put(hdev);
 	return err;
 	return err;