diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-07 11:36:05 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-07 11:36:05 -0700 |
commit | df2e2ae323420a682d025d4a636ecff274d96504 (patch) | |
tree | 13da938dde22fe8ec09cf16eeb85ecf0a3d33e1e | |
parent | 8ed491e1d162e90f33cfcd12b8017e739234aad9 (diff) | |
download | patches-df2e2ae323420a682d025d4a636ecff274d96504.tar.gz |
bugfixes for usb and staging
23 files changed, 2392 insertions, 1 deletions
@@ -19,6 +19,17 @@ driver-core.current/driver-core-allow-non-root-users-to-listen-to-uevents.patch ################################# usb.current/usb-gadget-fix-ethernet-link-reports-to-ethtool.patch usb.current/usb-ftdi_sio-add-vendor-project-id-for-jeti-specbos-1201-spectrometer.patch +usb.current/usb-option-add-ids-for-d-link-dwm-652-3.5g-modem.patch +usb.current/usb-qcserial-add-extra-device-ids.patch +usb.current/usb-fix-oops-in-cdc-wdm-in-case-of-malformed-descriptors.patch +usb.current/usb-musb_host-minor-enqueue-locking-fix.patch +usb.current/usb-usb-storage-augment-unusual_devs-entry-for-simple-tech-datafab.patch +usb.current/usb-musb_host-fix-ep0-fifo-flushing.patch +usb.current/usb-musb-bugfixes-for-multi-packet-txdma-support.patch +usb.current/usb-musb-sanitize-clearing-txcsr-dma-bits.patch +usb.current/usb-musb-fix-isochronous-txdma.patch +usb.current/usb-musb-fix-possible-panic-while-resuming.patch + ##################################################################### # Stuff to be merged after 2.6.30 is out @@ -54,6 +65,17 @@ staging/staging-sxg-convert-to-netdev_ops.patch staging/staging-wlan-ng-convert-to-netdev_ops.patch staging/staging-line6-convert-to-snd_card_create.patch staging/staging-rt2870-add-id-for-sitecom-wl-315.patch +staging/staging-aten2011-clean-up-some-tty-bits.patch +staging/staging-binder-remove-vm_exec-check.patch +staging/staging-binder-don-t-create-two-proc-entries-with-the-same-name-if-the-driver-is-opened-twice-in-one-process.patch +staging/staging-binder-mmap-fixes.patch +staging/staging-binder-add-more-offset-validation.patch +staging/staging-binder-keep-a-reference-to-the-files_struct-while-the-driver-is-mmapped.patch +staging/staging-binder-cast-to-uintptr_t-instead-of-size_t-when-aligning-pointers.patch +staging/staging-binder-prevent-the-wrong-thread-from-adding-a-transaction-to-the-stack.patch +staging/staging-binder-defer-flush-and-release-operations-to-avoid-deadlocks.patch +staging/staging-stlc45xx-should-depend-on-generic_hardirqs.patch +staging/revert-staging-slicoss-use-gfp_kernel-where-possible.patch # for after .30: @@ -66,3 +88,4 @@ staging/staging-rt2870-add-id-for-sitecom-wl-315.patch #staging/staging-add-intel-poulsbo-morrestown-drm-driver.patch + diff --git a/staging/revert-staging-slicoss-use-gfp_kernel-where-possible.patch b/staging/revert-staging-slicoss-use-gfp_kernel-where-possible.patch new file mode 100644 index 00000000000000..f22c4e9a34f391 --- /dev/null +++ b/staging/revert-staging-slicoss-use-gfp_kernel-where-possible.patch @@ -0,0 +1,38 @@ +From 2bb347361e2c19799431f56488a3f64de40a3aa6 Mon Sep 17 00:00:00 2001 +From: Lior Dotan <liodot@gmail.com> +Date: Wed, 11 Feb 2009 13:35:10 +0200 +Subject: Revert Staging: SLICOSS: use gfp_kernel where possible + +Revert commit 2bb347361e2c19799431f56488a3f64de40a3aa6 + +This commit has been reported to cause problems: + Mar 24 11:50:31 linuxdev kernel: BUG: sleeping function called from invalid context at mm/slub.c:1599 Mar 24 11:50:31 linuxdev kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 3251, name: avahi-daemon + +Cc: Lior Dotan <liodot@gmail.com> +Cc: Christopher Harrer <charrer@alacritech.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/slicoss/slicoss.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/slicoss/slicoss.c ++++ b/drivers/staging/slicoss/slicoss.c +@@ -1267,7 +1267,7 @@ static int slic_mcast_add_list(struct ad + } + + /* Doesn't already exist. Allocate a structure to hold it */ +- mcaddr = kmalloc(sizeof(struct mcast_address), GFP_KERNEL); ++ mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC); + if (mcaddr == NULL) + return 1; + +@@ -2291,7 +2291,7 @@ static u32 slic_card_locate(struct adapt + } + if (!physcard) { + /* no structure allocated for this physical card yet */ +- physcard = kzalloc(sizeof(struct physcard), GFP_KERNEL); ++ physcard = kzalloc(sizeof(struct physcard), GFP_ATOMIC); + ASSERT(physcard); + + physcard->next = slic_global.phys_card; diff --git a/staging/staging-aten2011-clean-up-some-tty-bits.patch b/staging/staging-aten2011-clean-up-some-tty-bits.patch new file mode 100644 index 00000000000000..0a951efb9ba48a --- /dev/null +++ b/staging/staging-aten2011-clean-up-some-tty-bits.patch @@ -0,0 +1,70 @@ +From alan@lxorguk.ukuu.org.uk Tue Apr 7 11:10:30 2009 +From: Alan Cox <alan@lxorguk.ukuu.org.uk> +Date: Tue, 07 Apr 2009 18:43:43 +0100 +Subject: Staging: aten2011: Clean up some tty bits +To: greg@kroah.com, linux-usb@vger.kernel.org +Message-ID: <20090407174342.19104.65668.stgit@t61.ukuu.org.uk> + +From: Alan Cox <alan@lxorguk.ukuu.org.uk> + +Minor fixes for tty layer stuff in this driver + +Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/uc2322/aten2011.c | 28 +++------------------------- + 1 file changed, 3 insertions(+), 25 deletions(-) + +--- a/drivers/staging/uc2322/aten2011.c ++++ b/drivers/staging/uc2322/aten2011.c +@@ -603,10 +603,9 @@ static void ATEN2011_bulk_out_data_callb + + tty = tty_port_tty_get(&ATEN2011_port->port->port); + +- if (tty && ATEN2011_port->open) { ++ if (tty && ATEN2011_port->open) + /* tell the tty driver that something has changed */ +- wake_up_interruptible(&tty->write_wait); +- } ++ tty_wakeup(tty); + + /* schedule_work(&ATEN2011_port->port->work); */ + tty_kref_put(tty); +@@ -825,12 +824,6 @@ static int ATEN2011_open(struct tty_stru + status = 0; + status = set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data); + +- /* force low_latency on so that our tty_push actually forces * +- * the data through,otherwise it is scheduled, and with * +- * high data rates (like with OHCI) data can get lost. */ +- +- if (tty) +- tty->low_latency = 1; + /* + * Check to see if we've set up our endpoint info yet + * (can't set it up in ATEN2011_startup as the structures +@@ -1473,22 +1466,7 @@ static void ATEN2011_set_termios(struct + + cflag = tty->termios->c_cflag; + +- if (!cflag) { +- dbg("%s %s", __func__, "cflag is NULL"); +- return; +- } +- +- /* check that they really want us to change something */ +- if (old_termios) { +- if ((cflag == old_termios->c_cflag) && +- (RELEVANT_IFLAG(tty->termios->c_iflag) == +- RELEVANT_IFLAG(old_termios->c_iflag))) { +- dbg("%s", "Nothing to change"); +- return; +- } +- } +- +- dbg("%s - clfag %08x iflag %08x", __func__, ++ dbg("%s - cflag %08x iflag %08x", __func__, + tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); + + if (old_termios) { diff --git a/staging/staging-binder-add-more-offset-validation.patch b/staging/staging-binder-add-more-offset-validation.patch new file mode 100644 index 00000000000000..e1e77d038cabb0 --- /dev/null +++ b/staging/staging-binder-add-more-offset-validation.patch @@ -0,0 +1,54 @@ +From arve@android.com Tue Apr 7 11:15:56 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:56 -0700 +Subject: Staging: binder: Add more offset validation. +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-4-git-send-email-arve@android.com> + + +Check that datasize is not smaller than one flat_binder_object. +Check that offsets are aligned. +Check that offsets_size is aligned. + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -1430,10 +1430,19 @@ binder_transaction(struct binder_proc *p + return_error = BR_FAILED_REPLY; + goto err_copy_data_failed; + } ++ if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { ++ binder_user_error("binder: %d:%d got transaction with " ++ "invalid offsets size, %zd\n", ++ proc->pid, thread->pid, tr->offsets_size); ++ return_error = BR_FAILED_REPLY; ++ goto err_bad_offset; ++ } + off_end = (void *)offp + tr->offsets_size; + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; +- if (*offp > t->buffer->data_size - sizeof(*fp)) { ++ if (*offp > t->buffer->data_size - sizeof(*fp) || ++ t->buffer->data_size < sizeof(*fp) || ++ !IS_ALIGNED(*offp, sizeof(void *))) { + binder_user_error("binder: %d:%d got transaction with " + "invalid offset, %zd\n", + proc->pid, thread->pid, *offp); +@@ -1651,7 +1660,9 @@ binder_transaction_buffer_release(struct + off_end = (void *)offp + buffer->offsets_size; + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; +- if (*offp > buffer->data_size - sizeof(*fp)) { ++ if (*offp > buffer->data_size - sizeof(*fp) || ++ buffer->data_size < sizeof(*fp) || ++ !IS_ALIGNED(*offp, sizeof(void *))) { + printk(KERN_ERR "binder: transaction release %d bad" + "offset %zd, size %zd\n", debug_id, *offp, buffer->data_size); + continue; diff --git a/staging/staging-binder-cast-to-uintptr_t-instead-of-size_t-when-aligning-pointers.patch b/staging/staging-binder-cast-to-uintptr_t-instead-of-size_t-when-aligning-pointers.patch new file mode 100644 index 00000000000000..fe1df85cf1f7ae --- /dev/null +++ b/staging/staging-binder-cast-to-uintptr_t-instead-of-size_t-when-aligning-pointers.patch @@ -0,0 +1,113 @@ +From arve@android.com Tue Apr 7 11:17:15 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:58 -0700 +Subject: Staging: binder: Cast to uintptr_t instead of size_t when aligning pointers +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-6-git-send-email-arve@android.com> + + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -246,7 +246,7 @@ struct binder_proc { + struct files_struct *files; + struct hlist_node release_files_node; + void *buffer; +- size_t user_buffer_offset; ++ ptrdiff_t user_buffer_offset; + + struct list_head buffers; + struct rb_root free_buffers; +@@ -614,7 +614,8 @@ static int binder_update_page_range(stru + proc->pid, page_addr); + goto err_map_kernel_failed; + } +- user_page_addr = (size_t)page_addr + proc->user_buffer_offset; ++ user_page_addr = ++ (uintptr_t)page_addr + proc->user_buffer_offset; + ret = vm_insert_page(vma, user_page_addr, page[0]); + if (ret) { + printk(KERN_ERR "binder: %d: binder_alloc_buf failed " +@@ -635,7 +636,7 @@ free_range: + page_addr -= PAGE_SIZE) { + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + if (vma) +- zap_page_range(vma, (size_t)page_addr + ++ zap_page_range(vma, (uintptr_t)page_addr + + proc->user_buffer_offset, PAGE_SIZE, NULL); + err_vm_insert_page_failed: + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); +@@ -716,18 +717,19 @@ static struct binder_buffer *binder_allo + "er %p size %zd\n", proc->pid, size, buffer, buffer_size); + + has_page_addr = +- (void *)(((size_t)buffer->data + buffer_size) & PAGE_MASK); ++ (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); + if (n == NULL) { + if (size + sizeof(struct binder_buffer) + 4 >= buffer_size) + buffer_size = size; /* no room for other buffers */ + else + buffer_size = size + sizeof(struct binder_buffer); + } +- end_page_addr = (void *)PAGE_ALIGN((size_t)buffer->data + buffer_size); ++ end_page_addr = ++ (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size); + if (end_page_addr > has_page_addr) + end_page_addr = has_page_addr; + if (binder_update_page_range(proc, 1, +- (void *)PAGE_ALIGN((size_t)buffer->data), end_page_addr, NULL)) ++ (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) + return NULL; + + rb_erase(best_fit, &proc->free_buffers); +@@ -758,12 +760,12 @@ static struct binder_buffer *binder_allo + + static void *buffer_start_page(struct binder_buffer *buffer) + { +- return (void *)((size_t)buffer & PAGE_MASK); ++ return (void *)((uintptr_t)buffer & PAGE_MASK); + } + + static void *buffer_end_page(struct binder_buffer *buffer) + { +- return (void *)(((size_t)(buffer + 1) - 1) & PAGE_MASK); ++ return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); + } + + static void binder_delete_free_buffer( +@@ -841,8 +843,8 @@ static void binder_free_buf( + } + + binder_update_page_range(proc, 0, +- (void *)PAGE_ALIGN((size_t)buffer->data), +- (void *)(((size_t)buffer->data + buffer_size) & PAGE_MASK), ++ (void *)PAGE_ALIGN((uintptr_t)buffer->data), ++ (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), + NULL); + rb_erase(&buffer->rb_node, &proc->allocated_buffers); + buffer->free = 1; +@@ -2347,7 +2349,7 @@ retry: + + tr.data_size = t->buffer->data_size; + tr.offsets_size = t->buffer->offsets_size; +- tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset); ++ tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset; + tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); + + if (put_user(cmd, (uint32_t __user *)ptr)) +@@ -2753,7 +2755,7 @@ static int binder_mmap(struct file *filp + goto err_get_vm_area_failed; + } + proc->buffer = area->addr; +- proc->user_buffer_offset = vma->vm_start - (size_t)proc->buffer; ++ proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; + + #ifdef CONFIG_CPU_CACHE_VIPT + if (cache_is_vipt_aliasing()) { diff --git a/staging/staging-binder-defer-flush-and-release-operations-to-avoid-deadlocks.patch b/staging/staging-binder-defer-flush-and-release-operations-to-avoid-deadlocks.patch new file mode 100644 index 00000000000000..919343f3b80946 --- /dev/null +++ b/staging/staging-binder-defer-flush-and-release-operations-to-avoid-deadlocks.patch @@ -0,0 +1,257 @@ +From arve@android.com Tue Apr 7 11:18:11 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:13:00 -0700 +Subject: Staging: binder: Defer flush and release operations to avoid deadlocks. +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-8-git-send-email-arve@android.com> + + +If a transaction that contains a file descriptor fails on a later object, +the new file descriptor needs to be closed. If this is a binder file +descriptor we would deadlock in flush. If there were no other references to +the file at this point release would also be called. + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 149 +++++++++++++++++++++++---------------- + 1 file changed, 88 insertions(+), 61 deletions(-) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -41,8 +41,8 @@ static int binder_last_id; + static struct proc_dir_entry *binder_proc_dir_entry_root; + static struct proc_dir_entry *binder_proc_dir_entry_proc; + static struct hlist_head binder_dead_nodes; +-static HLIST_HEAD(binder_release_files_list); +-static DEFINE_MUTEX(binder_release_files_lock); ++static HLIST_HEAD(binder_deferred_list); ++static DEFINE_MUTEX(binder_deferred_lock); + + static int binder_read_proc_proc( + char *page, char **start, off_t off, int count, int *eof, void *data); +@@ -234,6 +234,12 @@ struct binder_buffer { + uint8_t data[0]; + }; + ++enum { ++ BINDER_DEFERRED_PUT_FILES = 0x01, ++ BINDER_DEFERRED_FLUSH = 0x02, ++ BINDER_DEFERRED_RELEASE = 0x04, ++}; ++ + struct binder_proc { + struct hlist_node proc_node; + struct rb_root threads; +@@ -244,7 +250,8 @@ struct binder_proc { + struct vm_area_struct *vma; + struct task_struct *tsk; + struct files_struct *files; +- struct hlist_node release_files_node; ++ struct hlist_node deferred_work_node; ++ int deferred_work; + void *buffer; + ptrdiff_t user_buffer_offset; + +@@ -310,6 +317,8 @@ struct binder_transaction { + uid_t sender_euid; + }; + ++static void binder_defer_work(struct binder_proc *proc, int defer); ++ + /* + * copied from get_unused_fd_flags + */ +@@ -2677,33 +2686,6 @@ static void binder_vma_open(struct vm_ar + dump_stack(); + } + +-static void binder_release_files(struct work_struct *work) +-{ +- struct binder_proc *proc; +- struct files_struct *files; +- do { +- mutex_lock(&binder_lock); +- mutex_lock(&binder_release_files_lock); +- if (!hlist_empty(&binder_release_files_list)) { +- proc = hlist_entry(binder_release_files_list.first, +- struct binder_proc, release_files_node); +- hlist_del_init(&proc->release_files_node); +- files = proc->files; +- if (files) +- proc->files = NULL; +- } else { +- proc = NULL; +- files = NULL; +- } +- mutex_unlock(&binder_release_files_lock); +- mutex_unlock(&binder_lock); +- if (files) +- put_files_struct(files); +- } while (proc); +-} +- +-static DECLARE_WORK(binder_release_files_work, binder_release_files); +- + static void binder_vma_close(struct vm_area_struct *vma) + { + struct binder_proc *proc = vma->vm_private_data; +@@ -2714,13 +2696,7 @@ static void binder_vma_close(struct vm_a + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); + proc->vma = NULL; +- mutex_lock(&binder_release_files_lock); +- if (proc->files) { +- hlist_add_head(&proc->release_files_node, +- &binder_release_files_list); +- schedule_work(&binder_release_files_work); +- } +- mutex_unlock(&binder_release_files_lock); ++ binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); + } + + static struct vm_operations_struct binder_vm_ops = { +@@ -2853,11 +2829,17 @@ static int binder_open(struct inode *nod + + static int binder_flush(struct file *filp, fl_owner_t id) + { +- struct rb_node *n; + struct binder_proc *proc = filp->private_data; +- int wake_count = 0; + +- mutex_lock(&binder_lock); ++ binder_defer_work(proc, BINDER_DEFERRED_FLUSH); ++ ++ return 0; ++} ++ ++static void binder_deferred_flush(struct binder_proc *proc) ++{ ++ struct rb_node *n; ++ int wake_count = 0; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; +@@ -2867,36 +2849,34 @@ static int binder_flush(struct file *fil + } + } + wake_up_interruptible_all(&proc->wait); +- mutex_unlock(&binder_lock); + + if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) + printk(KERN_INFO "binder_flush: %d woke %d threads\n", proc->pid, wake_count); +- +- return 0; + } + + static int binder_release(struct inode *nodp, struct file *filp) + { +- struct hlist_node *pos; +- struct binder_transaction *t; +- struct rb_node *n; +- struct files_struct *files; + struct binder_proc *proc = filp->private_data; +- int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; +- + if (binder_proc_dir_entry_proc) { + char strbuf[11]; + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); + remove_proc_entry(strbuf, binder_proc_dir_entry_proc); + } +- mutex_lock(&binder_lock); +- mutex_lock(&binder_release_files_lock); +- if (!hlist_unhashed(&proc->release_files_node)) +- hlist_del(&proc->release_files_node); +- files = proc->files; +- if (files) +- proc->files = NULL; +- mutex_unlock(&binder_release_files_lock); ++ ++ binder_defer_work(proc, BINDER_DEFERRED_RELEASE); ++ ++ return 0; ++} ++ ++static void binder_deferred_release(struct binder_proc *proc) ++{ ++ struct hlist_node *pos; ++ struct binder_transaction *t; ++ struct rb_node *n; ++ int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; ++ ++ BUG_ON(proc->vma); ++ BUG_ON(proc->files); + + hlist_del(&proc->proc_node); + if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { +@@ -2971,7 +2951,6 @@ static int binder_release(struct inode * + } + + binder_stats.obj_deleted[BINDER_STAT_PROC]++; +- mutex_unlock(&binder_lock); + + page_count = 0; + if (proc->pages) { +@@ -2995,9 +2974,57 @@ static int binder_release(struct inode * + proc->pid, threads, nodes, incoming_refs, outgoing_refs, active_transactions, buffers, page_count); + + kfree(proc); +- if (files) +- put_files_struct(files); +- return 0; ++} ++ ++static void binder_deferred_func(struct work_struct *work) ++{ ++ struct binder_proc *proc; ++ struct files_struct *files; ++ ++ int defer; ++ do { ++ mutex_lock(&binder_lock); ++ mutex_lock(&binder_deferred_lock); ++ if (!hlist_empty(&binder_deferred_list)) { ++ proc = hlist_entry(binder_deferred_list.first, ++ struct binder_proc, deferred_work_node); ++ hlist_del_init(&proc->deferred_work_node); ++ defer = proc->deferred_work; ++ proc->deferred_work = 0; ++ } else { ++ proc = NULL; ++ defer = 0; ++ } ++ mutex_unlock(&binder_deferred_lock); ++ ++ files = NULL; ++ if (defer & BINDER_DEFERRED_PUT_FILES) ++ if ((files = proc->files)) ++ proc->files = NULL; ++ ++ if (defer & BINDER_DEFERRED_FLUSH) ++ binder_deferred_flush(proc); ++ ++ if (defer & BINDER_DEFERRED_RELEASE) ++ binder_deferred_release(proc); /* frees proc */ ++ ++ mutex_unlock(&binder_lock); ++ if (files) ++ put_files_struct(files); ++ } while (proc); ++} ++static DECLARE_WORK(binder_deferred_work, binder_deferred_func); ++ ++static void binder_defer_work(struct binder_proc *proc, int defer) ++{ ++ mutex_lock(&binder_deferred_lock); ++ proc->deferred_work |= defer; ++ if (hlist_unhashed(&proc->deferred_work_node)) { ++ hlist_add_head(&proc->deferred_work_node, ++ &binder_deferred_list); ++ schedule_work(&binder_deferred_work); ++ } ++ mutex_unlock(&binder_deferred_lock); + } + + static char *print_binder_transaction(char *buf, char *end, const char *prefix, struct binder_transaction *t) diff --git a/staging/staging-binder-don-t-create-two-proc-entries-with-the-same-name-if-the-driver-is-opened-twice-in-one-process.patch b/staging/staging-binder-don-t-create-two-proc-entries-with-the-same-name-if-the-driver-is-opened-twice-in-one-process.patch new file mode 100644 index 00000000000000..78cef07a893fe7 --- /dev/null +++ b/staging/staging-binder-don-t-create-two-proc-entries-with-the-same-name-if-the-driver-is-opened-twice-in-one-process.patch @@ -0,0 +1,26 @@ +From arve@android.com Tue Apr 7 11:14:55 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:54 -0700 +Subject: Staging: binder: Don't create two proc entries with the same name if the driver is opened twice in one process. +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-2-git-send-email-arve@android.com> + + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -2776,6 +2776,7 @@ static int binder_open(struct inode *nod + if (binder_proc_dir_entry_proc) { + char strbuf[11]; + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); ++ remove_proc_entry(strbuf, binder_proc_dir_entry_proc); + create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc); + } + diff --git a/staging/staging-binder-keep-a-reference-to-the-files_struct-while-the-driver-is-mmapped.patch b/staging/staging-binder-keep-a-reference-to-the-files_struct-while-the-driver-is-mmapped.patch new file mode 100644 index 00000000000000..0b816e8806bc7b --- /dev/null +++ b/staging/staging-binder-keep-a-reference-to-the-files_struct-while-the-driver-is-mmapped.patch @@ -0,0 +1,235 @@ +From arve@android.com Tue Apr 7 11:16:36 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:57 -0700 +Subject: Staging: binder: Keep a reference to the files_struct while the driver is mmapped +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-5-git-send-email-arve@android.com> + + +This prevents breaking fget_light if a single threaded application +allows incoming file descriptors (in replies or on nodes). +Should also prevent inserting a file in the wrong files_struct if the +receving process execs in the middle of a transaction (between +task_get_unused_fd_flags and task_fd_install). + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 79 +++++++++++++++++++++++++++++++-------- + 1 file changed, 63 insertions(+), 16 deletions(-) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -41,6 +41,8 @@ static int binder_last_id; + static struct proc_dir_entry *binder_proc_dir_entry_root; + static struct proc_dir_entry *binder_proc_dir_entry_proc; + static struct hlist_head binder_dead_nodes; ++static HLIST_HEAD(binder_release_files_list); ++static DEFINE_MUTEX(binder_release_files_lock); + + static int binder_read_proc_proc( + char *page, char **start, off_t off, int count, int *eof, void *data); +@@ -241,6 +243,8 @@ struct binder_proc { + int pid; + struct vm_area_struct *vma; + struct task_struct *tsk; ++ struct files_struct *files; ++ struct hlist_node release_files_node; + void *buffer; + size_t user_buffer_offset; + +@@ -309,9 +313,9 @@ struct binder_transaction { + /* + * copied from get_unused_fd_flags + */ +-int task_get_unused_fd_flags(struct task_struct *tsk, int flags) ++int task_get_unused_fd_flags(struct binder_proc *proc, int flags) + { +- struct files_struct *files = get_files_struct(tsk); ++ struct files_struct *files = proc->files; + int fd, error; + struct fdtable *fdt; + unsigned long rlim_cur; +@@ -333,9 +337,9 @@ repeat: + * will limit the total number of files that can be opened. + */ + rlim_cur = 0; +- if (lock_task_sighand(tsk, &irqs)) { +- rlim_cur = tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; +- unlock_task_sighand(tsk, &irqs); ++ if (lock_task_sighand(proc->tsk, &irqs)) { ++ rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; ++ unlock_task_sighand(proc->tsk, &irqs); + } + if (fd >= rlim_cur) + goto out; +@@ -371,7 +375,6 @@ repeat: + + out: + spin_unlock(&files->file_lock); +- put_files_struct(files); + return error; + } + +@@ -379,9 +382,9 @@ out: + * copied from fd_install + */ + static void task_fd_install( +- struct task_struct *tsk, unsigned int fd, struct file *file) ++ struct binder_proc *proc, unsigned int fd, struct file *file) + { +- struct files_struct *files = get_files_struct(tsk); ++ struct files_struct *files = proc->files; + struct fdtable *fdt; + + if (files == NULL) +@@ -392,7 +395,6 @@ static void task_fd_install( + BUG_ON(fdt->fd[fd] != NULL); + rcu_assign_pointer(fdt->fd[fd], file); + spin_unlock(&files->file_lock); +- put_files_struct(files); + } + + /* +@@ -409,10 +411,10 @@ static void __put_unused_fd(struct files + /* + * copied from sys_close + */ +-static long task_close_fd(struct task_struct *tsk, unsigned int fd) ++static long task_close_fd(struct binder_proc *proc, unsigned int fd) + { + struct file *filp; +- struct files_struct *files = get_files_struct(tsk); ++ struct files_struct *files = proc->files; + struct fdtable *fdt; + int retval; + +@@ -439,12 +441,10 @@ static long task_close_fd(struct task_st + retval == -ERESTART_RESTARTBLOCK)) + retval = -EINTR; + +- put_files_struct(files); + return retval; + + out_unlock: + spin_unlock(&files->file_lock); +- put_files_struct(files); + return -EBADF; + } + +@@ -1549,13 +1549,13 @@ binder_transaction(struct binder_proc *p + return_error = BR_FAILED_REPLY; + goto err_fget_failed; + } +- target_fd = task_get_unused_fd_flags(target_proc->tsk, O_CLOEXEC); ++ target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); + if (target_fd < 0) { + fput(file); + return_error = BR_FAILED_REPLY; + goto err_get_unused_fd_failed; + } +- task_fd_install(target_proc->tsk, target_fd, file); ++ task_fd_install(target_proc, target_fd, file); + if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) + printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd); + /* TODO: fput? */ +@@ -1698,7 +1698,7 @@ binder_transaction_buffer_release(struct + if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) + printk(KERN_INFO " fd %ld\n", fp->handle); + if (failed_at) +- task_close_fd(proc->tsk, fp->handle); ++ task_close_fd(proc, fp->handle); + break; + + default: +@@ -2663,6 +2663,34 @@ static void binder_vma_open(struct vm_ar + (unsigned long)pgprot_val(vma->vm_page_prot)); + dump_stack(); + } ++ ++static void binder_release_files(struct work_struct *work) ++{ ++ struct binder_proc *proc; ++ struct files_struct *files; ++ do { ++ mutex_lock(&binder_lock); ++ mutex_lock(&binder_release_files_lock); ++ if (!hlist_empty(&binder_release_files_list)) { ++ proc = hlist_entry(binder_release_files_list.first, ++ struct binder_proc, release_files_node); ++ hlist_del_init(&proc->release_files_node); ++ files = proc->files; ++ if (files) ++ proc->files = NULL; ++ } else { ++ proc = NULL; ++ files = NULL; ++ } ++ mutex_unlock(&binder_release_files_lock); ++ mutex_unlock(&binder_lock); ++ if (files) ++ put_files_struct(files); ++ } while (proc); ++} ++ ++static DECLARE_WORK(binder_release_files_work, binder_release_files); ++ + static void binder_vma_close(struct vm_area_struct *vma) + { + struct binder_proc *proc = vma->vm_private_data; +@@ -2673,6 +2701,13 @@ static void binder_vma_close(struct vm_a + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); + proc->vma = NULL; ++ mutex_lock(&binder_release_files_lock); ++ if (proc->files) { ++ hlist_add_head(&proc->release_files_node, ++ &binder_release_files_list); ++ schedule_work(&binder_release_files_work); ++ } ++ mutex_unlock(&binder_release_files_lock); + } + + static struct vm_operations_struct binder_vm_ops = { +@@ -2751,6 +2786,7 @@ static int binder_mmap(struct file *filp + binder_insert_free_buffer(proc, buffer); + proc->free_async_space = proc->buffer_size / 2; + barrier(); ++ proc->files = get_files_struct(current); + proc->vma = vma; + + /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ +@@ -2831,6 +2867,7 @@ static int binder_release(struct inode * + struct hlist_node *pos; + struct binder_transaction *t; + struct rb_node *n; ++ struct files_struct *files; + struct binder_proc *proc = filp->private_data; + int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; + +@@ -2840,6 +2877,14 @@ static int binder_release(struct inode * + remove_proc_entry(strbuf, binder_proc_dir_entry_proc); + } + mutex_lock(&binder_lock); ++ mutex_lock(&binder_release_files_lock); ++ if (!hlist_unhashed(&proc->release_files_node)) ++ hlist_del(&proc->release_files_node); ++ files = proc->files; ++ if (files) ++ proc->files = NULL; ++ mutex_unlock(&binder_release_files_lock); ++ + hlist_del(&proc->proc_node); + if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { + if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) +@@ -2937,6 +2982,8 @@ static int binder_release(struct inode * + proc->pid, threads, nodes, incoming_refs, outgoing_refs, active_transactions, buffers, page_count); + + kfree(proc); ++ if (files) ++ put_files_struct(files); + return 0; + } + diff --git a/staging/staging-binder-mmap-fixes.patch b/staging/staging-binder-mmap-fixes.patch new file mode 100644 index 00000000000000..4e7bc31b1afd78 --- /dev/null +++ b/staging/staging-binder-mmap-fixes.patch @@ -0,0 +1,49 @@ +From arve@android.com Tue Apr 7 11:15:28 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:55 -0700 +Subject: Staging: binder: mmap fixes. +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-3-git-send-email-arve@android.com> + + +Only allow a binder file pointer to be mmapped once. The buffer management +code cannot deal with more then one area. +Also remove leftover mutex_unlock if mmap fails. + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -2694,6 +2694,12 @@ static int binder_mmap(struct file *filp + } + vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; + ++ if (proc->buffer) { ++ ret = -EBUSY; ++ failure_string = "already mapped"; ++ goto err_already_mapped; ++ } ++ + area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); + if (area == NULL) { + ret = -ENOMEM; +@@ -2741,10 +2747,12 @@ static int binder_mmap(struct file *filp + + err_alloc_small_buf_failed: + kfree(proc->pages); ++ proc->pages = NULL; + err_alloc_pages_failed: + vfree(proc->buffer); ++ proc->buffer = NULL; + err_get_vm_area_failed: +- mutex_unlock(&binder_lock); ++err_already_mapped: + err_bad_arg: + printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); + return ret; diff --git a/staging/staging-binder-prevent-the-wrong-thread-from-adding-a-transaction-to-the-stack.patch b/staging/staging-binder-prevent-the-wrong-thread-from-adding-a-transaction-to-the-stack.patch new file mode 100644 index 00000000000000..7baa939283c24d --- /dev/null +++ b/staging/staging-binder-prevent-the-wrong-thread-from-adding-a-transaction-to-the-stack.patch @@ -0,0 +1,39 @@ +From arve@android.com Tue Apr 7 11:17:44 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:59 -0700 +Subject: Staging: binder: Prevent the wrong thread from adding a transaction to the stack. +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-7-git-send-email-arve@android.com> + + +If a thread is part of a transaction stack, it is only allowed to make +another call if it was the target of the top transaction on the stack. + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -1343,6 +1343,17 @@ binder_transaction(struct binder_proc *p + if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { + struct binder_transaction *tmp; + tmp = thread->transaction_stack; ++ if (tmp->to_thread != thread) { ++ binder_user_error("binder: %d:%d got new " ++ "transaction with bad transaction stack" ++ ", transaction %d has target %d:%d\n", ++ proc->pid, thread->pid, tmp->debug_id, ++ tmp->to_proc ? tmp->to_proc->pid : 0, ++ tmp->to_thread ? ++ tmp->to_thread->pid : 0); ++ return_error = BR_FAILED_REPLY; ++ goto err_bad_call_stack; ++ } + while (tmp) { + if (tmp->from && tmp->from->proc == target_proc) + target_thread = tmp->from; diff --git a/staging/staging-binder-remove-vm_exec-check.patch b/staging/staging-binder-remove-vm_exec-check.patch new file mode 100644 index 00000000000000..892660780062fe --- /dev/null +++ b/staging/staging-binder-remove-vm_exec-check.patch @@ -0,0 +1,32 @@ +From arve@android.com Tue Apr 7 11:14:11 2009 +From: Arve Hj�nnev�g <arve@android.com> +Date: Mon, 6 Apr 2009 15:12:53 -0700 +Subject: Staging: binder: Remove VM_EXEC check. +To: gregkh@suse.de +Cc: swetland@google.com, viro@zeniv.linux.org.uk, torvalds@linux-foundation.org, hugh@veritas.com, Arve Hj�nnev�g <arve@android.com> +Message-ID: <1239055980-24607-1-git-send-email-arve@android.com> + + +Many platforms do not support mappings without VM_EXEC. + +Signed-off-by: Arve Hj�nnev�g <arve@android.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/android/binder.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -54,11 +54,7 @@ static int binder_read_proc_proc( + #define SZ_4M 0x400000 + #endif + +-#ifndef __i386__ +-#define FORBIDDEN_MMAP_FLAGS (VM_WRITE | VM_EXEC) +-#else + #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) +-#endif + + #define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) + diff --git a/staging/staging-stlc45xx-should-depend-on-generic_hardirqs.patch b/staging/staging-stlc45xx-should-depend-on-generic_hardirqs.patch new file mode 100644 index 00000000000000..6fdfd0cebdd17b --- /dev/null +++ b/staging/staging-stlc45xx-should-depend-on-generic_hardirqs.patch @@ -0,0 +1,31 @@ +From geert@linux-m68k.org Tue Apr 7 11:18:56 2009 +From: Geert Uytterhoeven <geert@linux-m68k.org> +Date: Mon, 6 Apr 2009 15:15:55 +0200 (CEST) +Subject: Staging: STLC45XX should depend on GENERIC_HARDIRQS +To: Kalle Valo <kalle.valo@nokia.com>, Greg Kroah-Hartman <gregkh@suse.de> +Cc: Linux Kernel Development <linux-kernel@vger.kernel.org> +Message-ID: <Pine.LNX.4.64.0904061515001.13923@anakin> + + +m68k allmodconfig: +| drivers/staging/stlc45xx/stlc45xx.c: In function 'stlc45xx_probe': +| drivers/staging/stlc45xx/stlc45xx.c:2456: error: implicit declaration of function 'set_irq_type' +| make[6]: *** [drivers/staging/stlc45xx/stlc45xx.o] Error 1 + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/stlc45xx/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/stlc45xx/Kconfig ++++ b/drivers/staging/stlc45xx/Kconfig +@@ -1,6 +1,6 @@ + config STLC45XX + tristate "stlc4550/4560 support" +- depends on MAC80211 && WLAN_80211 && SPI_MASTER ++ depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS + ---help--- + This is a driver for stlc4550 and stlc4560 chipsets. + diff --git a/usb.current/usb-fix-oops-in-cdc-wdm-in-case-of-malformed-descriptors.patch b/usb.current/usb-fix-oops-in-cdc-wdm-in-case-of-malformed-descriptors.patch new file mode 100644 index 00000000000000..0104a231a80bf9 --- /dev/null +++ b/usb.current/usb-fix-oops-in-cdc-wdm-in-case-of-malformed-descriptors.patch @@ -0,0 +1,31 @@ +From oliver@neukum.org Tue Apr 7 11:12:23 2009 +From: Oliver Neukum <oliver@neukum.org> +Date: Sat, 4 Apr 2009 09:25:15 +0200 +Subject: USB: fix oops in cdc-wdm in case of malformed descriptors +To: greg@kroah.com, Chuck Ebbert <cebbert@redhat.com> +Message-ID: <200904040925.23539.oliver@neukum.org> +Content-Disposition: inline + + +cdc-wdm needs to ignore extremely malformed descriptors. + +Signed-off-by: Oliver Neukum <oliver@neukum.org> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/class/cdc-wdm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -652,7 +652,7 @@ next_desc: + + iface = &intf->altsetting[0]; + ep = &iface->endpoint[0].desc; +- if (!usb_endpoint_is_int_in(ep)) { ++ if (!ep || !usb_endpoint_is_int_in(ep)) { + rv = -EINVAL; + goto err; + } diff --git a/usb.current/usb-musb-bugfixes-for-multi-packet-txdma-support.patch b/usb.current/usb-musb-bugfixes-for-multi-packet-txdma-support.patch new file mode 100644 index 00000000000000..5566b494406c9e --- /dev/null +++ b/usb.current/usb-musb-bugfixes-for-multi-packet-txdma-support.patch @@ -0,0 +1,206 @@ +From david-b@pacbell.net Tue Apr 7 11:30:22 2009 +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Date: Thu, 26 Mar 2009 18:26:40 -0700 +Subject: USB: musb: bugfixes for multi-packet TXDMA support +To: Greg KH <greg@kroah.com> +Cc: felipe.balbi@nokia.com, Sergei Shtylyov <sshtylyov@ru.mvista.com> +Message-ID: <200903261826.40856.david-b@pacbell.net> +Content-Disposition: inline + + +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> + +We really want to use DMA mode 1 for all multi-packet transfers; +that's one IRQ on DMA completion, instead of one per packet. + +There is an important issue with such transfers, especially on +the host side: when such transfers end with a full-size packet, +we must defer musb_dma_completion() calls until the FIFO empties. +Else we report URB completions too soon, and may clobber data in +the FIFO fifo when writing the next packet (losing data). + +The Inventra DMA support uses DMA mode 1, but it ignores that +issue. The CPPI DMA support uses mode 0, but doesn't handle +its TXPKTRDY interrupts quite right either; it can get stale +"packet ready" interrupts, and report transfer completion too +early using slightly different code paths, also losing data. + +So I'm solving it in a generic way -- by adding a sort of the +"interrupt filter" into musb_host_tx(), catching these cases +where a DMA completion IRQ doesn't suffice and removing some +needlessly controller-specific logic. When a TXDMA interrupt +happens and DMA request mode 1 is active, that filter resets +to mode 0 and defers URB completion processing until TXPKTRDY, +unless the FIFO is already empty. Related filtering logic in +Inventra and CPPI code gets removed. + +Since it should be competely safe now to use the DMA request +mode 1 for host side transfers with the CPPI DMA controller, +set it in musb_h_tx_dma_start() ... now renamed (and shared). + +[ dbrownell@users.sourceforge.net: don't introduce more +CamElCase; use more concise explanations ] + +Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Cc: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/cppi_dma.c | 22 ------------- + drivers/usb/musb/musb_host.c | 68 +++++++++++++++++++++++++++++++++++++++++-- + drivers/usb/musb/musbhsdma.c | 7 +--- + 3 files changed, 69 insertions(+), 28 deletions(-) + +--- a/drivers/usb/musb/cppi_dma.c ++++ b/drivers/usb/musb/cppi_dma.c +@@ -1228,27 +1228,7 @@ void cppi_completion(struct musb *musb, + + hw_ep = tx_ch->hw_ep; + +- /* Peripheral role never repurposes the +- * endpoint, so immediate completion is +- * safe. Host role waits for the fifo +- * to empty (TXPKTRDY irq) before going +- * to the next queued bulk transfer. +- */ +- if (is_host_active(cppi->musb)) { +-#if 0 +- /* WORKAROUND because we may +- * not always get TXKPTRDY ... +- */ +- int csr; +- +- csr = musb_readw(hw_ep->regs, +- MUSB_TXCSR); +- if (csr & MUSB_TXCSR_TXPKTRDY) +-#endif +- completed = false; +- } +- if (completed) +- musb_dma_completion(musb, index + 1, 1); ++ musb_dma_completion(musb, index + 1, 1); + + } else { + /* Bigger transfer than we could fit in +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -4,6 +4,7 @@ + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation ++ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -168,13 +169,15 @@ static inline void musb_h_tx_start(struc + + } + +-static inline void cppi_host_txdma_start(struct musb_hw_ep *ep) ++static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep) + { + u16 txcsr; + + /* NOTE: no locks here; caller should lock and select EP */ + txcsr = musb_readw(ep->regs, MUSB_TXCSR); + txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS; ++ if (is_cppi_enabled()) ++ txcsr |= MUSB_TXCSR_DMAMODE; + musb_writew(ep->regs, MUSB_TXCSR, txcsr); + } + +@@ -279,7 +282,7 @@ start: + if (!hw_ep->tx_channel) + musb_h_tx_start(hw_ep); + else if (is_cppi_enabled() || tusb_dma_omap()) +- cppi_host_txdma_start(hw_ep); ++ musb_h_tx_dma_start(hw_ep); + } + } + +@@ -1250,6 +1253,67 @@ void musb_host_tx(struct musb *musb, u8 + + } + ++ if (is_dma_capable() && dma && !status) { ++ /* ++ * DMA has completed. But if we're using DMA mode 1 (multi ++ * packet DMA), we need a terminal TXPKTRDY interrupt before ++ * we can consider this transfer completed, lest we trash ++ * its last packet when writing the next URB's data. So we ++ * switch back to mode 0 to get that interrupt; we'll come ++ * back here once it happens. ++ */ ++ if (tx_csr & MUSB_TXCSR_DMAMODE) { ++ /* ++ * We shouldn't clear DMAMODE with DMAENAB set; so ++ * clear them in a safe order. That should be OK ++ * once TXPKTRDY has been set (and I've never seen ++ * it being 0 at this moment -- DMA interrupt latency ++ * is significant) but if it hasn't been then we have ++ * no choice but to stop being polite and ignore the ++ * programmer's guide... :-) ++ * ++ * Note that we must write TXCSR with TXPKTRDY cleared ++ * in order not to re-trigger the packet send (this bit ++ * can't be cleared by CPU), and there's another caveat: ++ * TXPKTRDY may be set shortly and then cleared in the ++ * double-buffered FIFO mode, so we do an extra TXCSR ++ * read for debouncing... ++ */ ++ tx_csr &= musb_readw(epio, MUSB_TXCSR); ++ if (tx_csr & MUSB_TXCSR_TXPKTRDY) { ++ tx_csr &= ~(MUSB_TXCSR_DMAENAB | ++ MUSB_TXCSR_TXPKTRDY); ++ musb_writew(epio, MUSB_TXCSR, ++ tx_csr | MUSB_TXCSR_H_WZC_BITS); ++ } ++ tx_csr &= ~(MUSB_TXCSR_DMAMODE | ++ MUSB_TXCSR_TXPKTRDY); ++ musb_writew(epio, MUSB_TXCSR, ++ tx_csr | MUSB_TXCSR_H_WZC_BITS); ++ ++ /* ++ * There is no guarantee that we'll get an interrupt ++ * after clearing DMAMODE as we might have done this ++ * too late (after TXPKTRDY was cleared by controller). ++ * Re-read TXCSR as we have spoiled its previous value. ++ */ ++ tx_csr = musb_readw(epio, MUSB_TXCSR); ++ } ++ ++ /* ++ * We may get here from a DMA completion or TXPKTRDY interrupt. ++ * In any case, we must check the FIFO status here and bail out ++ * only if the FIFO still has data -- that should prevent the ++ * "missed" TXPKTRDY interrupts and deal with double-buffered ++ * FIFO mode too... ++ */ ++ if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { ++ DBG(2, "DMA complete but packet still in FIFO, " ++ "CSR %04x\n", tx_csr); ++ return; ++ } ++ } ++ + /* REVISIT this looks wrong... */ + if (!status || dma || usb_pipeisoc(pipe)) { + if (dma) +--- a/drivers/usb/musb/musbhsdma.c ++++ b/drivers/usb/musb/musbhsdma.c +@@ -304,12 +304,9 @@ static irqreturn_t dma_controller_irq(in + musb_channel->epnum, + MUSB_TXCSR), + MUSB_TXCSR_TXPKTRDY); +- } else { +- musb_dma_completion( +- musb, +- musb_channel->epnum, +- musb_channel->transmit); + } ++ musb_dma_completion(musb, musb_channel->epnum, ++ musb_channel->transmit); + } + } + } diff --git a/usb.current/usb-musb-fix-isochronous-txdma.patch b/usb.current/usb-musb-fix-isochronous-txdma.patch new file mode 100644 index 00000000000000..b790b16dc8b061 --- /dev/null +++ b/usb.current/usb-musb-fix-isochronous-txdma.patch @@ -0,0 +1,424 @@ +From david-b@pacbell.net Tue Apr 7 11:31:07 2009 +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Date: Thu, 26 Mar 2009 18:29:19 -0700 +Subject: USB: musb: fix isochronous TXDMA (take 2) +To: Greg KH <greg@kroah.com> +Cc: felipe.balbi@nokia.com, Sergei Shtylyov <sshtylyov@ru.mvista.com> +Message-ID: <200903261829.19682.david-b@pacbell.net> +Content-Disposition: inline + + +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> + +Multi-frame isochronous TX URBs transfers in DMA mode never +complete with CPPI DMA because musb_host_tx() doesn't restart +DMA on the second frame, only emitting a debug message. +With Inventra DMA they complete, but in PIO mode. To fix: + + - Factor out programming of the DMA transfer from + musb_ep_program() into musb_tx_dma_program(); + + - Reorder the code at the end of musb_host_tx() to + facilitate the fallback to PIO iff DMA fails; + + - Handle the buffer offset consistently for both + PIO and DMA modes; + + - Add an argument to musb_ep_program() for the same + reason (it only worked correctly with non-zero + offset of the first frame in PIO mode); + + - Set the completed isochronous frame descriptor's + 'actual_length' and 'status' fields correctly in + DMA mode. + +Also, since CPPI reportedly doesn't like sending isochronous +packets in the RNDIS mode, change the criterion for this +mode to be used only for multi-packet transfers. (There's +no need for that mode in the single-packet case anyway.) + +[ dbrownell@users.sourceforge.net: split comment paragraph +into bullet list, shrink patch delta, style tweaks ] + +Signed-off-by: Pavel Kiryukhin <pkiryukhin@ru.mvista.com> +Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/cppi_dma.c | 1 + drivers/usb/musb/musb_host.c | 227 +++++++++++++++++++------------------------ + 2 files changed, 105 insertions(+), 123 deletions(-) + +--- a/drivers/usb/musb/cppi_dma.c ++++ b/drivers/usb/musb/cppi_dma.c +@@ -579,6 +579,7 @@ cppi_next_tx_segment(struct musb *musb, + * trigger the "send a ZLP?" confusion. + */ + rndis = (maxpacket & 0x3f) == 0 ++ && length > maxpacket + && length < 0xffff + && (length % maxpacket) != 0; + +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -97,8 +97,8 @@ + + + static void musb_ep_program(struct musb *musb, u8 epnum, +- struct urb *urb, unsigned int nOut, +- u8 *buf, u32 len); ++ struct urb *urb, int is_out, ++ u8 *buf, u32 offset, u32 len); + + /* + * Clear TX fifo. Needed to avoid BABBLE errors. +@@ -192,9 +192,10 @@ musb_start_urb(struct musb *musb, int is + { + u16 frame; + u32 len; +- void *buf; + void __iomem *mbase = musb->mregs; + struct urb *urb = next_urb(qh); ++ void *buf = urb->transfer_buffer; ++ u32 offset = 0; + struct musb_hw_ep *hw_ep = qh->hw_ep; + unsigned pipe = urb->pipe; + u8 address = usb_pipedevice(pipe); +@@ -217,7 +218,7 @@ musb_start_urb(struct musb *musb, int is + case USB_ENDPOINT_XFER_ISOC: + qh->iso_idx = 0; + qh->frame = 0; +- buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset; ++ offset = urb->iso_frame_desc[0].offset; + len = urb->iso_frame_desc[0].length; + break; + default: /* bulk, interrupt */ +@@ -235,14 +236,14 @@ musb_start_urb(struct musb *musb, int is + case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; + default: s = "-intr"; break; + }; s; }), +- epnum, buf, len); ++ epnum, buf + offset, len); + + /* Configure endpoint */ + if (is_in || hw_ep->is_shared_fifo) + hw_ep->in_qh = qh; + else + hw_ep->out_qh = qh; +- musb_ep_program(musb, epnum, urb, !is_in, buf, len); ++ musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len); + + /* transmit may have more work: start it when it is time */ + if (is_in) +@@ -253,7 +254,6 @@ musb_start_urb(struct musb *musb, int is + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: + DBG(3, "check whether there's still time for periodic Tx\n"); +- qh->iso_idx = 0; + frame = musb_readw(mbase, MUSB_FRAME); + /* FIXME this doesn't implement that scheduling policy ... + * or handle framecounter wrapping +@@ -634,14 +634,68 @@ musb_rx_reinit(struct musb *musb, struct + ep->rx_reinit = 0; + } + ++static bool musb_tx_dma_program(struct dma_controller *dma, ++ struct musb_hw_ep *hw_ep, struct musb_qh *qh, ++ struct urb *urb, u32 offset, u32 length) ++{ ++ struct dma_channel *channel = hw_ep->tx_channel; ++ void __iomem *epio = hw_ep->regs; ++ u16 pkt_size = qh->maxpacket; ++ u16 csr; ++ u8 mode; ++ ++#ifdef CONFIG_USB_INVENTRA_DMA ++ if (length > channel->max_len) ++ length = channel->max_len; ++ ++ csr = musb_readw(epio, MUSB_TXCSR); ++ if (length > pkt_size) { ++ mode = 1; ++ csr |= MUSB_TXCSR_AUTOSET ++ | MUSB_TXCSR_DMAMODE ++ | MUSB_TXCSR_DMAENAB; ++ } else { ++ mode = 0; ++ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); ++ csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ ++ } ++ channel->desired_mode = mode; ++ musb_writew(epio, MUSB_TXCSR, csr); ++#else ++ if (!is_cppi_enabled() && !tusb_dma_omap()) ++ return false; ++ ++ channel->actual_len = 0; ++ ++ /* ++ * TX uses "RNDIS" mode automatically but needs help ++ * to identify the zero-length-final-packet case. ++ */ ++ mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; ++#endif ++ ++ qh->segsize = length; ++ ++ if (!dma->channel_program(channel, pkt_size, mode, ++ urb->transfer_dma + offset, length)) { ++ dma->channel_release(channel); ++ hw_ep->tx_channel = NULL; ++ ++ csr = musb_readw(epio, MUSB_TXCSR); ++ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); ++ musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); ++ return false; ++ } ++ return true; ++} + + /* + * Program an HDRC endpoint as per the given URB + * Context: irqs blocked, controller lock held + */ + static void musb_ep_program(struct musb *musb, u8 epnum, +- struct urb *urb, unsigned int is_out, +- u8 *buf, u32 len) ++ struct urb *urb, int is_out, ++ u8 *buf, u32 offset, u32 len) + { + struct dma_controller *dma_controller; + struct dma_channel *dma_channel; +@@ -768,82 +822,9 @@ static void musb_ep_program(struct musb + else + load_count = min((u32) packet_sz, len); + +-#ifdef CONFIG_USB_INVENTRA_DMA +- if (dma_channel) { +- qh->segsize = min(len, dma_channel->max_len); +- if (qh->segsize <= packet_sz) +- dma_channel->desired_mode = 0; +- else +- dma_channel->desired_mode = 1; +- +- if (dma_channel->desired_mode == 0) { +- /* Against the programming guide */ +- csr |= (MUSB_TXCSR_DMAENAB); +- } else +- csr |= (MUSB_TXCSR_AUTOSET +- | MUSB_TXCSR_DMAENAB +- | MUSB_TXCSR_DMAMODE); +- musb_writew(epio, MUSB_TXCSR, csr); +- +- dma_ok = dma_controller->channel_program( +- dma_channel, packet_sz, +- dma_channel->desired_mode, +- urb->transfer_dma, +- qh->segsize); +- if (dma_ok) { +- load_count = 0; +- } else { +- dma_controller->channel_release(dma_channel); +- if (is_out) +- hw_ep->tx_channel = NULL; +- else +- hw_ep->rx_channel = NULL; +- dma_channel = NULL; +- +- /* +- * The programming guide says that we must +- * clear the DMAENAB bit before DMAMODE... +- */ +- csr = musb_readw(epio, MUSB_TXCSR); +- csr &= ~(MUSB_TXCSR_DMAENAB +- | MUSB_TXCSR_AUTOSET); +- musb_writew(epio, MUSB_TXCSR, csr); +- csr &= ~MUSB_TXCSR_DMAMODE; +- musb_writew(epio, MUSB_TXCSR, csr); +- } +- } +-#endif +- +- /* candidate for DMA */ +- if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { +- +- /* Defer enabling DMA */ +- dma_channel->actual_len = 0L; +- qh->segsize = len; +- +- /* TX uses "rndis" mode automatically, but needs help +- * to identify the zero-length-final-packet case. +- */ +- dma_ok = dma_controller->channel_program( +- dma_channel, packet_sz, +- (urb->transfer_flags +- & URB_ZERO_PACKET) +- == URB_ZERO_PACKET, +- urb->transfer_dma, +- qh->segsize); +- if (dma_ok) { +- load_count = 0; +- } else { +- dma_controller->channel_release(dma_channel); +- hw_ep->tx_channel = NULL; +- dma_channel = NULL; +- +- /* REVISIT there's an error path here that +- * needs handling: can't do dma, but +- * there's no pio buffer address... +- */ +- } +- } ++ if (dma_channel && musb_tx_dma_program(dma_controller, ++ hw_ep, qh, urb, offset, len)) ++ load_count = 0; + + if (load_count) { + /* PIO to load FIFO */ +@@ -903,7 +884,7 @@ static void musb_ep_program(struct musb + dma_channel, packet_sz, + !(urb->transfer_flags + & URB_SHORT_NOT_OK), +- urb->transfer_dma, ++ urb->transfer_dma + offset, + qh->segsize); + if (!dma_ok) { + dma_controller->channel_release( +@@ -1146,8 +1127,8 @@ void musb_host_tx(struct musb *musb, u8 + int pipe; + bool done = false; + u16 tx_csr; +- size_t wLength = 0; +- u8 *buf = NULL; ++ size_t length = 0; ++ size_t offset = 0; + struct urb *urb; + struct musb_hw_ep *hw_ep = musb->endpoints + epnum; + void __iomem *epio = hw_ep->regs; +@@ -1165,7 +1146,7 @@ void musb_host_tx(struct musb *musb, u8 + /* with CPPI, DMA sometimes triggers "extra" irqs */ + if (!urb) { + DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); +- goto finish; ++ return; + } + + pipe = urb->pipe; +@@ -1202,7 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 + musb_writew(epio, MUSB_TXCSR, + MUSB_TXCSR_H_WZC_BITS + | MUSB_TXCSR_TXPKTRDY); +- goto finish; ++ return; + } + + if (status) { +@@ -1234,8 +1215,7 @@ void musb_host_tx(struct musb *musb, u8 + /* second cppi case */ + if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { + DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); +- goto finish; +- ++ return; + } + + if (is_dma_capable() && dma && !status) { +@@ -1299,25 +1279,25 @@ void musb_host_tx(struct musb *musb, u8 + } + } + +- /* REVISIT this looks wrong... */ + if (!status || dma || usb_pipeisoc(pipe)) { + if (dma) +- wLength = dma->actual_len; ++ length = dma->actual_len; + else +- wLength = qh->segsize; +- qh->offset += wLength; ++ length = qh->segsize; ++ qh->offset += length; + + if (usb_pipeisoc(pipe)) { + struct usb_iso_packet_descriptor *d; + + d = urb->iso_frame_desc + qh->iso_idx; +- d->actual_length = qh->segsize; ++ d->actual_length = length; ++ d->status = status; + if (++qh->iso_idx >= urb->number_of_packets) { + done = true; + } else { + d++; +- buf = urb->transfer_buffer + d->offset; +- wLength = d->length; ++ offset = d->offset; ++ length = d->length; + } + } else if (dma) { + done = true; +@@ -1330,10 +1310,8 @@ void musb_host_tx(struct musb *musb, u8 + & URB_ZERO_PACKET)) + done = true; + if (!done) { +- buf = urb->transfer_buffer +- + qh->offset; +- wLength = urb->transfer_buffer_length +- - qh->offset; ++ offset = qh->offset; ++ length = urb->transfer_buffer_length - offset; + } + } + } +@@ -1352,28 +1330,31 @@ void musb_host_tx(struct musb *musb, u8 + urb->status = status; + urb->actual_length = qh->offset; + musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); ++ return; ++ } else if (usb_pipeisoc(pipe) && dma) { ++ if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, ++ offset, length)) ++ return; ++ } else if (tx_csr & MUSB_TXCSR_DMAENAB) { ++ DBG(1, "not complete, but DMA enabled?\n"); ++ return; ++ } + +- } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) { +- /* WARN_ON(!buf); */ +- +- /* REVISIT: some docs say that when hw_ep->tx_double_buffered, +- * (and presumably, fifo is not half-full) we should write TWO +- * packets before updating TXCSR ... other docs disagree ... +- */ +- /* PIO: start next packet in this URB */ +- if (wLength > qh->maxpacket) +- wLength = qh->maxpacket; +- musb_write_fifo(hw_ep, wLength, buf); +- qh->segsize = wLength; +- +- musb_ep_select(mbase, epnum); +- musb_writew(epio, MUSB_TXCSR, +- MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); +- } else +- DBG(1, "not complete, but dma enabled?\n"); ++ /* ++ * PIO: start next packet in this URB. ++ * ++ * REVISIT: some docs say that when hw_ep->tx_double_buffered, ++ * (and presumably, FIFO is not half-full) we should write *two* ++ * packets before updating TXCSR; other docs disagree... ++ */ ++ if (length > qh->maxpacket) ++ length = qh->maxpacket; ++ musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); ++ qh->segsize = length; + +-finish: +- return; ++ musb_ep_select(mbase, epnum); ++ musb_writew(epio, MUSB_TXCSR, ++ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); + } + + diff --git a/usb.current/usb-musb-fix-possible-panic-while-resuming.patch b/usb.current/usb-musb-fix-possible-panic-while-resuming.patch new file mode 100644 index 00000000000000..eee27b0e6f048e --- /dev/null +++ b/usb.current/usb-musb-fix-possible-panic-while-resuming.patch @@ -0,0 +1,64 @@ +From david-b@pacbell.net Tue Apr 7 11:31:35 2009 +From: Kim Kyuwon <q1.kim@samsung.com> +Date: Thu, 26 Mar 2009 18:56:51 -0700 +Subject: USB: musb: fix possible panic while resuming +To: Greg KH <greg@kroah.com> +Cc: felipe.balbi@nokia.com, Kim Kyuwon <q1.kim@samsung.com> +Message-ID: <200903261856.52215.david-b@pacbell.net> +Content-Disposition: inline + + +From: Kim Kyuwon <q1.kim@samsung.com> + +During driver resume processing, musb could cause a kernel panic. +Fix by enabling the clock earlier, with the resume_early method. + +Signed-off-by: Kim Kyuwon <q1.kim@samsung.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_core.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -2170,26 +2170,22 @@ static int musb_suspend(struct platform_ + return 0; + } + +-static int musb_resume(struct platform_device *pdev) ++static int musb_resume_early(struct platform_device *pdev) + { +- unsigned long flags; + struct musb *musb = dev_to_musb(&pdev->dev); + + if (!musb->clock) + return 0; + +- spin_lock_irqsave(&musb->lock, flags); +- + if (musb->set_clock) + musb->set_clock(musb->clock, 1); + else + clk_enable(musb->clock); + + /* for static cmos like DaVinci, register values were preserved +- * unless for some reason the whole soc powered down and we're +- * not treating that as a whole-system restart (e.g. swsusp) ++ * unless for some reason the whole soc powered down or the USB ++ * module got reset through the PSC (vs just being disabled). + */ +- spin_unlock_irqrestore(&musb->lock, flags); + return 0; + } + +@@ -2207,7 +2203,7 @@ static struct platform_driver musb_drive + .remove = __devexit_p(musb_remove), + .shutdown = musb_shutdown, + .suspend = musb_suspend, +- .resume = musb_resume, ++ .resume_early = musb_resume_early, + }; + + /*-------------------------------------------------------------------------*/ diff --git a/usb.current/usb-musb-sanitize-clearing-txcsr-dma-bits.patch b/usb.current/usb-musb-sanitize-clearing-txcsr-dma-bits.patch new file mode 100644 index 00000000000000..a857ba87c96d52 --- /dev/null +++ b/usb.current/usb-musb-sanitize-clearing-txcsr-dma-bits.patch @@ -0,0 +1,360 @@ +From david-b@pacbell.net Tue Apr 7 11:30:45 2009 +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Date: Thu, 26 Mar 2009 18:27:47 -0700 +Subject: USB: musb: sanitize clearing TXCSR DMA bits (take 2) +To: Greg KH <greg@kroah.com> +Cc: felipe.balbi@nokia.com, Sergei Shtylyov <sshtylyov@ru.mvista.com> +Message-ID: <200903261827.47294.david-b@pacbell.net> +Content-Disposition: inline + + +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> + +The MUSB code clears TXCSR_DMAMODE incorrectly in several +places, either asserting that TXCSR_DMAENAB is clear (when +sometimes it isn't) or clearing both bits together. Recent +versions of the programmer's guide require DMAENAB to be +cleared first, although some older ones didn't. + +Fix this and while at it: + + - In musb_gadget::txstate(), stop clearing the AUTOSET + and DMAMODE bits for the CPPI case since they never + get set anyway (the former bit is reserved on DaVinci); + but do clear the DMAENAB bit on the DMA error path. + + - In musb_host::musb_ep_program(), remove the duplicate + DMA controller specific code code clearing the TXCSR + previous state, add the code to clear TXCSR DMA bits + on the Inventra DMA error path, to replace such code + (executed late) on the PIO path. + + - In musbhsdma::dma_channel_abort()/dma_controller_irq(), + add/use the 'offset' variable to avoid MUSB_EP_OFFSET() + invocations on every RXCSR/TXCSR access. + +[dbrownell@users.sourceforge.net: don't introduce CamelCase, +shrink diff] + +Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_gadget.c | 33 +++++++++++------ + drivers/usb/musb/musb_host.c | 79 ++++++++++++++++------------------------- + drivers/usb/musb/musbhsdma.c | 57 ++++++++++++++++++----------- + 3 files changed, 89 insertions(+), 80 deletions(-) + +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -165,9 +165,15 @@ static void nuke(struct musb_ep *ep, con + if (is_dma_capable() && ep->dma) { + struct dma_controller *c = ep->musb->dma_controller; + int value; ++ + if (ep->is_in) { ++ /* ++ * The programming guide says that we must not clear ++ * the DMAMODE bit before DMAENAB, so we only ++ * clear it in the second write... ++ */ + musb_writew(epio, MUSB_TXCSR, +- 0 | MUSB_TXCSR_FLUSHFIFO); ++ MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO); + musb_writew(epio, MUSB_TXCSR, + 0 | MUSB_TXCSR_FLUSHFIFO); + } else { +@@ -230,7 +236,7 @@ static inline int max_ep_writesize(struc + | IN token(s) are recd from Host. + | -> DMA interrupt on completion + | calls TxAvail. +- | -> stop DMA, ~DmaEenab, ++ | -> stop DMA, ~DMAENAB, + | -> set TxPktRdy for last short pkt or zlp + | -> Complete Request + | -> Continue next request (call txstate) +@@ -315,9 +321,17 @@ static void txstate(struct musb *musb, s + request->dma, request_size); + if (use_dma) { + if (musb_ep->dma->desired_mode == 0) { +- /* ASSERT: DMAENAB is clear */ +- csr &= ~(MUSB_TXCSR_AUTOSET | +- MUSB_TXCSR_DMAMODE); ++ /* ++ * We must not clear the DMAMODE bit ++ * before the DMAENAB bit -- and the ++ * latter doesn't always get cleared ++ * before we get here... ++ */ ++ csr &= ~(MUSB_TXCSR_AUTOSET ++ | MUSB_TXCSR_DMAENAB); ++ musb_writew(epio, MUSB_TXCSR, csr ++ | MUSB_TXCSR_P_WZC_BITS); ++ csr &= ~MUSB_TXCSR_DMAMODE; + csr |= (MUSB_TXCSR_DMAENAB | + MUSB_TXCSR_MODE); + /* against programming guide */ +@@ -334,10 +348,7 @@ static void txstate(struct musb *musb, s + + #elif defined(CONFIG_USB_TI_CPPI_DMA) + /* program endpoint CSR first, then setup DMA */ +- csr &= ~(MUSB_TXCSR_AUTOSET +- | MUSB_TXCSR_DMAMODE +- | MUSB_TXCSR_P_UNDERRUN +- | MUSB_TXCSR_TXPKTRDY); ++ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); + csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, + (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) +@@ -364,8 +375,8 @@ static void txstate(struct musb *musb, s + if (!use_dma) { + c->channel_release(musb_ep->dma); + musb_ep->dma = NULL; +- /* ASSERT: DMAENAB clear */ +- csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE); ++ csr &= ~MUSB_TXCSR_DMAENAB; ++ musb_writew(epio, MUSB_TXCSR, csr); + /* invariant: prequest->buf is non-null */ + } + #elif defined(CONFIG_USB_TUSB_OMAP_DMA) +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -593,10 +593,17 @@ musb_rx_reinit(struct musb *musb, struct + csr = musb_readw(ep->regs, MUSB_TXCSR); + if (csr & MUSB_TXCSR_MODE) { + musb_h_tx_flush_fifo(ep); ++ csr = musb_readw(ep->regs, MUSB_TXCSR); + musb_writew(ep->regs, MUSB_TXCSR, +- MUSB_TXCSR_FRCDATATOG); ++ csr | MUSB_TXCSR_FRCDATATOG); + } +- /* clear mode (and everything else) to enable Rx */ ++ ++ /* ++ * Clear the MODE bit (and everything else) to enable Rx. ++ * NOTE: we mustn't clear the DMAMODE bit before DMAENAB. ++ */ ++ if (csr & MUSB_TXCSR_DMAMODE) ++ musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE); + musb_writew(ep->regs, MUSB_TXCSR, 0); + + /* scrub all previous state, clearing toggle */ +@@ -693,12 +700,17 @@ static void musb_ep_program(struct musb + + /* general endpoint setup */ + if (epnum) { +- /* ASSERT: TXCSR_DMAENAB was already cleared */ +- + /* flush all old state, set default */ + musb_h_tx_flush_fifo(hw_ep); ++ ++ /* ++ * We must not clear the DMAMODE bit before or in ++ * the same cycle with the DMAENAB bit, so we clear ++ * the latter first... ++ */ + csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT +- | MUSB_TXCSR_DMAMODE ++ | MUSB_TXCSR_AUTOSET ++ | MUSB_TXCSR_DMAENAB + | MUSB_TXCSR_FRCDATATOG + | MUSB_TXCSR_H_RXSTALL + | MUSB_TXCSR_H_ERROR +@@ -706,16 +718,15 @@ static void musb_ep_program(struct musb + ); + csr |= MUSB_TXCSR_MODE; + +- if (usb_gettoggle(urb->dev, +- qh->epnum, 1)) ++ if (usb_gettoggle(urb->dev, qh->epnum, 1)) + csr |= MUSB_TXCSR_H_WR_DATATOGGLE + | MUSB_TXCSR_H_DATATOGGLE; + else + csr |= MUSB_TXCSR_CLRDATATOG; + +- /* twice in case of double packet buffering */ + musb_writew(epio, MUSB_TXCSR, csr); + /* REVISIT may need to clear FLUSHFIFO ... */ ++ csr &= ~MUSB_TXCSR_DMAMODE; + musb_writew(epio, MUSB_TXCSR, csr); + csr = musb_readw(epio, MUSB_TXCSR); + } else { +@@ -759,34 +770,19 @@ static void musb_ep_program(struct musb + + #ifdef CONFIG_USB_INVENTRA_DMA + if (dma_channel) { +- +- /* clear previous state */ +- csr = musb_readw(epio, MUSB_TXCSR); +- csr &= ~(MUSB_TXCSR_AUTOSET +- | MUSB_TXCSR_DMAMODE +- | MUSB_TXCSR_DMAENAB); +- csr |= MUSB_TXCSR_MODE; +- musb_writew(epio, MUSB_TXCSR, +- csr | MUSB_TXCSR_MODE); +- + qh->segsize = min(len, dma_channel->max_len); +- + if (qh->segsize <= packet_sz) + dma_channel->desired_mode = 0; + else + dma_channel->desired_mode = 1; + +- + if (dma_channel->desired_mode == 0) { +- csr &= ~(MUSB_TXCSR_AUTOSET +- | MUSB_TXCSR_DMAMODE); ++ /* Against the programming guide */ + csr |= (MUSB_TXCSR_DMAENAB); +- /* against programming guide */ + } else + csr |= (MUSB_TXCSR_AUTOSET + | MUSB_TXCSR_DMAENAB + | MUSB_TXCSR_DMAMODE); +- + musb_writew(epio, MUSB_TXCSR, csr); + + dma_ok = dma_controller->channel_program( +@@ -803,6 +799,17 @@ static void musb_ep_program(struct musb + else + hw_ep->rx_channel = NULL; + dma_channel = NULL; ++ ++ /* ++ * The programming guide says that we must ++ * clear the DMAENAB bit before DMAMODE... ++ */ ++ csr = musb_readw(epio, MUSB_TXCSR); ++ csr &= ~(MUSB_TXCSR_DMAENAB ++ | MUSB_TXCSR_AUTOSET); ++ musb_writew(epio, MUSB_TXCSR, csr); ++ csr &= ~MUSB_TXCSR_DMAMODE; ++ musb_writew(epio, MUSB_TXCSR, csr); + } + } + #endif +@@ -810,18 +817,7 @@ static void musb_ep_program(struct musb + /* candidate for DMA */ + if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { + +- /* program endpoint CSRs first, then setup DMA. +- * assume CPPI setup succeeds. +- * defer enabling dma. +- */ +- csr = musb_readw(epio, MUSB_TXCSR); +- csr &= ~(MUSB_TXCSR_AUTOSET +- | MUSB_TXCSR_DMAMODE +- | MUSB_TXCSR_DMAENAB); +- csr |= MUSB_TXCSR_MODE; +- musb_writew(epio, MUSB_TXCSR, +- csr | MUSB_TXCSR_MODE); +- ++ /* Defer enabling DMA */ + dma_channel->actual_len = 0L; + qh->segsize = len; + +@@ -850,20 +846,9 @@ static void musb_ep_program(struct musb + } + + if (load_count) { +- /* ASSERT: TXCSR_DMAENAB was already cleared */ +- + /* PIO to load FIFO */ + qh->segsize = load_count; + musb_write_fifo(hw_ep, load_count, buf); +- csr = musb_readw(epio, MUSB_TXCSR); +- csr &= ~(MUSB_TXCSR_DMAENAB +- | MUSB_TXCSR_DMAMODE +- | MUSB_TXCSR_AUTOSET); +- /* write CSR */ +- csr |= MUSB_TXCSR_MODE; +- +- if (epnum) +- musb_writew(epio, MUSB_TXCSR, csr); + } + + /* re-enable interrupt */ +--- a/drivers/usb/musb/musbhsdma.c ++++ b/drivers/usb/musb/musbhsdma.c +@@ -195,30 +195,32 @@ static int dma_channel_abort(struct dma_ + void __iomem *mbase = musb_channel->controller->base; + + u8 bchannel = musb_channel->idx; ++ int offset; + u16 csr; + + if (channel->status == MUSB_DMA_STATUS_BUSY) { + if (musb_channel->transmit) { ++ offset = MUSB_EP_OFFSET(musb_channel->epnum, ++ MUSB_TXCSR); + +- csr = musb_readw(mbase, +- MUSB_EP_OFFSET(musb_channel->epnum, +- MUSB_TXCSR)); +- csr &= ~(MUSB_TXCSR_AUTOSET | +- MUSB_TXCSR_DMAENAB | +- MUSB_TXCSR_DMAMODE); +- musb_writew(mbase, +- MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR), +- csr); ++ /* ++ * The programming guide says that we must clear ++ * the DMAENAB bit before the DMAMODE bit... ++ */ ++ csr = musb_readw(mbase, offset); ++ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); ++ musb_writew(mbase, offset, csr); ++ csr &= ~MUSB_TXCSR_DMAMODE; ++ musb_writew(mbase, offset, csr); + } else { +- csr = musb_readw(mbase, +- MUSB_EP_OFFSET(musb_channel->epnum, +- MUSB_RXCSR)); ++ offset = MUSB_EP_OFFSET(musb_channel->epnum, ++ MUSB_RXCSR); ++ ++ csr = musb_readw(mbase, offset); + csr &= ~(MUSB_RXCSR_AUTOCLEAR | + MUSB_RXCSR_DMAENAB | + MUSB_RXCSR_DMAMODE); +- musb_writew(mbase, +- MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR), +- csr); ++ musb_writew(mbase, offset, csr); + } + + musb_writew(mbase, +@@ -296,14 +298,25 @@ static irqreturn_t dma_controller_irq(in + && ((channel->desired_mode == 0) + || (channel->actual_len & + (musb_channel->max_packet_sz - 1))) +- ) { ++ ) { ++ u8 epnum = musb_channel->epnum; ++ int offset = MUSB_EP_OFFSET(epnum, ++ MUSB_TXCSR); ++ u16 txcsr; ++ ++ /* ++ * The programming guide says that we ++ * must clear DMAENAB before DMAMODE. ++ */ ++ musb_ep_select(mbase, epnum); ++ txcsr = musb_readw(mbase, offset); ++ txcsr &= ~(MUSB_TXCSR_DMAENAB ++ | MUSB_TXCSR_AUTOSET); ++ musb_writew(mbase, offset, txcsr); + /* Send out the packet */ +- musb_ep_select(mbase, +- musb_channel->epnum); +- musb_writew(mbase, MUSB_EP_OFFSET( +- musb_channel->epnum, +- MUSB_TXCSR), +- MUSB_TXCSR_TXPKTRDY); ++ txcsr &= ~MUSB_TXCSR_DMAMODE; ++ txcsr |= MUSB_TXCSR_TXPKTRDY; ++ musb_writew(mbase, offset, txcsr); + } + musb_dma_completion(musb, musb_channel->epnum, + musb_channel->transmit); diff --git a/usb.current/usb-musb_host-fix-ep0-fifo-flushing.patch b/usb.current/usb-musb_host-fix-ep0-fifo-flushing.patch new file mode 100644 index 00000000000000..edb42c45948678 --- /dev/null +++ b/usb.current/usb-musb_host-fix-ep0-fifo-flushing.patch @@ -0,0 +1,116 @@ +From david-b@pacbell.net Tue Apr 7 11:29:56 2009 +From: David Brownell <david-b@pacbell.net> +Date: Thu, 26 Mar 2009 17:38:30 -0700 +Subject: USB: musb_host, fix ep0 fifo flushing +To: Greg KH <greg@kroah.com> +Cc: felipe.balbi@nokia.com +Message-ID: <200903261738.30625.david-b@pacbell.net> +Content-Disposition: inline + + +From: David Brownell <dbrownell@users.sourceforge.net> + +The MUSB host side can't share generic TX FIFO flush logic +with EP0; the EP0 TX status register bits are different +from those for other entpoints. + +Resolve this issue by providing a new EP0-specific routine +to flush and reset the FIFO, which pays careful attention to +restrictions listed in the latest programmer's guide. This +gets rid of an open issue whereby the usbtest control write +test (#14) failed. + +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_host.c | 43 +++++++++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 14 deletions(-) + +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -125,6 +125,29 @@ static void musb_h_tx_flush_fifo(struct + } + } + ++static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) ++{ ++ void __iomem *epio = ep->regs; ++ u16 csr; ++ int retries = 5; ++ ++ /* scrub any data left in the fifo */ ++ do { ++ csr = musb_readw(epio, MUSB_TXCSR); ++ if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY))) ++ break; ++ musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO); ++ csr = musb_readw(epio, MUSB_TXCSR); ++ udelay(10); ++ } while (--retries); ++ ++ WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n", ++ ep->epnum, csr); ++ ++ /* and reset for the next transfer */ ++ musb_writew(epio, MUSB_TXCSR, 0); ++} ++ + /* + * Start transmit. Caller is responsible for locking shared resources. + * musb must be locked. +@@ -694,10 +717,7 @@ static void musb_ep_program(struct musb + csr = musb_readw(epio, MUSB_TXCSR); + } else { + /* endpoint 0: just flush */ +- musb_writew(epio, MUSB_CSR0, +- csr | MUSB_CSR0_FLUSHFIFO); +- musb_writew(epio, MUSB_CSR0, +- csr | MUSB_CSR0_FLUSHFIFO); ++ musb_h_ep0_flush_fifo(hw_ep); + } + + /* target addr and (for multipoint) hub addr/port */ +@@ -1063,11 +1083,7 @@ irqreturn_t musb_h_ep0_irq(struct musb * + csr &= ~MUSB_CSR0_H_NAKTIMEOUT; + musb_writew(epio, MUSB_CSR0, csr); + } else { +- csr |= MUSB_CSR0_FLUSHFIFO; +- musb_writew(epio, MUSB_CSR0, csr); +- musb_writew(epio, MUSB_CSR0, csr); +- csr &= ~MUSB_CSR0_H_NAKTIMEOUT; +- musb_writew(epio, MUSB_CSR0, csr); ++ musb_h_ep0_flush_fifo(hw_ep); + } + + musb_writeb(epio, MUSB_NAKLIMIT0, 0); +@@ -1081,10 +1097,7 @@ irqreturn_t musb_h_ep0_irq(struct musb * + * SHOULD NEVER HAPPEN! */ + ERR("no URB for end 0\n"); + +- musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO); +- musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO); +- musb_writew(epio, MUSB_CSR0, 0); +- ++ musb_h_ep0_flush_fifo(hw_ep); + goto done; + } + +@@ -2043,7 +2056,7 @@ static int musb_cleanup_urb(struct urb * + * endpoint's irq status here to avoid bogus irqs. + * clearing that status is platform-specific... + */ +- } else { ++ } else if (ep->epnum) { + musb_h_tx_flush_fifo(ep); + csr = musb_readw(epio, MUSB_TXCSR); + csr &= ~(MUSB_TXCSR_AUTOSET +@@ -2057,6 +2070,8 @@ static int musb_cleanup_urb(struct urb * + musb_writew(epio, MUSB_TXCSR, csr); + /* flush cpu writebuffer */ + csr = musb_readw(epio, MUSB_TXCSR); ++ } else { ++ musb_h_ep0_flush_fifo(ep); + } + if (status == 0) + musb_advance_schedule(ep->musb, urb, ep, is_in); diff --git a/usb.current/usb-musb_host-minor-enqueue-locking-fix.patch b/usb.current/usb-musb_host-minor-enqueue-locking-fix.patch new file mode 100644 index 00000000000000..26aa6a2b7d2635 --- /dev/null +++ b/usb.current/usb-musb_host-minor-enqueue-locking-fix.patch @@ -0,0 +1,64 @@ +From david-b@pacbell.net Tue Apr 7 11:19:45 2009 +From: David Brownell <david-b@pacbell.net> +Date: Thu, 26 Mar 2009 17:36:57 -0700 +Subject: USB: musb_host, minor enqueue locking fix (v2) +To: Greg KH <greg@kroah.com> +Cc: <felipe.balbi@nokia.com> +Message-ID: <200903261736.58123.david-b@pacbell.net> +Content-Disposition: inline + + +From: David Brownell <dbrownell@users.sourceforge.net> + +Someone noted that the enqueue path used an unlocked access +for usb_host_endpoint->hcpriv ... fix that, by being safe +and always accessing it under spinlock protection. + +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_host.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -1841,7 +1841,7 @@ static int musb_urb_enqueue( + unsigned long flags; + struct musb *musb = hcd_to_musb(hcd); + struct usb_host_endpoint *hep = urb->ep; +- struct musb_qh *qh = hep->hcpriv; ++ struct musb_qh *qh; + struct usb_endpoint_descriptor *epd = &hep->desc; + int ret; + unsigned type_reg; +@@ -1853,22 +1853,21 @@ static int musb_urb_enqueue( + + spin_lock_irqsave(&musb->lock, flags); + ret = usb_hcd_link_urb_to_ep(hcd, urb); ++ qh = ret ? NULL : hep->hcpriv; ++ if (qh) ++ urb->hcpriv = qh; + spin_unlock_irqrestore(&musb->lock, flags); +- if (ret) +- return ret; + + /* DMA mapping was already done, if needed, and this urb is on +- * hep->urb_list ... so there's little to do unless hep wasn't +- * yet scheduled onto a live qh. ++ * hep->urb_list now ... so we're done, unless hep wasn't yet ++ * scheduled onto a live qh. + * + * REVISIT best to keep hep->hcpriv valid until the endpoint gets + * disabled, testing for empty qh->ring and avoiding qh setup costs + * except for the first urb queued after a config change. + */ +- if (qh) { +- urb->hcpriv = qh; +- return 0; +- } ++ if (qh || ret) ++ return ret; + + /* Allocate and initialize qh, minimizing the work done each time + * hw_ep gets reprogrammed, or with irqs blocked. Then schedule it. diff --git a/usb.current/usb-option-add-ids-for-d-link-dwm-652-3.5g-modem.patch b/usb.current/usb-option-add-ids-for-d-link-dwm-652-3.5g-modem.patch new file mode 100644 index 00000000000000..92b5d52608d72e --- /dev/null +++ b/usb.current/usb-option-add-ids-for-d-link-dwm-652-3.5g-modem.patch @@ -0,0 +1,66 @@ +From pterjan@mandriva.com Tue Apr 7 11:11:00 2009 +From: Pascal Terjan <pterjan@mandriva.com> +Date: Tue, 07 Apr 2009 14:40:42 +0200 +Subject: USB: option: Add ids for D-Link DWM-652 3.5G modem +Message-ID: <1239108042.31094.9.camel@plop> + + +This patch allows D-Link DWM-652 3.5G modem to work. +It is an express card but was only tested with the provided usb adapter as I +don't have machines with express card connector. + +/dev/ttyUSB{0,1,2} get created, and using comgt on ttyUSB1 works fine : + +[root@plop tmp]# comgt -d /dev/ttyUSB1 -e + +Enter PIN number: XXXX +Waiting for Registration..(120 sec max). +Registered on Home network: "Orange France",2 +Signal Quality: 15,99 + +From: Pascal Terjan <pterjan@mandriva.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/option.c | 5 +++++ + drivers/usb/storage/unusual_devs.h | 8 ++++++++ + 2 files changed, 13 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -300,6 +300,10 @@ static int option_resume(struct usb_ser + #define BENQ_VENDOR_ID 0x04a5 + #define BENQ_PRODUCT_H10 0x4068 + ++#define DLINK_VENDOR_ID 0x1186 ++#define DLINK_PRODUCT_DWM_652 0x3e04 ++ ++ + static struct usb_device_id option_ids[] = { + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, +@@ -516,6 +520,7 @@ static struct usb_device_id option_ids[] + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, ++ { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, + { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ + { } /* Terminating entry */ + }; +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -1376,6 +1376,14 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x + US_SC_DEVICE, US_PR_DEVICE, NULL, + 0), + ++/* Reported by Pascal Terjan <pterjan@mandriva.com> ++ * Ignore driver CD mode and force into modem mode by default. ++ */ ++UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000, ++ "D-Link", ++ "USB Mass Storage", ++ US_SC_DEVICE, US_PR_DEVICE, option_ms_init, 0), ++ + /* Reported by Kevin Lloyd <linux@sierrawireless.com> + * Entry is needed for the initializer function override, + * which instructs the device to load as a modem diff --git a/usb.current/usb-qcserial-add-extra-device-ids.patch b/usb.current/usb-qcserial-add-extra-device-ids.patch new file mode 100644 index 00000000000000..3467b6352d9922 --- /dev/null +++ b/usb.current/usb-qcserial-add-extra-device-ids.patch @@ -0,0 +1,52 @@ +From mjg59@srcf.ucam.org Tue Apr 7 11:11:49 2009 +From: Matthew Garrett <mjg59@srcf.ucam.org> +Date: Sat, 4 Apr 2009 17:24:24 +0100 +Subject: USB: qcserial: Add extra device IDs +To: Greg KH <gregkh@suse.de> +Cc: <shurik@gwu.edu> +Message-ID: <20090404162424.GA5799@srcf.ucam.org> +Content-Disposition: inline + + +Add a set of device IDs from the Windows drivers. These aren't complete +(there's a couple of cases where a QDL device is identified without the +associated modem being identified), but it's better than the current +situation. + +Signed-off-by: Matthew Garrett <mjg@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/qcserial.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/drivers/usb/serial/qcserial.c ++++ b/drivers/usb/serial/qcserial.c +@@ -26,6 +26,27 @@ static struct usb_device_id id_table[] = + {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ + {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ + {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ ++ {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ ++ {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ ++ {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ ++ {USB_DEVICE(0x413c, 0x8171)}, /* Dell Gobi QDL device */ ++ {USB_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ ++ {USB_DEVICE(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ ++ {USB_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ ++ {USB_DEVICE(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ ++ {USB_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ ++ {USB_DEVICE(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ ++ {USB_DEVICE(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ ++ {USB_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ ++ {USB_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ ++ {USB_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ ++ {USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ ++ {USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ ++ {USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ ++ {USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ ++ {USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ ++ {USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ ++ {USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, id_table); diff --git a/usb.current/usb-usb-storage-augment-unusual_devs-entry-for-simple-tech-datafab.patch b/usb.current/usb-usb-storage-augment-unusual_devs-entry-for-simple-tech-datafab.patch new file mode 100644 index 00000000000000..f15309835729bc --- /dev/null +++ b/usb.current/usb-usb-storage-augment-unusual_devs-entry-for-simple-tech-datafab.patch @@ -0,0 +1,41 @@ +From stern@rowland.harvard.edu Tue Apr 7 11:29:13 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 24 Mar 2009 10:39:13 -0400 (EDT) +Subject: USB: usb-storage: augment unusual_devs entry for Simple Tech/Datafab +To: Greg KH <greg@kroah.com> +Cc: binbin <binbinsh@gmail.com>, Phil Dibowitz <phil@ipom.com> +Message-ID: <Pine.LNX.4.44L0.0903241037000.3162-100000@iolanthe.rowland.org> + + +This patch (as1227) adds the MAX_SECTORS_64 flag to the unusual_devs +entry for the Simple Tech/Datafab controller. This fixes Bugzilla +#12882. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Reported-and-tested-by: binbin <binbinsh@gmail.com> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/storage/unusual_devs.h | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -975,12 +975,14 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0x + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY ), + +-/* Reported by Rauch Wolke <rauchwolke@gmx.net> */ ++/* Reported by Rauch Wolke <rauchwolke@gmx.net> ++ * and augmented by binbin <binbinsh@gmail.com> (Bugzilla #12882) ++ */ + UNUSUAL_DEV( 0x07c4, 0xa4a5, 0x0000, 0xffff, + "Simple Tech/Datafab", + "CF+SM Reader", + US_SC_DEVICE, US_PR_DEVICE, NULL, +- US_FL_IGNORE_RESIDUE ), ++ US_FL_IGNORE_RESIDUE | US_FL_MAX_SECTORS_64 ), + + /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant + * to the USB storage specification in two ways: @@ -1 +1 @@ -2.6.29-git13 +2.6.29-git15 |