rpms/kernel/devel linux-2.6-bluetooth-autosuspend.diff, NONE, 1.1 linux-2.6-driver-level-usb-autosuspend.diff, NONE, 1.1 linux-2.6-fix-usb-serial-autosuspend.diff, NONE, 1.1 linux-2.6-qcserial-autosuspend.diff, NONE, 1.1 kernel.spec, 1.1634, 1.1635

Matthew Garrett mjg59 at fedoraproject.org
Sat Jul 18 22:50:14 UTC 2009


Author: mjg59

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv10477

Modified Files:
	kernel.spec 
Added Files:
	linux-2.6-bluetooth-autosuspend.diff 
	linux-2.6-driver-level-usb-autosuspend.diff 
	linux-2.6-fix-usb-serial-autosuspend.diff 
	linux-2.6-qcserial-autosuspend.diff 
Log Message:
* Sat Jul 18 2009 Matthew Garrett <mjg at redhat.com>
- linux-2.6-driver-level-usb-autosuspend.diff - allow drivers to enable autopm
- linux-2.6-fix-usb-serial-autosuspend.diff - fix generic usb-serial autopm
- linux-2.6-qcserial-autosuspend.diff - enable autopm by default on qcserial
- linux-2.6-bluetooth-autosuspend.diff - enable autopm by default on btusb


linux-2.6-bluetooth-autosuspend.diff:
 btusb.c |  185 +++++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 143 insertions(+), 42 deletions(-)

--- NEW FILE linux-2.6-bluetooth-autosuspend.diff ---
commit 7ed6456e2717d641a287bf6a83c1bf80395d312c
Author: Matthew Garrett <mjg at redhat.com>
Date:   Sat Jul 18 23:19:10 2009 +0100

    Add support for bluetooth autosuspend

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e70c57e..2f4b4c6 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -145,6 +145,7 @@ static struct usb_device_id blacklist_table[] = {
 #define BTUSB_INTR_RUNNING	0
 #define BTUSB_BULK_RUNNING	1
 #define BTUSB_ISOC_RUNNING	2
+#define BTUSB_SUSPENDING	3
 
 struct btusb_data {
 	struct hci_dev       *hdev;
@@ -157,11 +158,13 @@ struct btusb_data {
 	unsigned long flags;
 
 	struct work_struct work;
+	struct work_struct waker;
 
 	struct usb_anchor tx_anchor;
 	struct usb_anchor intr_anchor;
 	struct usb_anchor bulk_anchor;
 	struct usb_anchor isoc_anchor;
+	struct usb_anchor deferred;
 
 	struct usb_endpoint_descriptor *intr_ep;
 	struct usb_endpoint_descriptor *bulk_tx_ep;
@@ -174,6 +177,7 @@ struct btusb_data {
 	unsigned int sco_num;
 	int isoc_altsetting;
 	int suspend_count;
+	int did_iso_resume:1;
 };
 
 static void btusb_intr_complete(struct urb *urb)
@@ -202,6 +206,10 @@ static void btusb_intr_complete(struct urb *urb)
 	if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
 		return;
 
+	if (test_bit(BTUSB_SUSPENDING, &data->flags))
+		return;
+
+	usb_mark_last_busy(data->udev);
 	usb_anchor_urb(urb, &data->intr_anchor);
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -285,6 +293,9 @@ static void btusb_bulk_complete(struct urb *urb)
 	if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
 		return;
 
+	if (test_bit(BTUSB_SUSPENDING, &data->flags))
+		return;
+
 	usb_anchor_urb(urb, &data->bulk_anchor);
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -320,6 +331,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 		return -ENOMEM;
 	}
 
+	usb_mark_last_busy(data->udev);
 	pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
 
 	usb_fill_bulk_urb(urb, data->udev, pipe,
@@ -327,6 +339,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
 	urb->transfer_flags |= URB_FREE_BUFFER;
 
+	usb_mark_last_busy(data->udev);
 	usb_anchor_urb(urb, &data->bulk_anchor);
 
 	err = usb_submit_urb(urb, mem_flags);
@@ -375,6 +388,9 @@ static void btusb_isoc_complete(struct urb *urb)
 	if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
 		return;
 
+	if (test_bit(BTUSB_SUSPENDING, &data->flags))
+		return;
+
 	usb_anchor_urb(urb, &data->isoc_anchor);
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -490,6 +506,12 @@ static int btusb_open(struct hci_dev *hdev)
 
 	BT_DBG("%s", hdev->name);
 
+	err = usb_autopm_get_interface(data->intf);
+	if (err < 0)
+		return err;
+	data->intf->needs_remote_wakeup = 1;
+	usb_autopm_put_interface(data->intf);
+
 	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
@@ -517,9 +539,17 @@ failed:
 	return err;
 }
 
+static void btusb_stop_traffic(struct btusb_data *data)
+{
+	usb_kill_anchored_urbs(&data->intr_anchor);
+	usb_kill_anchored_urbs(&data->bulk_anchor);
+	usb_kill_anchored_urbs(&data->isoc_anchor);
+}
+
 static int btusb_close(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hdev->driver_data;
+	int err;
 
 	BT_DBG("%s", hdev->name);
 
@@ -529,13 +559,15 @@ static int btusb_close(struct hci_dev *hdev)
 	cancel_work_sync(&data->work);
 
 	clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
-	usb_kill_anchored_urbs(&data->isoc_anchor);
-
 	clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-	usb_kill_anchored_urbs(&data->bulk_anchor);
-
 	clear_bit(BTUSB_INTR_RUNNING, &data->flags);
-	usb_kill_anchored_urbs(&data->intr_anchor);
+	btusb_stop_traffic(data);
+
+	err = usb_autopm_get_interface(data->intf);
+	if (!err) {
+		data->intf->needs_remote_wakeup = 0;
+		usb_autopm_put_interface(data->intf);
+	}
 
 	return 0;
 }
@@ -558,7 +590,7 @@ static int btusb_send_frame(struct sk_buff *skb)
 	struct usb_ctrlrequest *dr;
 	struct urb *urb;
 	unsigned int pipe;
-	int err;
+	int err, susp;
 
 	BT_DBG("%s", hdev->name);
 
@@ -567,6 +599,7 @@ static int btusb_send_frame(struct sk_buff *skb)
 
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
+		BT_DBG("HCI_COMMAND_PKT");
 		urb = usb_alloc_urb(0, GFP_ATOMIC);
 		if (!urb)
 			return -ENOMEM;
@@ -592,6 +625,7 @@ static int btusb_send_frame(struct sk_buff *skb)
 		break;
 
 	case HCI_ACLDATA_PKT:
+		BT_DBG("HCI_ACLDATA_PKT");
 		if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1)
 			return -ENODEV;
 
@@ -609,6 +643,7 @@ static int btusb_send_frame(struct sk_buff *skb)
 		break;
 
 	case HCI_SCODATA_PKT:
+		BT_DBG("HCI_SCODATA_PKT");
 		if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1)
 			return -ENODEV;
 
@@ -639,17 +674,22 @@ static int btusb_send_frame(struct sk_buff *skb)
 		return -EILSEQ;
 	}
 
+	spin_lock(&data->lock);
+	susp = test_bit(BTUSB_SUSPENDING, &data->flags);
 	usb_anchor_urb(urb, &data->tx_anchor);
-
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err < 0) {
-		BT_ERR("%s urb %p submission failed", hdev->name, urb);
-		kfree(urb->setup_packet);
-		usb_unanchor_urb(urb);
+	if (susp) {
+		schedule_work(&data->waker);
+		err = 0;
+	} else {
+		err = usb_submit_urb(urb, GFP_ATOMIC);
+		if (err < 0) {
+			BT_ERR("%s urb %p submission failed", hdev->name, urb);
+			kfree(urb->setup_packet);
+			usb_unanchor_urb(urb);
+		}
+		usb_free_urb(urb);
 	}
-
-	usb_free_urb(urb);
-
+	spin_unlock(&data->lock);
 	return err;
 }
 
@@ -742,9 +782,26 @@ static void btusb_work(struct work_struct *work)
 		usb_kill_anchored_urbs(&data->isoc_anchor);
 
 		__set_isoc_interface(hdev, 0);
+		if (data->did_iso_resume) {
+			data->did_iso_resume = 0;
+			usb_autopm_put_interface(data->isoc);
+		}
 	}
 }
 
+static void btusb_waker(struct work_struct *work)
+{
+	struct btusb_data *data = container_of(work, struct btusb_data, waker);
+	int err;
+
+	BUG_ON(data == NULL);
+	BT_DBG("about to resume");
+	BUG_ON(data->intf == NULL);
+	err = usb_autopm_get_interface(data->intf);
+	if (!err)
+		usb_autopm_put_interface(data->intf);
+}
+
 static int btusb_probe(struct usb_interface *intf,
 				const struct usb_device_id *id)
 {
@@ -814,11 +871,13 @@ static int btusb_probe(struct usb_interface *intf,
 	spin_lock_init(&data->lock);
 
 	INIT_WORK(&data->work, btusb_work);
+	INIT_WORK(&data->waker, btusb_waker);
 
 	init_usb_anchor(&data->tx_anchor);
 	init_usb_anchor(&data->intr_anchor);
 	init_usb_anchor(&data->bulk_anchor);
 	init_usb_anchor(&data->isoc_anchor);
+	init_usb_anchor(&data->deferred);
 
 	hdev = hci_alloc_dev();
 	if (!hdev) {
@@ -908,6 +967,7 @@ static int btusb_probe(struct usb_interface *intf,
 	}
 
 	usb_set_intfdata(intf, data);
+	usb_device_autosuspend_enable(data->udev);
 
 	return 0;
 }
@@ -947,60 +1007,100 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 
-	BT_DBG("intf %p", intf);
+	BT_DBG("%s called\n", __func__);
 
 	if (data->suspend_count++)
 		return 0;
 
-	cancel_work_sync(&data->work);
+	spin_lock_irq(&data->lock);
+	if (interface_to_usbdev(intf)->auto_pm &&
+		!usb_anchor_empty(&data->tx_anchor)) {
+		spin_unlock_irq(&data->lock);
+		return -EBUSY;
+	}
+
+	set_bit(BTUSB_SUSPENDING, &data->flags);
+	spin_unlock_irq(&data->lock);
 
+	cancel_work_sync(&data->work);
+	btusb_stop_traffic(data);
 	usb_kill_anchored_urbs(&data->tx_anchor);
+	return 0;
+}
 
-	usb_kill_anchored_urbs(&data->isoc_anchor);
-	usb_kill_anchored_urbs(&data->bulk_anchor);
-	usb_kill_anchored_urbs(&data->intr_anchor);
+static int play_deferred(struct btusb_data *data)
+{
+	struct urb *urb;
+	int err = 0;
 
-	return 0;
+	while ((urb = usb_get_from_anchor(&data->tx_anchor))) {
+		err = usb_submit_urb(urb, GFP_ATOMIC);
+		if (err < 0)
+			break;
+	}
+
+	usb_scuttle_anchored_urbs(&data->tx_anchor);
+	return err;
 }
 
+
 static int btusb_resume(struct usb_interface *intf)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 	struct hci_dev *hdev = data->hdev;
-	int err;
-
-	BT_DBG("intf %p", intf);
+	int ret = 0;
 
 	if (--data->suspend_count)
 		return 0;
 
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		return 0;
+	if (test_bit(HCI_RUNNING, &hdev->flags)) {
+		spin_lock_irq(&data->lock);
+		ret = play_deferred(data);
+		clear_bit(BTUSB_SUSPENDING, &data->flags);
+		spin_unlock_irq(&data->lock);
 
-	if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) {
-		err = btusb_submit_intr_urb(hdev, GFP_NOIO);
-		if (err < 0) {
-			clear_bit(BTUSB_INTR_RUNNING, &data->flags);
-			return err;
+		if (ret < 0) {
+			clear_bit(HCI_RUNNING, &hdev->flags);
+			return ret;
 		}
+
+		ret = btusb_submit_intr_urb(hdev, GFP_NOIO);
+		if (ret < 0) {
+			clear_bit(HCI_RUNNING, &hdev->flags);
+			return ret;
+		}
+	} else {
+		spin_lock_irq(&data->lock);
+		clear_bit(BTUSB_SUSPENDING, &data->flags);
+		spin_unlock_irq(&data->lock);
 	}
 
-	if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) {
-		err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
-		if (err < 0) {
+	if (hdev->conn_hash.acl_num > 0) {
+		ret = btusb_submit_bulk_urb(hdev, GFP_NOIO);
+		if (ret < 0) {
 			clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-			return err;
-		} else
-			btusb_submit_bulk_urb(hdev, GFP_NOIO);
+			return ret;
+		} else {
+			ret = btusb_submit_bulk_urb(hdev, GFP_NOIO);
+			if (ret < 0) {
+				clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+				usb_kill_anchored_urbs(&data->bulk_anchor);
+				return ret;
+			}
+		}
 	}
 
-	if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
-		if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0)
-			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
-		else
-			btusb_submit_isoc_urb(hdev, GFP_NOIO);
+	if (data->isoc) {
+		if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
+			ret = btusb_submit_isoc_urb(hdev, GFP_NOIO);
+			if (ret < 0)
+				clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+			else
+				btusb_submit_isoc_urb(hdev, GFP_NOIO);
+		}
 	}
 
+	schedule_work(&data->work);
 	return 0;
 }
 
@@ -1011,6 +1111,7 @@ static struct usb_driver btusb_driver = {
 	.suspend	= btusb_suspend,
 	.resume		= btusb_resume,
 	.id_table	= btusb_table,
+	.supports_autosuspend = 1,
 };
 
 static int __init btusb_init(void)

linux-2.6-driver-level-usb-autosuspend.diff:
 drivers/usb/core/driver.c |   15 +++++++++++++++
 include/linux/usb.h       |    4 ++++
 2 files changed, 19 insertions(+)

--- NEW FILE linux-2.6-driver-level-usb-autosuspend.diff ---
commit 0f592e33934bf6108e33e34f00b425f98ee833ef
Author: Matthew Garrett <mjg at redhat.com>
Date:   Wed Jul 8 19:04:23 2009 +0100

    usb: Allow drivers to enable USB autosuspend on a per-device basis
    
    USB autosuspend is currently only enabled by default for hubs. On other
    hardware the decision is made by userspace. This is unnecessary in cases
    where we know that the hardware supports autosuspend, so this patch adds
    a function to allow drivers to enable it at probe time.
    
    Signed-off-by: Matthew Garrett <mjg at redhat.com>

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 69e5773..6e81caa 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1560,6 +1560,21 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
 
 /**
+ * usb_device_autosuspend_enable - enable autosuspend on a device
+ * @udev: the usb_device to be autosuspended
+ *
+ * This routine should be called by an interface driver when it knows that
+ * the device in question supports USB autosuspend.
+ *
+ */
+void usb_device_autosuspend_enable(struct usb_device *udev)
+{
+	udev->autosuspend_disabled = 0;
+	udev->autoresume_disabled = 0;
+}
+EXPORT_SYMBOL_GPL(usb_device_autosuspend_enable);
+
+/**
  * usb_autopm_get_interface - increment a USB interface's PM-usage counter
  * @intf: the usb_interface whose counter should be incremented
  *
diff --git a/include/linux/usb.h b/include/linux/usb.h
index b1e3c2f..61bddbe 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -543,6 +543,7 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
 
 /* USB autosuspend and autoresume */
 #ifdef CONFIG_USB_SUSPEND
+extern void usb_device_autosuspend_enable(struct usb_device *udev);
 extern int usb_autopm_set_interface(struct usb_interface *intf);
 extern int usb_autopm_get_interface(struct usb_interface *intf);
 extern void usb_autopm_put_interface(struct usb_interface *intf);
@@ -568,6 +569,9 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
 
 #else
 
+static inline void usb_device_autosuspend_enable(struct usb_device *udev)
+{ }
+
 static inline int usb_autopm_set_interface(struct usb_interface *intf)
 { return 0; }
 

linux-2.6-fix-usb-serial-autosuspend.diff:
 usb-serial.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

--- NEW FILE linux-2.6-fix-usb-serial-autosuspend.diff ---
commit 3b8e1210f0a558145ba87eddb20f7b104676d6f6
Author: Oliber Neukum <oliver at neukum.org>
Date:   Sat Jul 18 07:19:04 2009 +0200

    usb: fix counter logic in opening serial converters
    
    the usage counter must be increased only after autoresumption

diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index bd7581b..c6f69c0 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -214,15 +214,13 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
 		goto bailout_port_put;
 	}
 
-	++port->port.count;
-
 	/* set up our port structure making the tty driver
 	 * remember our port object, and us it */
 	tty->driver_data = port;
 	tty_port_tty_set(&port->port, tty);
 
 	/* If the console is attached, the device is already open */
-	if (port->port.count == 1 && !port->console) {
+	if (!port->port.count && !port->console) {
 
 		/* lock this module before we call it
 		 * this may fail, which means we must bail out,
@@ -240,12 +238,16 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
 		if (retval)
 			goto bailout_module_put;
 
+		++port->port.count;
+
 		/* only call the device specific open if this
 		 * is the first time the port is opened */
 		retval = serial->type->open(tty, port, filp);
 		if (retval)
 			goto bailout_interface_put;
 		mutex_unlock(&serial->disc_mutex);
+	} else {
+		++port->port.count;
 	}
 	mutex_unlock(&port->mutex);
 	/* Now do the correct tty layer semantics */

linux-2.6-qcserial-autosuspend.diff:
 qcserial.c |    2 ++
 1 file changed, 2 insertions(+)

--- NEW FILE linux-2.6-qcserial-autosuspend.diff ---
commit b2bcfa17349e5a6a01170b5269ee261dbd762a0c
Author: Matthew Garrett <mjg at redhat.com>
Date:   Sat Jul 18 14:43:36 2009 +0100

    usb: enable autosuspend by default on qcserial
    
    All qcserial hardware supports autosuspend properly. Enable it by default.
    
    Signed-off-by: Matthew Garrett <mjg at redhat.com>

diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 7528b8d..959a176 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -74,6 +74,8 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
 	dbg("This Interface = %d", ifnum);
 
+	usb_device_autosuspend_enable(serial->dev);
+
 	switch (nintf) {
 	case 1:
 		/* QDL mode */


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1634
retrieving revision 1.1635
diff -u -p -r1.1634 -r1.1635
--- kernel.spec	17 Jul 2009 02:07:24 -0000	1.1634
+++ kernel.spec	18 Jul 2009 22:50:13 -0000	1.1635
@@ -616,6 +616,10 @@ Patch250: linux-2.6-debug-sizeof-structs
 Patch260: linux-2.6-debug-nmi-timeout.patch
 Patch270: linux-2.6-debug-taint-vm.patch
 Patch280: linux-2.6-debug-spinlock-taint.patch
+Patch300: linux-2.6-driver-level-usb-autosuspend.diff
+Patch301: linux-2.6-fix-usb-serial-autosuspend.diff
+Patch302: linux-2.6-qcserial-autosuspend.diff
+Patch303: linux-2.6-bluetooth-autosuspend.diff
 Patch340: linux-2.6-debug-vm-would-have-oomkilled.patch
 Patch360: linux-2.6-debug-always-inline-kzalloc.patch
 Patch380: linux-2.6-defaults-pci_no_msi.patch
@@ -1147,6 +1151,10 @@ ApplyPatch linux-2.6-execshield.patch
 ApplyPatch linux-2.6-nfsd4-proots.patch
 
 # USB
+ApplyPatch linux-2.6-driver-level-usb-autosuspend.diff
+ApplyPatch linux-2.6-fix-usb-serial-autosuspend.diff
+ApplyPatch linux-2.6-qcserial-autosuspend.diff
+ApplyPatch linux-2.6-bluetooth-autosuspend.diff
 
 # ACPI
 ApplyPatch linux-2.6-defaults-acpi-video.patch
@@ -1875,6 +1883,12 @@ fi
 # and build.
 
 %changelog
+* Sat Jul 18 2009 Matthew Garrett <mjg at redhat.com>
+- linux-2.6-driver-level-usb-autosuspend.diff - allow drivers to enable autopm
+- linux-2.6-fix-usb-serial-autosuspend.diff - fix generic usb-serial autopm
+- linux-2.6-qcserial-autosuspend.diff - enable autopm by default on qcserial
+- linux-2.6-bluetooth-autosuspend.diff - enable autopm by default on btusb
+
 * Thu Jul 16 2009 Chuck Ebbert <cebbert at redhat.com>
 - 2.6.31-rc3-git3
 




More information about the fedora-extras-commits mailing list