From: Greg Kroah-Hartman Date: Thu, 29 Jul 2010 00:13:30 +0000 (-0700) Subject: .34 patches X-Git-Tag: v2.6.27.49~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c2f3b60cddb3c90b864795a0e90d1c3267f1731e;p=thirdparty%2Fkernel%2Fstable-queue.git .34 patches --- diff --git a/queue-2.6.34/acpi-pm-do-not-enable-gpes-for-system-wakeup-in-advance.patch b/queue-2.6.34/acpi-pm-do-not-enable-gpes-for-system-wakeup-in-advance.patch new file mode 100644 index 00000000000..1dee0179297 --- /dev/null +++ b/queue-2.6.34/acpi-pm-do-not-enable-gpes-for-system-wakeup-in-advance.patch @@ -0,0 +1,108 @@ +From cb1cb1780f2025a7d612de09131bf6530f80fb1a Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Thu, 17 Jun 2010 17:40:57 +0200 +Subject: ACPI / PM: Do not enable GPEs for system wakeup in advance + +From: Rafael J. Wysocki + +commit cb1cb1780f2025a7d612de09131bf6530f80fb1a upstream. + +After commit 9630bdd9b15d2f489c646d8bc04b60e53eb5ec78 +(ACPI: Use GPE reference counting to support shared GPEs) the wakeup +enable mask bits of GPEs are set as soon as the GPEs are enabled to +wake up the system. Unfortunately, this leads to a regression +reported by Michal Hocko, where a system is woken up from ACPI S5 by +a device that is not supposed to do that, because the wakeup enable +mask bit of this device's GPE is always set when +acpi_enter_sleep_state() calls acpi_hw_enable_all_wakeup_gpes(), +although it should only be set if the device is supposed to wake up +the system from the target state. + +To work around this issue, rework the ACPI power management code so +that GPEs are not enabled to wake up the system upfront, but only +during a system state transition when the target state of the system +is known. [Of course, this means that the reference counting of +"wakeup" GPEs doesn't really make sense and it is sufficient to +set/unset the wakeup mask bits for them during system sleep +transitions. This will allow us to simplify the GPE handling code +quite a bit, but that change is too intrusive for 2.6.35.] + +Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15951 + +Signed-off-by: Rafael J. Wysocki +Reported-and-tested-by: Michal Hocko +Signed-off-by: Len Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/button.c | 4 ++-- + drivers/acpi/wakeup.c | 20 +++++++------------- + 2 files changed, 9 insertions(+), 15 deletions(-) + +--- a/drivers/acpi/button.c ++++ b/drivers/acpi/button.c +@@ -425,7 +425,7 @@ static int acpi_button_add(struct acpi_d + /* Button's GPE is run-wake GPE */ + acpi_enable_gpe(device->wakeup.gpe_device, + device->wakeup.gpe_number, +- ACPI_GPE_TYPE_WAKE_RUN); ++ ACPI_GPE_TYPE_RUNTIME); + device->wakeup.run_wake_count++; + device->wakeup.state.enabled = 1; + } +@@ -449,7 +449,7 @@ static int acpi_button_remove(struct acp + if (device->wakeup.flags.valid) { + acpi_disable_gpe(device->wakeup.gpe_device, + device->wakeup.gpe_number, +- ACPI_GPE_TYPE_WAKE_RUN); ++ ACPI_GPE_TYPE_RUNTIME); + device->wakeup.run_wake_count--; + device->wakeup.state.enabled = 0; + } +--- a/drivers/acpi/wakeup.c ++++ b/drivers/acpi/wakeup.c +@@ -64,16 +64,13 @@ void acpi_enable_wakeup_device(u8 sleep_ + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); + +- if (!dev->wakeup.flags.valid) +- continue; +- +- if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count) ++ if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled + || sleep_state > (u32) dev->wakeup.sleep_state) + continue; + + /* The wake-up power should have been enabled already. */ +- acpi_set_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, +- ACPI_GPE_ENABLE); ++ acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ++ ACPI_GPE_TYPE_WAKE); + } + } + +@@ -96,6 +93,8 @@ void acpi_disable_wakeup_device(u8 sleep + || (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + ++ acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ++ ACPI_GPE_TYPE_WAKE); + acpi_disable_wakeup_device_power(dev); + } + } +@@ -109,13 +108,8 @@ int __init acpi_wakeup_device_init(void) + struct acpi_device *dev = container_of(node, + struct acpi_device, + wakeup_list); +- /* In case user doesn't load button driver */ +- if (!dev->wakeup.flags.always_enabled || +- dev->wakeup.state.enabled) +- continue; +- acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, +- ACPI_GPE_TYPE_WAKE); +- dev->wakeup.state.enabled = 1; ++ if (dev->wakeup.flags.always_enabled) ++ dev->wakeup.state.enabled = 1; + } + mutex_unlock(&acpi_device_lock); + return 0; diff --git a/queue-2.6.34/acpi-skip-checking-bm_sts-if-the-bios-doesn-t-ask-for-it.patch b/queue-2.6.34/acpi-skip-checking-bm_sts-if-the-bios-doesn-t-ask-for-it.patch new file mode 100644 index 00000000000..9396caebd2f --- /dev/null +++ b/queue-2.6.34/acpi-skip-checking-bm_sts-if-the-bios-doesn-t-ask-for-it.patch @@ -0,0 +1,82 @@ +From 718be4aaf3613cf7c2d097f925abc3d3553c0605 Mon Sep 17 00:00:00 2001 +From: Len Brown +Date: Thu, 22 Jul 2010 16:54:27 -0400 +Subject: ACPI: skip checking BM_STS if the BIOS doesn't ask for it + +From: Len Brown + +commit 718be4aaf3613cf7c2d097f925abc3d3553c0605 upstream. + +It turns out that there is a bit in the _CST for Intel FFH C3 +that tells the OS if we should be checking BM_STS or not. + +Linux has been unconditionally checking BM_STS. +If the chip-set is configured to enable BM_STS, +it can retard or completely prevent entry into +deep C-states -- as illustrated by turbostat: + +http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/ + +ref: Intel Processor Vendor-Specific ACPI Interface Specification +table 4 "_CST FFH GAS Field Encoding" +Bit 1: Set to 1 if OSPM should use Bus Master avoidance for this C-state + +https://bugzilla.kernel.org/show_bug.cgi?id=15886 + +Signed-off-by: Len Brown +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/acpi/cstate.c | 9 +++++++++ + drivers/acpi/processor_idle.c | 2 +- + include/acpi/processor.h | 3 ++- + 3 files changed, 12 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/acpi/cstate.c ++++ b/arch/x86/kernel/acpi/cstate.c +@@ -145,6 +145,15 @@ int acpi_processor_ffh_cstate_probe(unsi + percpu_entry->states[cx->index].eax = cx->address; + percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK; + } ++ ++ /* ++ * For _CST FFH on Intel, if GAS.access_size bit 1 is cleared, ++ * then we should skip checking BM_STS for this C-state. ++ * ref: "Intel Processor Vendor-Specific ACPI Interface Specification" ++ */ ++ if ((c->x86_vendor == X86_VENDOR_INTEL) && !(reg->access_size & 0x2)) ++ cx->bm_sts_skip = 1; ++ + return retval; + } + EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe); +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -955,7 +955,7 @@ static int acpi_idle_enter_bm(struct cpu + if (acpi_idle_suspend) + return(acpi_idle_enter_c1(dev, state)); + +- if (acpi_idle_bm_check()) { ++ if (!cx->bm_sts_skip && acpi_idle_bm_check()) { + if (dev->safe_state) { + dev->last_state = dev->safe_state; + return dev->safe_state->enter(dev, dev->safe_state); +--- a/include/acpi/processor.h ++++ b/include/acpi/processor.h +@@ -48,7 +48,7 @@ struct acpi_power_register { + u8 space_id; + u8 bit_width; + u8 bit_offset; +- u8 reserved; ++ u8 access_size; + u64 address; + } __attribute__ ((packed)); + +@@ -74,6 +74,7 @@ struct acpi_processor_cx { + u32 power; + u32 usage; + u64 time; ++ u8 bm_sts_skip; + struct acpi_processor_cx_policy promotion; + struct acpi_processor_cx_policy demotion; + char desc[ACPI_CX_DESC_LEN]; diff --git a/queue-2.6.34/acpi-unconditionally-set-sci_en-on-resume.patch b/queue-2.6.34/acpi-unconditionally-set-sci_en-on-resume.patch new file mode 100644 index 00000000000..73f8c089f4f --- /dev/null +++ b/queue-2.6.34/acpi-unconditionally-set-sci_en-on-resume.patch @@ -0,0 +1,252 @@ +From b6dacf63e9fb2e7a1369843d6cef332f76fca6a3 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Tue, 11 May 2010 13:49:25 -0400 +Subject: ACPI: Unconditionally set SCI_EN on resume + +From: Matthew Garrett + +commit b6dacf63e9fb2e7a1369843d6cef332f76fca6a3 upstream. + +The ACPI spec tells us that the firmware will reenable SCI_EN on resume. +Reality disagrees in some cases. The ACPI spec tells us that the only way +to set SCI_EN is via an SMM call. +https://bugzilla.kernel.org/show_bug.cgi?id=13745 shows us that doing so +may break machines. Tracing the ACPI calls made by Windows shows that it +unconditionally sets SCI_EN on resume with a direct register write, and +therefore the overwhelming probability is that everything is fine with +this behaviour. + +Signed-off-by: Matthew Garrett +Tested-by: Rafael J. Wysocki +Signed-off-by: Len Brown +Cc: Kamal Mostafa +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/acpi/sleep.c | 2 + drivers/acpi/sleep.c | 157 ------------------------------------------- + include/linux/acpi.h | 1 + 3 files changed, 2 insertions(+), 158 deletions(-) + +--- a/arch/x86/kernel/acpi/sleep.c ++++ b/arch/x86/kernel/acpi/sleep.c +@@ -162,8 +162,6 @@ static int __init acpi_sleep_setup(char + #endif + if (strncmp(str, "old_ordering", 12) == 0) + acpi_old_suspend_ordering(); +- if (strncmp(str, "sci_force_enable", 16) == 0) +- acpi_set_sci_en_on_resume(); + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); +--- a/drivers/acpi/sleep.c ++++ b/drivers/acpi/sleep.c +@@ -80,22 +80,6 @@ static int acpi_sleep_prepare(u32 acpi_s + + #ifdef CONFIG_ACPI_SLEEP + static u32 acpi_target_sleep_state = ACPI_STATE_S0; +-/* +- * According to the ACPI specification the BIOS should make sure that ACPI is +- * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still, +- * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI +- * on such systems during resume. Unfortunately that doesn't help in +- * particularly pathological cases in which SCI_EN has to be set directly on +- * resume, although the specification states very clearly that this flag is +- * owned by the hardware. The set_sci_en_on_resume variable will be set in such +- * cases. +- */ +-static bool set_sci_en_on_resume; +- +-void __init acpi_set_sci_en_on_resume(void) +-{ +- set_sci_en_on_resume = true; +-} + + /* + * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the +@@ -253,11 +237,8 @@ static int acpi_suspend_enter(suspend_st + break; + } + +- /* If ACPI is not enabled by the BIOS, we need to enable it here. */ +- if (set_sci_en_on_resume) +- acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); +- else +- acpi_enable(); ++ /* This violates the spec but is required for bug compatibility. */ ++ acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); + + /* Reprogram control registers and execute _BFS */ + acpi_leave_sleep_state_prep(acpi_state); +@@ -346,12 +327,6 @@ static int __init init_old_suspend_order + return 0; + } + +-static int __init init_set_sci_en_on_resume(const struct dmi_system_id *d) +-{ +- set_sci_en_on_resume = true; +- return 0; +-} +- + static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + { + .callback = init_old_suspend_ordering, +@@ -370,22 +345,6 @@ static struct dmi_system_id __initdata a + }, + }, + { +- .callback = init_set_sci_en_on_resume, +- .ident = "Apple MacBook 1,1", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Apple MacMini 1,1", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"), +- }, +- }, +- { + .callback = init_old_suspend_ordering, + .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", + .matches = { +@@ -394,94 +353,6 @@ static struct dmi_system_id __initdata a + }, + }, + { +- .callback = init_set_sci_en_on_resume, +- .ident = "Toshiba Satellite L300", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Hewlett-Packard HP G7000 Notebook PC", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP G7000 Notebook PC"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Hewlett-Packard HP Pavilion dv3 Notebook PC", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv3 Notebook PC"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Hewlett-Packard Pavilion dv4", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Hewlett-Packard Pavilion dv7", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Hewlett-Packard Compaq Presario C700 Notebook PC", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario C700 Notebook PC"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Hewlett-Packard Compaq Presario CQ40 Notebook PC", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario CQ40 Notebook PC"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Lenovo ThinkPad T410", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T410"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Lenovo ThinkPad T510", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T510"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Lenovo ThinkPad W510", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W510"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Lenovo ThinkPad X201[s]", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201"), +- }, +- }, +- { + .callback = init_old_suspend_ordering, + .ident = "Panasonic CF51-2L", + .matches = { +@@ -490,30 +361,6 @@ static struct dmi_system_id __initdata a + DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), + }, + }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Dell Studio 1558", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1558"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Dell Studio 1557", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"), +- }, +- }, +- { +- .callback = init_set_sci_en_on_resume, +- .ident = "Dell Studio 1555", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1555"), +- }, +- }, + {}, + }; + #endif /* CONFIG_SUSPEND */ +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -251,7 +251,6 @@ int acpi_check_mem_region(resource_size_ + void __init acpi_no_s4_hw_signature(void); + void __init acpi_old_suspend_ordering(void); + void __init acpi_s4_no_nvs(void); +-void __init acpi_set_sci_en_on_resume(void); + #endif /* CONFIG_PM_SLEEP */ + + struct acpi_osc_context { diff --git a/queue-2.6.34/futex-futex_find_get_task-remove-credentails-check.patch b/queue-2.6.34/futex-futex_find_get_task-remove-credentails-check.patch new file mode 100644 index 00000000000..89d8f552c30 --- /dev/null +++ b/queue-2.6.34/futex-futex_find_get_task-remove-credentails-check.patch @@ -0,0 +1,82 @@ +From 7a0ea09ad5352efce8fe79ed853150449903b9f5 Mon Sep 17 00:00:00 2001 +From: Michal Hocko +Date: Wed, 30 Jun 2010 09:51:19 +0200 +Subject: futex: futex_find_get_task remove credentails check + +From: Michal Hocko + +commit 7a0ea09ad5352efce8fe79ed853150449903b9f5 upstream. + +futex_find_get_task is currently used (through lookup_pi_state) from two +contexts, futex_requeue and futex_lock_pi_atomic. None of the paths +looks it needs the credentials check, though. Different (e)uids +shouldn't matter at all because the only thing that is important for +shared futex is the accessibility of the shared memory. + +The credentail check results in glibc assert failure or process hang (if +glibc is compiled without assert support) for shared robust pthread +mutex with priority inheritance if a process tries to lock already held +lock owned by a process with a different euid: + +pthread_mutex_lock.c:312: __pthread_mutex_lock_full: Assertion `(-(e)) != 3 || !robust' failed. + +The problem is that futex_lock_pi_atomic which is called when we try to +lock already held lock checks the current holder (tid is stored in the +futex value) to get the PI state. It uses lookup_pi_state which in turn +gets task struct from futex_find_get_task. ESRCH is returned either +when the task is not found or if credentials check fails. + +futex_lock_pi_atomic simply returns if it gets ESRCH. glibc code, +however, doesn't expect that robust lock returns with ESRCH because it +should get either success or owner died. + +Signed-off-by: Michal Hocko +Acked-by: Darren Hart +Cc: Ingo Molnar +Cc: Thomas Gleixner +Cc: Nick Piggin +Cc: Alexey Kuznetsov +Cc: Peter Zijlstra +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/futex.c | 17 ++++------------- + 1 file changed, 4 insertions(+), 13 deletions(-) + +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -429,20 +429,11 @@ static void free_pi_state(struct futex_p + static struct task_struct * futex_find_get_task(pid_t pid) + { + struct task_struct *p; +- const struct cred *cred = current_cred(), *pcred; + + rcu_read_lock(); + p = find_task_by_vpid(pid); +- if (!p) { +- p = ERR_PTR(-ESRCH); +- } else { +- pcred = __task_cred(p); +- if (cred->euid != pcred->euid && +- cred->euid != pcred->uid) +- p = ERR_PTR(-ESRCH); +- else +- get_task_struct(p); +- } ++ if (p) ++ get_task_struct(p); + + rcu_read_unlock(); + +@@ -564,8 +555,8 @@ lookup_pi_state(u32 uval, struct futex_h + if (!pid) + return -ESRCH; + p = futex_find_get_task(pid); +- if (IS_ERR(p)) +- return PTR_ERR(p); ++ if (!p) ++ return -ESRCH; + + /* + * We need to look at the task state flags to figure out, diff --git a/queue-2.6.34/isdn-capi-make-reset_ctr-op-truly-optional.patch b/queue-2.6.34/isdn-capi-make-reset_ctr-op-truly-optional.patch new file mode 100644 index 00000000000..a376347f18f --- /dev/null +++ b/queue-2.6.34/isdn-capi-make-reset_ctr-op-truly-optional.patch @@ -0,0 +1,37 @@ +From 85a83560afa69862639fb2d6f670b4440a003335 Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Sun, 23 May 2010 01:02:08 +0000 +Subject: isdn/capi: make reset_ctr op truly optional + +From: Tilman Schmidt + +commit 85a83560afa69862639fb2d6f670b4440a003335 upstream. + +The CAPI controller operation reset_ctr is marked as optional, and +not all drivers do implement it. Add a check to the kernel CAPI +whether it exists before trying to call it. + +Signed-off-by: Tilman Schmidt +Acked-by: Karsten Keil +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/capi/kcapi.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/isdn/capi/kcapi.c ++++ b/drivers/isdn/capi/kcapi.c +@@ -1147,6 +1147,12 @@ load_unlock_out: + if (ctr->state == CAPI_CTR_DETECTED) + goto reset_unlock_out; + ++ if (ctr->reset_ctr == NULL) { ++ printk(KERN_DEBUG "kcapi: reset: no reset function\n"); ++ retval = -ESRCH; ++ goto reset_unlock_out; ++ } ++ + ctr->reset_ctr(ctr); + + retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED); diff --git a/queue-2.6.34/isdn-gigaset-correct-capi-connection-state-storage.patch b/queue-2.6.34/isdn-gigaset-correct-capi-connection-state-storage.patch new file mode 100644 index 00000000000..adf8e17aec8 --- /dev/null +++ b/queue-2.6.34/isdn-gigaset-correct-capi-connection-state-storage.patch @@ -0,0 +1,596 @@ +From 1b4843c5e8cbab86830da8a53b8288882060c059 Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Mon, 21 Jun 2010 13:55:20 +0000 +Subject: isdn/gigaset: correct CAPI connection state storage + +From: Tilman Schmidt + +commit 1b4843c5e8cbab86830da8a53b8288882060c059 upstream. + +CAPI applications can handle several connections in parallel, +so one connection state per application isn't sufficient. +Store the connection state in the channel structure instead. + +Impact: bugfix +Signed-off-by: Tilman Schmidt +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/gigaset/capi.c | 225 +++++++++++++++++++++++++++++++---------- + drivers/isdn/gigaset/common.c | 4 + drivers/isdn/gigaset/gigaset.h | 4 + 3 files changed, 180 insertions(+), 53 deletions(-) + +--- a/drivers/isdn/gigaset/capi.c ++++ b/drivers/isdn/gigaset/capi.c +@@ -70,7 +70,7 @@ + #define MAX_NUMBER_DIGITS 20 + #define MAX_FMT_IE_LEN 20 + +-/* values for gigaset_capi_appl.connected */ ++/* values for bcs->apconnstate */ + #define APCONN_NONE 0 /* inactive/listening */ + #define APCONN_SETUP 1 /* connecting */ + #define APCONN_ACTIVE 2 /* B channel up */ +@@ -84,7 +84,6 @@ struct gigaset_capi_appl { + u16 nextMessageNumber; + u32 listenInfoMask; + u32 listenCIPmask; +- int connected; + }; + + /* CAPI specific controller data structure */ +@@ -395,7 +394,7 @@ void gigaset_skb_sent(struct bc_state *b + } + + /* don't send further B3 messages if disconnected */ +- if (ap->connected < APCONN_ACTIVE) { ++ if (bcs->apconnstate < APCONN_ACTIVE) { + gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); + return; + } +@@ -439,7 +438,7 @@ void gigaset_skb_rcvd(struct bc_state *b + } + + /* don't send further B3 messages if disconnected */ +- if (ap->connected < APCONN_ACTIVE) { ++ if (bcs->apconnstate < APCONN_ACTIVE) { + gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); + dev_kfree_skb_any(skb); + return; +@@ -511,6 +510,7 @@ int gigaset_isdn_icall(struct at_state_t + u32 actCIPmask; + struct sk_buff *skb; + unsigned int msgsize; ++ unsigned long flags; + int i; + + /* +@@ -635,7 +635,14 @@ int gigaset_isdn_icall(struct at_state_t + format_ie(iif->hcmsg.CalledPartyNumber)); + + /* scan application list for matching listeners */ +- bcs->ap = NULL; ++ spin_lock_irqsave(&bcs->aplock, flags); ++ if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { ++ dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", ++ __func__, bcs->ap, bcs->apconnstate); ++ bcs->ap = NULL; ++ bcs->apconnstate = APCONN_NONE; ++ } ++ spin_unlock_irqrestore(&bcs->aplock, flags); + actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); + list_for_each_entry(ap, &iif->appls, ctrlist) + if (actCIPmask & ap->listenCIPmask) { +@@ -653,10 +660,12 @@ int gigaset_isdn_icall(struct at_state_t + dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); + + /* add to listeners on this B channel, update state */ ++ spin_lock_irqsave(&bcs->aplock, flags); + ap->bcnext = bcs->ap; + bcs->ap = ap; + bcs->chstate |= CHS_NOTIFY_LL; +- ap->connected = APCONN_SETUP; ++ bcs->apconnstate = APCONN_SETUP; ++ spin_unlock_irqrestore(&bcs->aplock, flags); + + /* emit message */ + capi_ctr_handle_message(&iif->ctr, ap->id, skb); +@@ -681,7 +690,7 @@ static void send_disconnect_ind(struct b + struct gigaset_capi_ctr *iif = cs->iif; + struct sk_buff *skb; + +- if (ap->connected == APCONN_NONE) ++ if (bcs->apconnstate == APCONN_NONE) + return; + + capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, +@@ -695,7 +704,6 @@ static void send_disconnect_ind(struct b + } + capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); + dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); +- ap->connected = APCONN_NONE; + capi_ctr_handle_message(&iif->ctr, ap->id, skb); + } + +@@ -712,9 +720,9 @@ static void send_disconnect_b3_ind(struc + struct sk_buff *skb; + + /* nothing to do if no logical connection active */ +- if (ap->connected < APCONN_ACTIVE) ++ if (bcs->apconnstate < APCONN_ACTIVE) + return; +- ap->connected = APCONN_SETUP; ++ bcs->apconnstate = APCONN_SETUP; + + capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, + ap->nextMessageNumber++, +@@ -741,14 +749,25 @@ void gigaset_isdn_connD(struct bc_state + { + struct cardstate *cs = bcs->cs; + struct gigaset_capi_ctr *iif = cs->iif; +- struct gigaset_capi_appl *ap = bcs->ap; ++ struct gigaset_capi_appl *ap; + struct sk_buff *skb; + unsigned int msgsize; ++ unsigned long flags; + ++ spin_lock_irqsave(&bcs->aplock, flags); ++ ap = bcs->ap; + if (!ap) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); + dev_err(cs->dev, "%s: no application\n", __func__); + return; + } ++ if (bcs->apconnstate == APCONN_NONE) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ dev_warn(cs->dev, "%s: application %u not connected\n", ++ __func__, ap->id); ++ return; ++ } ++ spin_unlock_irqrestore(&bcs->aplock, flags); + while (ap->bcnext) { + /* this should never happen */ + dev_warn(cs->dev, "%s: dropping extra application %u\n", +@@ -757,11 +776,6 @@ void gigaset_isdn_connD(struct bc_state + CapiCallGivenToOtherApplication); + ap->bcnext = ap->bcnext->bcnext; + } +- if (ap->connected == APCONN_NONE) { +- dev_warn(cs->dev, "%s: application %u not connected\n", +- __func__, ap->id); +- return; +- } + + /* prepare CONNECT_ACTIVE_IND message + * Note: LLC not supported by device +@@ -799,17 +813,24 @@ void gigaset_isdn_connD(struct bc_state + void gigaset_isdn_hupD(struct bc_state *bcs) + { + struct gigaset_capi_appl *ap; ++ unsigned long flags; + + /* + * ToDo: pass on reason code reported by device + * (requires ev-layer state machine extension to collect + * ZCAU device reply) + */ +- for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { ++ spin_lock_irqsave(&bcs->aplock, flags); ++ while (bcs->ap != NULL) { ++ ap = bcs->ap; ++ bcs->ap = ap->bcnext; ++ spin_unlock_irqrestore(&bcs->aplock, flags); + send_disconnect_b3_ind(bcs, ap); + send_disconnect_ind(bcs, ap, 0); ++ spin_lock_irqsave(&bcs->aplock, flags); + } +- bcs->ap = NULL; ++ bcs->apconnstate = APCONN_NONE; ++ spin_unlock_irqrestore(&bcs->aplock, flags); + } + + /** +@@ -823,24 +844,21 @@ void gigaset_isdn_connB(struct bc_state + { + struct cardstate *cs = bcs->cs; + struct gigaset_capi_ctr *iif = cs->iif; +- struct gigaset_capi_appl *ap = bcs->ap; ++ struct gigaset_capi_appl *ap; + struct sk_buff *skb; ++ unsigned long flags; + unsigned int msgsize; + u8 command; + ++ spin_lock_irqsave(&bcs->aplock, flags); ++ ap = bcs->ap; + if (!ap) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); + dev_err(cs->dev, "%s: no application\n", __func__); + return; + } +- while (ap->bcnext) { +- /* this should never happen */ +- dev_warn(cs->dev, "%s: dropping extra application %u\n", +- __func__, ap->bcnext->id); +- send_disconnect_ind(bcs, ap->bcnext, +- CapiCallGivenToOtherApplication); +- ap->bcnext = ap->bcnext->bcnext; +- } +- if (!ap->connected) { ++ if (!bcs->apconnstate) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); + dev_warn(cs->dev, "%s: application %u not connected\n", + __func__, ap->id); + return; +@@ -852,13 +870,26 @@ void gigaset_isdn_connB(struct bc_state + * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP + * Parameters in both cases always: NCCI = 1, NCPI empty + */ +- if (ap->connected >= APCONN_ACTIVE) { ++ if (bcs->apconnstate >= APCONN_ACTIVE) { + command = CAPI_CONNECT_B3_ACTIVE; + msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; + } else { + command = CAPI_CONNECT_B3; + msgsize = CAPI_CONNECT_B3_IND_BASELEN; + } ++ bcs->apconnstate = APCONN_ACTIVE; ++ ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ ++ while (ap->bcnext) { ++ /* this should never happen */ ++ dev_warn(cs->dev, "%s: dropping extra application %u\n", ++ __func__, ap->bcnext->id); ++ send_disconnect_ind(bcs, ap->bcnext, ++ CapiCallGivenToOtherApplication); ++ ap->bcnext = ap->bcnext->bcnext; ++ } ++ + capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, + ap->nextMessageNumber++, + iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); +@@ -869,7 +900,6 @@ void gigaset_isdn_connB(struct bc_state + } + capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); + dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); +- ap->connected = APCONN_ACTIVE; + capi_ctr_handle_message(&iif->ctr, ap->id, skb); + } + +@@ -975,6 +1005,61 @@ static void gigaset_register_appl(struct + ap->rp = *rp; + + list_add(&ap->ctrlist, &iif->appls); ++ dev_info(cs->dev, "application %u registered\n", ap->id); ++} ++ ++/* ++ * remove CAPI application from channel ++ * helper function to keep indentation levels down and stay in 80 columns ++ */ ++ ++static inline void remove_appl_from_channel(struct bc_state *bcs, ++ struct gigaset_capi_appl *ap) ++{ ++ struct cardstate *cs = bcs->cs; ++ struct gigaset_capi_appl *bcap; ++ unsigned long flags; ++ int prevconnstate; ++ ++ spin_lock_irqsave(&bcs->aplock, flags); ++ bcap = bcs->ap; ++ if (bcap == NULL) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ return; ++ } ++ ++ /* check first application on channel */ ++ if (bcap == ap) { ++ bcs->ap = ap->bcnext; ++ if (bcs->ap != NULL) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ return; ++ } ++ ++ /* none left, clear channel state */ ++ prevconnstate = bcs->apconnstate; ++ bcs->apconnstate = APCONN_NONE; ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ ++ if (prevconnstate == APCONN_ACTIVE) { ++ dev_notice(cs->dev, "%s: hanging up channel %u\n", ++ __func__, bcs->channel); ++ gigaset_add_event(cs, &bcs->at_state, ++ EV_HUP, NULL, 0, NULL); ++ gigaset_schedule_event(cs); ++ } ++ return; ++ } ++ ++ /* check remaining list */ ++ do { ++ if (bcap->bcnext == ap) { ++ bcap->bcnext = bcap->bcnext->bcnext; ++ return; ++ } ++ bcap = bcap->bcnext; ++ } while (bcap != NULL); ++ spin_unlock_irqrestore(&bcs->aplock, flags); + } + + /* +@@ -986,19 +1071,19 @@ static void gigaset_release_appl(struct + = container_of(ctr, struct gigaset_capi_ctr, ctr); + struct cardstate *cs = iif->ctr.driverdata; + struct gigaset_capi_appl *ap, *tmp; ++ unsigned ch; + + list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) + if (ap->id == appl) { +- if (ap->connected != APCONN_NONE) { +- dev_err(cs->dev, +- "%s: application %u still connected\n", +- __func__, ap->id); +- /* ToDo: clear active connection */ +- } ++ /* remove from any channels */ ++ for (ch = 0; ch < cs->channels; ch++) ++ remove_appl_from_channel(&cs->bcs[ch], ap); ++ ++ /* remove from registration list */ + list_del(&ap->ctrlist); + kfree(ap); ++ dev_info(cs->dev, "application %u released\n", appl); + } +- + } + + /* +@@ -1177,6 +1262,7 @@ static void do_connect_req(struct gigase + char **commands; + char *s; + u8 *pp; ++ unsigned long flags; + int i, l, lbc, lhlc; + u16 info; + +@@ -1192,8 +1278,15 @@ static void do_connect_req(struct gigase + send_conf(iif, ap, skb, CapiNoPlciAvailable); + return; + } ++ spin_lock_irqsave(&bcs->aplock, flags); ++ if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) ++ dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", ++ __func__, bcs->ap, bcs->apconnstate); + ap->bcnext = NULL; + bcs->ap = ap; ++ bcs->apconnstate = APCONN_SETUP; ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ + bcs->rx_bufsize = ap->rp.datablklen; + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); +@@ -1430,7 +1523,6 @@ static void do_connect_req(struct gigase + goto error; + } + gigaset_schedule_event(cs); +- ap->connected = APCONN_SETUP; + send_conf(iif, ap, skb, CapiSuccess); + return; + +@@ -1458,6 +1550,7 @@ static void do_connect_resp(struct gigas + _cmsg *cmsg = &iif->acmsg; + struct bc_state *bcs; + struct gigaset_capi_appl *oap; ++ unsigned long flags; + int channel; + + /* decode message */ +@@ -1477,12 +1570,21 @@ static void do_connect_resp(struct gigas + switch (cmsg->Reject) { + case 0: /* Accept */ + /* drop all competing applications, keep only this one */ +- for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) +- if (oap != ap) ++ spin_lock_irqsave(&bcs->aplock, flags); ++ while (bcs->ap != NULL) { ++ oap = bcs->ap; ++ bcs->ap = oap->bcnext; ++ if (oap != ap) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); + send_disconnect_ind(bcs, oap, + CapiCallGivenToOtherApplication); ++ spin_lock_irqsave(&bcs->aplock, flags); ++ } ++ } + ap->bcnext = NULL; + bcs->ap = ap; ++ spin_unlock_irqrestore(&bcs->aplock, flags); ++ + bcs->rx_bufsize = ap->rp.datablklen; + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); +@@ -1553,31 +1655,45 @@ static void do_connect_resp(struct gigas + send_disconnect_ind(bcs, ap, 0); + + /* remove it from the list of listening apps */ ++ spin_lock_irqsave(&bcs->aplock, flags); + if (bcs->ap == ap) { + bcs->ap = ap->bcnext; +- if (bcs->ap == NULL) ++ if (bcs->ap == NULL) { + /* last one: stop ev-layer hupD notifications */ ++ bcs->apconnstate = APCONN_NONE; + bcs->chstate &= ~CHS_NOTIFY_LL; ++ } ++ spin_unlock_irqrestore(&bcs->aplock, flags); + return; + } + for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { + if (oap->bcnext == ap) { + oap->bcnext = oap->bcnext->bcnext; ++ spin_unlock_irqrestore(&bcs->aplock, flags); + return; + } + } ++ spin_unlock_irqrestore(&bcs->aplock, flags); + dev_err(cs->dev, "%s: application %u not found\n", + __func__, ap->id); + return; + + default: /* Reject */ + /* drop all competing applications, keep only this one */ +- for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) +- if (oap != ap) ++ spin_lock_irqsave(&bcs->aplock, flags); ++ while (bcs->ap != NULL) { ++ oap = bcs->ap; ++ bcs->ap = oap->bcnext; ++ if (oap != ap) { ++ spin_unlock_irqrestore(&bcs->aplock, flags); + send_disconnect_ind(bcs, oap, + CapiCallGivenToOtherApplication); ++ spin_lock_irqsave(&bcs->aplock, flags); ++ } ++ } + ap->bcnext = NULL; + bcs->ap = ap; ++ spin_unlock_irqrestore(&bcs->aplock, flags); + + /* reject call - will trigger DISCONNECT_IND for this app */ + dev_info(cs->dev, "%s: Reject=%x\n", +@@ -1600,6 +1716,7 @@ static void do_connect_b3_req(struct gig + { + struct cardstate *cs = iif->ctr.driverdata; + _cmsg *cmsg = &iif->acmsg; ++ struct bc_state *bcs; + int channel; + + /* decode message */ +@@ -1614,9 +1731,10 @@ static void do_connect_b3_req(struct gig + send_conf(iif, ap, skb, CapiIllContrPlciNcci); + return; + } ++ bcs = &cs->bcs[channel-1]; + + /* mark logical connection active */ +- ap->connected = APCONN_ACTIVE; ++ bcs->apconnstate = APCONN_ACTIVE; + + /* build NCCI: always 1 (one B3 connection only) */ + cmsg->adr.adrNCCI |= 1 << 16; +@@ -1662,7 +1780,7 @@ static void do_connect_b3_resp(struct gi + + if (cmsg->Reject) { + /* Reject: clear B3 connect received flag */ +- ap->connected = APCONN_SETUP; ++ bcs->apconnstate = APCONN_SETUP; + + /* trigger hangup, causing eventual DISCONNECT_IND */ + if (!gigaset_add_event(cs, &bcs->at_state, +@@ -1734,11 +1852,11 @@ static void do_disconnect_req(struct gig + } + + /* skip if DISCONNECT_IND already sent */ +- if (!ap->connected) ++ if (!bcs->apconnstate) + return; + + /* check for active logical connection */ +- if (ap->connected >= APCONN_ACTIVE) { ++ if (bcs->apconnstate >= APCONN_ACTIVE) { + /* + * emit DISCONNECT_B3_IND with cause 0x3301 + * use separate cmsg structure, as the content of iif->acmsg +@@ -1787,6 +1905,7 @@ static void do_disconnect_b3_req(struct + { + struct cardstate *cs = iif->ctr.driverdata; + _cmsg *cmsg = &iif->acmsg; ++ struct bc_state *bcs; + int channel; + + /* decode message */ +@@ -1802,17 +1921,17 @@ static void do_disconnect_b3_req(struct + send_conf(iif, ap, skb, CapiIllContrPlciNcci); + return; + } ++ bcs = &cs->bcs[channel-1]; + + /* reject if logical connection not active */ +- if (ap->connected < APCONN_ACTIVE) { ++ if (bcs->apconnstate < APCONN_ACTIVE) { + send_conf(iif, ap, skb, + CapiMessageNotSupportedInCurrentState); + return; + } + + /* trigger hangup, causing eventual DISCONNECT_B3_IND */ +- if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, +- EV_HUP, NULL, 0, NULL)) { ++ if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { + send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); + return; + } +@@ -1833,6 +1952,7 @@ static void do_data_b3_req(struct gigase + struct sk_buff *skb) + { + struct cardstate *cs = iif->ctr.driverdata; ++ struct bc_state *bcs; + int channel = CAPIMSG_PLCI_PART(skb->data); + u16 ncci = CAPIMSG_NCCI_PART(skb->data); + u16 msglen = CAPIMSG_LEN(skb->data); +@@ -1855,6 +1975,7 @@ static void do_data_b3_req(struct gigase + send_conf(iif, ap, skb, CapiIllContrPlciNcci); + return; + } ++ bcs = &cs->bcs[channel-1]; + if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) + dev_notice(cs->dev, "%s: unexpected length %d\n", + "DATA_B3_REQ", msglen); +@@ -1874,7 +1995,7 @@ static void do_data_b3_req(struct gigase + } + + /* reject if logical connection not active */ +- if (ap->connected < APCONN_ACTIVE) { ++ if (bcs->apconnstate < APCONN_ACTIVE) { + send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); + return; + } +@@ -1885,7 +2006,7 @@ static void do_data_b3_req(struct gigase + skb_pull(skb, msglen); + + /* pass to device-specific module */ +- if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { ++ if (cs->ops->send_skb(bcs, skb) < 0) { + send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); + return; + } +--- a/drivers/isdn/gigaset/common.c ++++ b/drivers/isdn/gigaset/common.c +@@ -649,6 +649,10 @@ static struct bc_state *gigaset_initbcs( + for (i = 0; i < AT_NUM; ++i) + bcs->commands[i] = NULL; + ++ spin_lock_init(&bcs->aplock); ++ bcs->ap = NULL; ++ bcs->apconnstate = 0; ++ + gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); + if (cs->ops->initbcshw(bcs)) + return bcs; +--- a/drivers/isdn/gigaset/gigaset.h ++++ b/drivers/isdn/gigaset/gigaset.h +@@ -403,7 +403,9 @@ struct bc_state { + struct bas_bc_state *bas; /* usb hardware driver (base) */ + } hw; + +- void *ap; /* LL application structure */ ++ void *ap; /* associated LL application */ ++ int apconnstate; /* LL application connection state */ ++ spinlock_t aplock; + }; + + struct cardstate { diff --git a/queue-2.6.34/isdn-gigaset-correct-capi-data_b3-delivery-confirmation.patch b/queue-2.6.34/isdn-gigaset-correct-capi-data_b3-delivery-confirmation.patch new file mode 100644 index 00000000000..142848da416 --- /dev/null +++ b/queue-2.6.34/isdn-gigaset-correct-capi-data_b3-delivery-confirmation.patch @@ -0,0 +1,148 @@ +From 23b36778b4c82577746d26e4ac0ae66c6f462475 Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Mon, 21 Jun 2010 13:54:50 +0000 +Subject: isdn/gigaset: correct CAPI DATA_B3 Delivery Confirmation + +From: Tilman Schmidt + +commit 23b36778b4c82577746d26e4ac0ae66c6f462475 upstream. + +The Gigaset CAPI driver handled all DATA_B3_REQ messages as if the +Delivery Confirmation flag bit was set, delaying the emission of the +DATA_B3_CONF reply until the data was actually transmitted. Some +CAPI applications (notably Asterisk) aren't happy with that +behaviour. Change it to actually evaluate the Delivery Confirmation +flag as described the CAPI specification. + +Impact: bugfix +Signed-off-by: Tilman Schmidt +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/gigaset/capi.c | 83 +++++++++++++++++++++++++++----------------- + 1 file changed, 51 insertions(+), 32 deletions(-) + +--- a/drivers/isdn/gigaset/capi.c ++++ b/drivers/isdn/gigaset/capi.c +@@ -331,6 +331,39 @@ static const char *format_ie(const char + return result; + } + ++/* ++ * emit DATA_B3_CONF message ++ */ ++static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, ++ u16 appl, u16 msgid, int channel, ++ u16 handle, u16 info) ++{ ++ struct sk_buff *cskb; ++ u8 *msg; ++ ++ cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); ++ if (!cskb) { ++ dev_err(cs->dev, "%s: out of memory\n", __func__); ++ return; ++ } ++ /* frequent message, avoid _cmsg overhead */ ++ msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); ++ CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); ++ CAPIMSG_SETAPPID(msg, appl); ++ CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); ++ CAPIMSG_SETSUBCOMMAND(msg, CAPI_CONF); ++ CAPIMSG_SETMSGID(msg, msgid); ++ CAPIMSG_SETCONTROLLER(msg, ctr->cnr); ++ CAPIMSG_SETPLCI_PART(msg, channel); ++ CAPIMSG_SETNCCI_PART(msg, 1); ++ CAPIMSG_SETHANDLE_CONF(msg, handle); ++ CAPIMSG_SETINFO_CONF(msg, info); ++ ++ /* emit message */ ++ dump_rawmsg(DEBUG_MCMD, __func__, msg); ++ capi_ctr_handle_message(ctr, appl, cskb); ++} ++ + + /* + * driver interface functions +@@ -351,7 +384,6 @@ void gigaset_skb_sent(struct bc_state *b + struct gigaset_capi_ctr *iif = cs->iif; + struct gigaset_capi_appl *ap = bcs->ap; + unsigned char *req = skb_mac_header(dskb); +- struct sk_buff *cskb; + u16 flags; + + /* update statistics */ +@@ -368,34 +400,17 @@ void gigaset_skb_sent(struct bc_state *b + return; + } + +- /* ToDo: honor unset "delivery confirmation" bit */ ++ /* ++ * send DATA_B3_CONF if "delivery confirmation" bit was set in request; ++ * otherwise it has already been sent by do_data_b3_req() ++ */ + flags = CAPIMSG_FLAGS(req); +- +- /* build DATA_B3_CONF message */ +- cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); +- if (!cskb) { +- dev_err(cs->dev, "%s: out of memory\n", __func__); +- return; +- } +- /* frequent message, avoid _cmsg overhead */ +- CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN); +- CAPIMSG_SETAPPID(cskb->data, ap->id); +- CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3); +- CAPIMSG_SETSUBCOMMAND(cskb->data, CAPI_CONF); +- CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req)); +- CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr); +- CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1); +- CAPIMSG_SETNCCI_PART(cskb->data, 1); +- CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req)); +- if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) +- CAPIMSG_SETINFO_CONF(cskb->data, +- CapiFlagsNotSupportedByProtocol); +- else +- CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR); +- +- /* emit message */ +- dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data); +- capi_ctr_handle_message(&iif->ctr, ap->id, cskb); ++ if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) ++ send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), ++ bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), ++ (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? ++ CapiFlagsNotSupportedByProtocol : ++ CAPI_NOERROR); + } + EXPORT_SYMBOL_GPL(gigaset_skb_sent); + +@@ -1806,6 +1821,8 @@ static void do_data_b3_req(struct gigase + u16 msglen = CAPIMSG_LEN(skb->data); + u16 datalen = CAPIMSG_DATALEN(skb->data); + u16 flags = CAPIMSG_FLAGS(skb->data); ++ u16 msgid = CAPIMSG_MSGID(skb->data); ++ u16 handle = CAPIMSG_HANDLE_REQ(skb->data); + + /* frequent message, avoid _cmsg overhead */ + dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data); +@@ -1856,12 +1873,14 @@ static void do_data_b3_req(struct gigase + return; + } + +- /* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */ +- + /* +- * ToDo: honor unset "delivery confirmation" bit +- * (send DATA_B3_CONF immediately?) ++ * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery ++ * confirmation" bit is set; otherwise we have to send it now + */ ++ if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) ++ send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, ++ flags ? CapiFlagsNotSupportedByProtocol ++ : CAPI_NOERROR); + } + + /* diff --git a/queue-2.6.34/isdn-gigaset-correct-capi-voice-connection-encoding.patch b/queue-2.6.34/isdn-gigaset-correct-capi-voice-connection-encoding.patch new file mode 100644 index 00000000000..115a67feba4 --- /dev/null +++ b/queue-2.6.34/isdn-gigaset-correct-capi-voice-connection-encoding.patch @@ -0,0 +1,57 @@ +From 278a582989ade4cb5335762d6c5999562018859d Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Mon, 21 Jun 2010 13:54:35 +0000 +Subject: isdn/gigaset: correct CAPI voice connection encoding + +From: Tilman Schmidt + +commit 278a582989ade4cb5335762d6c5999562018859d upstream. + +Make the Gigaset CAPI driver select L2_VOICE (AT^SBPR=2) as the +layer 2 encoding for transparent connections, like the ISDN4Linux +variant. L2_BITSYNC (AT^SBPR=0) mutes internal connections and +distorts external ones. + +Impact: bugfix +Signed-off-by: Tilman Schmidt +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/gigaset/capi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/isdn/gigaset/capi.c ++++ b/drivers/isdn/gigaset/capi.c +@@ -1338,13 +1338,13 @@ static void do_connect_req(struct gigase + bcs->proto2 = L2_HDLC; + break; + case 1: +- bcs->proto2 = L2_BITSYNC; ++ bcs->proto2 = L2_VOICE; + break; + default: + dev_warn(cs->dev, + "B1 Protocol %u unsupported, using Transparent\n", + cmsg->B1protocol); +- bcs->proto2 = L2_BITSYNC; ++ bcs->proto2 = L2_VOICE; + } + if (cmsg->B2protocol != 1) + dev_warn(cs->dev, +@@ -1467,13 +1467,13 @@ static void do_connect_resp(struct gigas + bcs->proto2 = L2_HDLC; + break; + case 1: +- bcs->proto2 = L2_BITSYNC; ++ bcs->proto2 = L2_VOICE; + break; + default: + dev_warn(cs->dev, + "B1 Protocol %u unsupported, using Transparent\n", + cmsg->B1protocol); +- bcs->proto2 = L2_BITSYNC; ++ bcs->proto2 = L2_VOICE; + } + if (cmsg->B2protocol != 1) + dev_warn(cs->dev, diff --git a/queue-2.6.34/isdn-gigaset-encode-hlc-and-bc-together.patch b/queue-2.6.34/isdn-gigaset-encode-hlc-and-bc-together.patch new file mode 100644 index 00000000000..1ac76ccc7d2 --- /dev/null +++ b/queue-2.6.34/isdn-gigaset-encode-hlc-and-bc-together.patch @@ -0,0 +1,154 @@ +From 1ce368ff288ed872a8fee93b8a2b7706111feb9a Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Mon, 21 Jun 2010 13:55:05 +0000 +Subject: isdn/gigaset: encode HLC and BC together + +From: Tilman Schmidt + +commit 1ce368ff288ed872a8fee93b8a2b7706111feb9a upstream. + +Adapt to buggy device firmware which accepts setting HLC only in the +same command line as BC, by encoding HLC and BC in a single command +if both are specified, and rejecting HLC without BC. + +Impact: bugfix +Signed-off-by: Tilman Schmidt +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/gigaset/capi.c | 81 ++++++++++++++++++++++++---------------- + drivers/isdn/gigaset/ev-layer.c | 4 - + drivers/isdn/gigaset/gigaset.h | 5 -- + 3 files changed, 52 insertions(+), 38 deletions(-) + +--- a/drivers/isdn/gigaset/capi.c ++++ b/drivers/isdn/gigaset/capi.c +@@ -1177,7 +1177,7 @@ static void do_connect_req(struct gigase + char **commands; + char *s; + u8 *pp; +- int i, l; ++ int i, l, lbc, lhlc; + u16 info; + + /* decode message */ +@@ -1304,42 +1304,59 @@ static void do_connect_req(struct gigase + goto error; + } + +- /* check/encode parameter: BC */ +- if (cmsg->BC && cmsg->BC[0]) { +- /* explicit BC overrides CIP */ +- l = 2*cmsg->BC[0] + 7; ++ /* ++ * check/encode parameters: BC & HLC ++ * must be encoded together as device doesn't accept HLC separately ++ * explicit parameters override values derived from CIP ++ */ ++ ++ /* determine lengths */ ++ if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ ++ lbc = 2*cmsg->BC[0]; ++ else if (cip2bchlc[cmsg->CIPValue].bc) /* BC derived from CIP */ ++ lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); ++ else /* no BC */ ++ lbc = 0; ++ if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ ++ lhlc = 2*cmsg->HLC[0]; ++ else if (cip2bchlc[cmsg->CIPValue].hlc) /* HLC derived from CIP */ ++ lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); ++ else /* no HLC */ ++ lhlc = 0; ++ ++ if (lbc) { ++ /* have BC: allocate and assemble command string */ ++ l = lbc + 7; /* "^SBC=" + value + "\r" + null byte */ ++ if (lhlc) ++ l += lhlc + 7; /* ";^SHLC=" + value */ + commands[AT_BC] = kmalloc(l, GFP_KERNEL); + if (!commands[AT_BC]) + goto oom; + strcpy(commands[AT_BC], "^SBC="); +- decode_ie(cmsg->BC, commands[AT_BC]+5); ++ if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ ++ decode_ie(cmsg->BC, commands[AT_BC] + 5); ++ else /* BC derived from CIP */ ++ strcpy(commands[AT_BC] + 5, ++ cip2bchlc[cmsg->CIPValue].bc); ++ if (lhlc) { ++ strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); ++ if (cmsg->HLC && cmsg->HLC[0]) ++ /* HLC specified explicitly */ ++ decode_ie(cmsg->HLC, ++ commands[AT_BC] + lbc + 12); ++ else /* HLC derived from CIP */ ++ strcpy(commands[AT_BC] + lbc + 12, ++ cip2bchlc[cmsg->CIPValue].hlc); ++ } + strcpy(commands[AT_BC] + l - 2, "\r"); +- } else if (cip2bchlc[cmsg->CIPValue].bc) { +- l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7; +- commands[AT_BC] = kmalloc(l, GFP_KERNEL); +- if (!commands[AT_BC]) +- goto oom; +- snprintf(commands[AT_BC], l, "^SBC=%s\r", +- cip2bchlc[cmsg->CIPValue].bc); +- } +- +- /* check/encode parameter: HLC */ +- if (cmsg->HLC && cmsg->HLC[0]) { +- /* explicit HLC overrides CIP */ +- l = 2*cmsg->HLC[0] + 7; +- commands[AT_HLC] = kmalloc(l, GFP_KERNEL); +- if (!commands[AT_HLC]) +- goto oom; +- strcpy(commands[AT_HLC], "^SHLC="); +- decode_ie(cmsg->HLC, commands[AT_HLC]+5); +- strcpy(commands[AT_HLC] + l - 2, "\r"); +- } else if (cip2bchlc[cmsg->CIPValue].hlc) { +- l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7; +- commands[AT_HLC] = kmalloc(l, GFP_KERNEL); +- if (!commands[AT_HLC]) +- goto oom; +- snprintf(commands[AT_HLC], l, "^SHLC=%s\r", +- cip2bchlc[cmsg->CIPValue].hlc); ++ } else { ++ /* no BC */ ++ if (lhlc) { ++ dev_notice(cs->dev, "%s: cannot set HLC without BC\n", ++ "CONNECT_REQ"); ++ info = CapiIllMessageParmCoding; /* ? */ ++ goto error; ++ } + } + + /* check/encode parameter: B Protocol */ +--- a/drivers/isdn/gigaset/ev-layer.c ++++ b/drivers/isdn/gigaset/ev-layer.c +@@ -282,9 +282,7 @@ struct reply_t gigaset_tab_cid[] = + /* dial */ + {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} }, + {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD+AT_BC} }, +-{RSP_OK, 601, 601, -1, 602, 5, {ACT_CMD+AT_HLC} }, +-{RSP_NULL, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} }, +-{RSP_OK, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} }, ++{RSP_OK, 601, 601, -1, 603, 5, {ACT_CMD+AT_PROTO} }, + {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD+AT_TYPE} }, + {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD+AT_MSN} }, + {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} }, +--- a/drivers/isdn/gigaset/gigaset.h ++++ b/drivers/isdn/gigaset/gigaset.h +@@ -186,10 +186,9 @@ void gigaset_dbg_buffer(enum debuglevel + #define AT_BC 3 + #define AT_PROTO 4 + #define AT_TYPE 5 +-#define AT_HLC 6 +-#define AT_CLIP 7 ++#define AT_CLIP 6 + /* total number */ +-#define AT_NUM 8 ++#define AT_NUM 7 + + /* variables in struct at_state_t */ + #define VAR_ZSAU 0 diff --git a/queue-2.6.34/isdn-gigaset-honor-capi-application-s-buffer-size-request.patch b/queue-2.6.34/isdn-gigaset-honor-capi-application-s-buffer-size-request.patch new file mode 100644 index 00000000000..347c8425a57 --- /dev/null +++ b/queue-2.6.34/isdn-gigaset-honor-capi-application-s-buffer-size-request.patch @@ -0,0 +1,490 @@ +From e7752ee280608a24e27f163641121bdc2c68d6af Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Mon, 21 Jun 2010 13:54:19 +0000 +Subject: isdn/gigaset: honor CAPI application's buffer size request + +From: Tilman Schmidt + +commit e7752ee280608a24e27f163641121bdc2c68d6af upstream. + +Fix the Gigaset CAPI driver to limit the length of a connection's +payload data receive buffers to the corresponding CAPI application's +data buffer size, as some real-life CAPI applications tend to be +rather unhappy if they receive bigger data blocks than requested. + +Impact: bugfix +Signed-off-by: Tilman Schmidt +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/gigaset/asyncdata.c | 44 +++++------------------ + drivers/isdn/gigaset/capi.c | 8 ++++ + drivers/isdn/gigaset/common.c | 32 ++++------------- + drivers/isdn/gigaset/gigaset.h | 29 +++++++++++---- + drivers/isdn/gigaset/i4l.c | 21 +++++++++++ + drivers/isdn/gigaset/isocdata.c | 72 +++++++++++++-------------------------- + 6 files changed, 94 insertions(+), 112 deletions(-) + +--- a/drivers/isdn/gigaset/asyncdata.c ++++ b/drivers/isdn/gigaset/asyncdata.c +@@ -126,26 +126,6 @@ static unsigned lock_loop(unsigned numby + return numbytes; + } + +-/* set up next receive skb for data mode +- */ +-static void new_rcv_skb(struct bc_state *bcs) +-{ +- struct cardstate *cs = bcs->cs; +- unsigned short hw_hdr_len = cs->hw_hdr_len; +- +- if (bcs->ignore) { +- bcs->skb = NULL; +- return; +- } +- +- bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); +- if (bcs->skb == NULL) { +- dev_warn(cs->dev, "could not allocate new skb\n"); +- return; +- } +- skb_reserve(bcs->skb, hw_hdr_len); +-} +- + /* process a block of received bytes in HDLC data mode + * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) + * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. +@@ -159,8 +139,8 @@ static unsigned hdlc_loop(unsigned numby + struct cardstate *cs = inbuf->cs; + struct bc_state *bcs = cs->bcs; + int inputstate = bcs->inputstate; +- __u16 fcs = bcs->fcs; +- struct sk_buff *skb = bcs->skb; ++ __u16 fcs = bcs->rx_fcs; ++ struct sk_buff *skb = bcs->rx_skb; + unsigned char *src = inbuf->data + inbuf->head; + unsigned procbytes = 0; + unsigned char c; +@@ -245,8 +225,7 @@ byte_stuff: + + /* prepare reception of next frame */ + inputstate &= ~INS_have_data; +- new_rcv_skb(bcs); +- skb = bcs->skb; ++ skb = gigaset_new_rx_skb(bcs); + } else { + /* empty frame (7E 7E) */ + #ifdef CONFIG_GIGASET_DEBUG +@@ -255,8 +234,7 @@ byte_stuff: + if (!skb) { + /* skipped (?) */ + gigaset_isdn_rcv_err(bcs); +- new_rcv_skb(bcs); +- skb = bcs->skb; ++ skb = gigaset_new_rx_skb(bcs); + } + } + +@@ -279,11 +257,11 @@ byte_stuff: + #endif + inputstate |= INS_have_data; + if (skb) { +- if (skb->len == SBUFSIZE) { ++ if (skb->len >= bcs->rx_bufsize) { + dev_warn(cs->dev, "received packet too long\n"); + dev_kfree_skb_any(skb); + /* skip remainder of packet */ +- bcs->skb = skb = NULL; ++ bcs->rx_skb = skb = NULL; + } else { + *__skb_put(skb, 1) = c; + fcs = crc_ccitt_byte(fcs, c); +@@ -292,7 +270,7 @@ byte_stuff: + } + + bcs->inputstate = inputstate; +- bcs->fcs = fcs; ++ bcs->rx_fcs = fcs; + return procbytes; + } + +@@ -308,18 +286,18 @@ static unsigned iraw_loop(unsigned numby + struct cardstate *cs = inbuf->cs; + struct bc_state *bcs = cs->bcs; + int inputstate = bcs->inputstate; +- struct sk_buff *skb = bcs->skb; ++ struct sk_buff *skb = bcs->rx_skb; + unsigned char *src = inbuf->data + inbuf->head; + unsigned procbytes = 0; + unsigned char c; + + if (!skb) { + /* skip this block */ +- new_rcv_skb(bcs); ++ gigaset_new_rx_skb(bcs); + return numbytes; + } + +- while (procbytes < numbytes && skb->len < SBUFSIZE) { ++ while (procbytes < numbytes && skb->len < bcs->rx_bufsize) { + c = *src++; + procbytes++; + +@@ -343,7 +321,7 @@ static unsigned iraw_loop(unsigned numby + if (inputstate & INS_have_data) { + gigaset_skb_rcvd(bcs, skb); + inputstate &= ~INS_have_data; +- new_rcv_skb(bcs); ++ gigaset_new_rx_skb(bcs); + } + + bcs->inputstate = inputstate; +--- a/drivers/isdn/gigaset/capi.c ++++ b/drivers/isdn/gigaset/capi.c +@@ -80,6 +80,7 @@ struct gigaset_capi_appl { + struct list_head ctrlist; + struct gigaset_capi_appl *bcnext; + u16 id; ++ struct capi_register_params rp; + u16 nextMessageNumber; + u32 listenInfoMask; + u32 listenCIPmask; +@@ -956,6 +957,7 @@ static void gigaset_register_appl(struct + return; + } + ap->id = appl; ++ ap->rp = *rp; + + list_add(&ap->ctrlist, &iif->appls); + } +@@ -1177,6 +1179,9 @@ static void do_connect_req(struct gigase + } + ap->bcnext = NULL; + bcs->ap = ap; ++ bcs->rx_bufsize = ap->rp.datablklen; ++ dev_kfree_skb(bcs->rx_skb); ++ gigaset_new_rx_skb(bcs); + cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; + + /* build command table */ +@@ -1446,6 +1451,9 @@ static void do_connect_resp(struct gigas + CapiCallGivenToOtherApplication); + ap->bcnext = NULL; + bcs->ap = ap; ++ bcs->rx_bufsize = ap->rp.datablklen; ++ dev_kfree_skb(bcs->rx_skb); ++ gigaset_new_rx_skb(bcs); + bcs->chstate |= CHS_NOTIFY_LL; + + /* check/encode B channel protocol */ +--- a/drivers/isdn/gigaset/common.c ++++ b/drivers/isdn/gigaset/common.c +@@ -399,8 +399,8 @@ static void gigaset_freebcs(struct bc_st + gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); + clear_at_state(&bcs->at_state); + gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); +- dev_kfree_skb(bcs->skb); +- bcs->skb = NULL; ++ dev_kfree_skb(bcs->rx_skb); ++ bcs->rx_skb = NULL; + + for (i = 0; i < AT_NUM; ++i) { + kfree(bcs->commands[i]); +@@ -634,19 +634,10 @@ static struct bc_state *gigaset_initbcs( + bcs->emptycount = 0; + #endif + +- gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); +- bcs->fcs = PPP_INITFCS; ++ bcs->rx_bufsize = 0; ++ bcs->rx_skb = NULL; ++ bcs->rx_fcs = PPP_INITFCS; + bcs->inputstate = 0; +- if (cs->ignoreframes) { +- bcs->skb = NULL; +- } else { +- bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); +- if (bcs->skb != NULL) +- skb_reserve(bcs->skb, cs->hw_hdr_len); +- else +- pr_err("out of memory\n"); +- } +- + bcs->channel = channel; + bcs->cs = cs; + +@@ -663,11 +654,6 @@ static struct bc_state *gigaset_initbcs( + return bcs; + + gig_dbg(DEBUG_INIT, " failed"); +- +- gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); +- dev_kfree_skb(bcs->skb); +- bcs->skb = NULL; +- + return NULL; + } + +@@ -839,14 +825,12 @@ void gigaset_bcs_reinit(struct bc_state + bcs->emptycount = 0; + #endif + +- bcs->fcs = PPP_INITFCS; ++ bcs->rx_fcs = PPP_INITFCS; + bcs->chstate = 0; + + bcs->ignore = cs->ignoreframes; +- if (bcs->ignore) { +- dev_kfree_skb(bcs->skb); +- bcs->skb = NULL; +- } ++ dev_kfree_skb(bcs->rx_skb); ++ bcs->rx_skb = NULL; + + cs->ops->reinitbcshw(bcs); + } +--- a/drivers/isdn/gigaset/gigaset.h ++++ b/drivers/isdn/gigaset/gigaset.h +@@ -45,10 +45,6 @@ + #define MAX_EVENTS 64 /* size of event queue */ + + #define RBUFSIZE 8192 +-#define SBUFSIZE 4096 /* sk_buff payload size */ +- +-#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ +-#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */ + + /* compile time options */ + #define GIG_MAJOR 0 +@@ -380,8 +376,10 @@ struct bc_state { + + struct at_state_t at_state; + +- __u16 fcs; +- struct sk_buff *skb; ++ /* receive buffer */ ++ unsigned rx_bufsize; /* max size accepted by application */ ++ struct sk_buff *rx_skb; ++ __u16 rx_fcs; + int inputstate; /* see INS_XXXX */ + + int channel; +@@ -801,8 +799,23 @@ static inline void gigaset_bchannel_up(s + gigaset_schedule_event(bcs->cs); + } + +-/* handling routines for sk_buff */ +-/* ============================= */ ++/* set up next receive skb for data mode */ ++static inline struct sk_buff *gigaset_new_rx_skb(struct bc_state *bcs) ++{ ++ struct cardstate *cs = bcs->cs; ++ unsigned short hw_hdr_len = cs->hw_hdr_len; ++ ++ if (bcs->ignore) { ++ bcs->rx_skb = NULL; ++ } else { ++ bcs->rx_skb = dev_alloc_skb(bcs->rx_bufsize + hw_hdr_len); ++ if (bcs->rx_skb == NULL) ++ dev_warn(cs->dev, "could not allocate skb\n"); ++ else ++ skb_reserve(bcs->rx_skb, hw_hdr_len); ++ } ++ return bcs->rx_skb; ++} + + /* append received bytes to inbuf */ + int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, +--- a/drivers/isdn/gigaset/i4l.c ++++ b/drivers/isdn/gigaset/i4l.c +@@ -16,7 +16,10 @@ + #include "gigaset.h" + #include + ++#define SBUFSIZE 4096 /* sk_buff payload size */ ++#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ + #define HW_HDR_LEN 2 /* Header size used to store ack info */ ++#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */ + + /* == Handling of I4L IO =====================================================*/ + +@@ -231,6 +234,15 @@ static int command_from_LL(isdn_ctrl *cn + dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); + return -EBUSY; + } ++ switch (bcs->proto2) { ++ case L2_HDLC: ++ bcs->rx_bufsize = SBUFSIZE; ++ break; ++ default: /* assume transparent */ ++ bcs->rx_bufsize = TRANSBUFSIZE; ++ } ++ dev_kfree_skb(bcs->rx_skb); ++ gigaset_new_rx_skb(bcs); + + commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC); + if (!commands) { +@@ -314,6 +326,15 @@ static int command_from_LL(isdn_ctrl *cn + return -EINVAL; + } + bcs = cs->bcs + ch; ++ switch (bcs->proto2) { ++ case L2_HDLC: ++ bcs->rx_bufsize = SBUFSIZE; ++ break; ++ default: /* assume transparent */ ++ bcs->rx_bufsize = TRANSBUFSIZE; ++ } ++ dev_kfree_skb(bcs->rx_skb); ++ gigaset_new_rx_skb(bcs); + if (!gigaset_add_event(cs, &bcs->at_state, + EV_ACCEPT, NULL, 0, NULL)) + return -ENOMEM; +--- a/drivers/isdn/gigaset/isocdata.c ++++ b/drivers/isdn/gigaset/isocdata.c +@@ -500,19 +500,18 @@ int gigaset_isoc_buildframe(struct bc_st + */ + static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) + { +- bcs->fcs = crc_ccitt_byte(bcs->fcs, c); +- if (unlikely(bcs->skb == NULL)) { ++ bcs->rx_fcs = crc_ccitt_byte(bcs->rx_fcs, c); ++ if (bcs->rx_skb == NULL) + /* skipping */ + return; +- } +- if (unlikely(bcs->skb->len == SBUFSIZE)) { ++ if (bcs->rx_skb->len >= bcs->rx_bufsize) { + dev_warn(bcs->cs->dev, "received oversized packet discarded\n"); + bcs->hw.bas->giants++; +- dev_kfree_skb_any(bcs->skb); +- bcs->skb = NULL; ++ dev_kfree_skb_any(bcs->rx_skb); ++ bcs->rx_skb = NULL; + return; + } +- *__skb_put(bcs->skb, 1) = c; ++ *__skb_put(bcs->rx_skb, 1) = c; + } + + /* hdlc_flush +@@ -521,18 +520,13 @@ static inline void hdlc_putbyte(unsigned + static inline void hdlc_flush(struct bc_state *bcs) + { + /* clear skb or allocate new if not skipping */ +- if (likely(bcs->skb != NULL)) +- skb_trim(bcs->skb, 0); +- else if (!bcs->ignore) { +- bcs->skb = dev_alloc_skb(SBUFSIZE + bcs->cs->hw_hdr_len); +- if (bcs->skb) +- skb_reserve(bcs->skb, bcs->cs->hw_hdr_len); +- else +- dev_err(bcs->cs->dev, "could not allocate skb\n"); +- } ++ if (bcs->rx_skb != NULL) ++ skb_trim(bcs->rx_skb, 0); ++ else ++ gigaset_new_rx_skb(bcs); + + /* reset packet state */ +- bcs->fcs = PPP_INITFCS; ++ bcs->rx_fcs = PPP_INITFCS; + } + + /* hdlc_done +@@ -549,7 +543,7 @@ static inline void hdlc_done(struct bc_s + hdlc_flush(bcs); + return; + } +- procskb = bcs->skb; ++ procskb = bcs->rx_skb; + if (procskb == NULL) { + /* previous error */ + gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); +@@ -560,8 +554,8 @@ static inline void hdlc_done(struct bc_s + bcs->hw.bas->runts++; + dev_kfree_skb_any(procskb); + gigaset_isdn_rcv_err(bcs); +- } else if (bcs->fcs != PPP_GOODFCS) { +- dev_notice(cs->dev, "frame check error (0x%04x)\n", bcs->fcs); ++ } else if (bcs->rx_fcs != PPP_GOODFCS) { ++ dev_notice(cs->dev, "frame check error\n"); + bcs->hw.bas->fcserrs++; + dev_kfree_skb_any(procskb); + gigaset_isdn_rcv_err(bcs); +@@ -574,13 +568,8 @@ static inline void hdlc_done(struct bc_s + bcs->hw.bas->goodbytes += len; + gigaset_skb_rcvd(bcs, procskb); + } +- +- bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); +- if (bcs->skb) +- skb_reserve(bcs->skb, cs->hw_hdr_len); +- else +- dev_err(cs->dev, "could not allocate skb\n"); +- bcs->fcs = PPP_INITFCS; ++ gigaset_new_rx_skb(bcs); ++ bcs->rx_fcs = PPP_INITFCS; + } + + /* hdlc_frag +@@ -597,8 +586,8 @@ static inline void hdlc_frag(struct bc_s + dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits); + bcs->hw.bas->alignerrs++; + gigaset_isdn_rcv_err(bcs); +- __skb_trim(bcs->skb, 0); +- bcs->fcs = PPP_INITFCS; ++ __skb_trim(bcs->rx_skb, 0); ++ bcs->rx_fcs = PPP_INITFCS; + } + + /* bit counts lookup table for HDLC bit unstuffing +@@ -847,7 +836,6 @@ static inline void hdlc_unpack(unsigned + static inline void trans_receive(unsigned char *src, unsigned count, + struct bc_state *bcs) + { +- struct cardstate *cs = bcs->cs; + struct sk_buff *skb; + int dobytes; + unsigned char *dst; +@@ -857,17 +845,11 @@ static inline void trans_receive(unsigne + hdlc_flush(bcs); + return; + } +- skb = bcs->skb; +- if (unlikely(skb == NULL)) { +- bcs->skb = skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); +- if (!skb) { +- dev_err(cs->dev, "could not allocate skb\n"); +- return; +- } +- skb_reserve(skb, cs->hw_hdr_len); +- } ++ skb = bcs->rx_skb; ++ if (skb == NULL) ++ skb = gigaset_new_rx_skb(bcs); + bcs->hw.bas->goodbytes += skb->len; +- dobytes = TRANSBUFSIZE - skb->len; ++ dobytes = bcs->rx_bufsize - skb->len; + while (count > 0) { + dst = skb_put(skb, count < dobytes ? count : dobytes); + while (count > 0 && dobytes > 0) { +@@ -879,14 +861,10 @@ static inline void trans_receive(unsigne + dump_bytes(DEBUG_STREAM_DUMP, + "rcv data", skb->data, skb->len); + gigaset_skb_rcvd(bcs, skb); +- bcs->skb = skb = +- dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); +- if (!skb) { +- dev_err(cs->dev, "could not allocate skb\n"); ++ skb = gigaset_new_rx_skb(bcs); ++ if (skb == NULL) + return; +- } +- skb_reserve(skb, cs->hw_hdr_len); +- dobytes = TRANSBUFSIZE; ++ dobytes = bcs->rx_bufsize; + } + } + } diff --git a/queue-2.6.34/isdn-gigaset-remove-dummy-capi-method-implementations.patch b/queue-2.6.34/isdn-gigaset-remove-dummy-capi-method-implementations.patch new file mode 100644 index 00000000000..b7b5bef79a8 --- /dev/null +++ b/queue-2.6.34/isdn-gigaset-remove-dummy-capi-method-implementations.patch @@ -0,0 +1,66 @@ +From e487639dc8ca6bd6c19a4140f45ebc88da56ddd5 Mon Sep 17 00:00:00 2001 +From: Tilman Schmidt +Date: Sun, 23 May 2010 01:02:38 +0000 +Subject: isdn/gigaset: remove dummy CAPI method implementations + +From: Tilman Schmidt + +commit e487639dc8ca6bd6c19a4140f45ebc88da56ddd5 upstream. + +Dummy implementations for the optional CAPI controller operations +load_firmware and reset_ctr can cause userspace callers to hang +indefinitely. It's better not to implement them at all. + +Signed-off-by: Tilman Schmidt +Acked-by: Karsten Keil +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/isdn/gigaset/capi.c | 28 ++-------------------------- + 1 file changed, 2 insertions(+), 26 deletions(-) + +--- a/drivers/isdn/gigaset/capi.c ++++ b/drivers/isdn/gigaset/capi.c +@@ -933,30 +933,6 @@ void gigaset_isdn_stop(struct cardstate + */ + + /* +- * load firmware +- */ +-static int gigaset_load_firmware(struct capi_ctr *ctr, capiloaddata *data) +-{ +- struct cardstate *cs = ctr->driverdata; +- +- /* AVM specific operation, not needed for Gigaset -- ignore */ +- dev_notice(cs->dev, "load_firmware ignored\n"); +- +- return 0; +-} +- +-/* +- * reset (deactivate) controller +- */ +-static void gigaset_reset_ctr(struct capi_ctr *ctr) +-{ +- struct cardstate *cs = ctr->driverdata; +- +- /* AVM specific operation, not needed for Gigaset -- ignore */ +- dev_notice(cs->dev, "reset_ctr ignored\n"); +-} +- +-/* + * register CAPI application + */ + static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, +@@ -2213,8 +2189,8 @@ int gigaset_isdn_regdev(struct cardstate + iif->ctr.driverdata = cs; + strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name)); + iif->ctr.driver_name = "gigaset"; +- iif->ctr.load_firmware = gigaset_load_firmware; +- iif->ctr.reset_ctr = gigaset_reset_ctr; ++ iif->ctr.load_firmware = NULL; ++ iif->ctr.reset_ctr = NULL; + iif->ctr.register_appl = gigaset_register_appl; + iif->ctr.release_appl = gigaset_release_appl; + iif->ctr.send_message = gigaset_send_message; diff --git a/queue-2.6.34/pci-pm-do-not-use-native-pcie-pme-by-default.patch b/queue-2.6.34/pci-pm-do-not-use-native-pcie-pme-by-default.patch new file mode 100644 index 00000000000..9d04d05a1c4 --- /dev/null +++ b/queue-2.6.34/pci-pm-do-not-use-native-pcie-pme-by-default.patch @@ -0,0 +1,92 @@ +From b27759f880018b0cd43543dc94c921341b64b5ec Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Fri, 18 Jun 2010 17:04:22 +0200 +Subject: PCI/PM: Do not use native PCIe PME by default +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +commit b27759f880018b0cd43543dc94c921341b64b5ec upstream. + +Commit c7f486567c1d0acd2e4166c47069835b9f75e77b +(PCI PM: PCIe PME root port service driver) causes the native PCIe +PME signaling to be used by default, if the BIOS allows the kernel to +control the standard configuration registers of PCIe root ports. +However, the native PCIe PME is coupled to the native PCIe hotplug +and calling pcie_pme_acpi_setup() makes some BIOSes expect that +the native PCIe hotplug will be used as well. That, in turn, causes +problems to appear on systems where the PCIe hotplug driver is not +loaded. The usual symptom, as reported by Jaroslav Kameník and +others, is that the ACPI GPE associated with PCIe hotplug keeps +firing continuously causing kacpid to take substantial percentage +of CPU time. + +To work around this issue, change the default so that the native +PCIe PME signaling is only used if directly requested with the help +of the pcie_pme= command line switch. + +Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15924 , which is +a listed regression from 2.6.33. + +Signed-off-by: Rafael J. Wysocki +Reported-by: Jaroslav Kameník +Tested-by: Antoni Grzymala +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/kernel-parameters.txt | 4 +++- + drivers/pci/pcie/pme/pcie_pme.c | 19 +++++++++++++------ + 2 files changed, 16 insertions(+), 7 deletions(-) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -2013,7 +2013,9 @@ and is between 256 and 4096 characters. + WARNING: Forcing ASPM on may cause system lockups. + + pcie_pme= [PCIE,PM] Native PCIe PME signaling options: +- off Do not use native PCIe PME signaling. ++ Format: {auto|force}[,nomsi] ++ auto Use native PCIe PME signaling if the BIOS allows the ++ kernel to control PCIe config registers of root ports. + force Use native PCIe PME signaling even if the BIOS refuses + to allow the kernel to control the relevant PCIe config + registers. +--- a/drivers/pci/pcie/pme/pcie_pme.c ++++ b/drivers/pci/pcie/pme/pcie_pme.c +@@ -34,7 +34,7 @@ + * being registered. Consequently, the interrupt-based PCIe PME signaling will + * not be used by any PCIe root ports in that case. + */ +-static bool pcie_pme_disabled; ++static bool pcie_pme_disabled = true; + + /* + * The PCI Express Base Specification 2.0, Section 6.1.8, states the following: +@@ -64,12 +64,19 @@ bool pcie_pme_msi_disabled; + + static int __init pcie_pme_setup(char *str) + { +- if (!strcmp(str, "off")) +- pcie_pme_disabled = true; +- else if (!strcmp(str, "force")) ++ if (!strncmp(str, "auto", 4)) ++ pcie_pme_disabled = false; ++ else if (!strncmp(str, "force", 5)) + pcie_pme_force_enable = true; +- else if (!strcmp(str, "nomsi")) +- pcie_pme_msi_disabled = true; ++ ++ str = strchr(str, ','); ++ if (str) { ++ str++; ++ str += strspn(str, " \t"); ++ if (*str && !strcmp(str, "nomsi")) ++ pcie_pme_msi_disabled = true; ++ } ++ + return 1; + } + __setup("pcie_pme=", pcie_pme_setup); diff --git a/queue-2.6.34/pm-x86-save-restore-misc_enable-register.patch b/queue-2.6.34/pm-x86-save-restore-misc_enable-register.patch new file mode 100644 index 00000000000..d17e929745d --- /dev/null +++ b/queue-2.6.34/pm-x86-save-restore-misc_enable-register.patch @@ -0,0 +1,69 @@ +From 85a0e7539781dad4bfcffd98e72fa9f130f4e40d Mon Sep 17 00:00:00 2001 +From: Ondrej Zary +Date: Tue, 8 Jun 2010 00:32:49 +0200 +Subject: PM / x86: Save/restore MISC_ENABLE register + +From: Ondrej Zary + +commit 85a0e7539781dad4bfcffd98e72fa9f130f4e40d upstream. + +Save/restore MISC_ENABLE register on suspend/resume. +This fixes OOPS (invalid opcode) on resume from STR on Asus P4P800-VM, +which wakes up with MWAIT disabled. + +Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15385 + +Signed-off-by: Ondrej Zary +Tested-by: Alan Stern +Acked-by: H. Peter Anvin +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/include/asm/suspend_32.h | 2 ++ + arch/x86/include/asm/suspend_64.h | 2 ++ + arch/x86/power/cpu.c | 4 ++++ + 3 files changed, 8 insertions(+) + +--- a/arch/x86/include/asm/suspend_32.h ++++ b/arch/x86/include/asm/suspend_32.h +@@ -15,6 +15,8 @@ static inline int arch_prepare_suspend(v + struct saved_context { + u16 es, fs, gs, ss; + unsigned long cr0, cr2, cr3, cr4; ++ u64 misc_enable; ++ bool misc_enable_saved; + struct desc_ptr gdt; + struct desc_ptr idt; + u16 ldt; +--- a/arch/x86/include/asm/suspend_64.h ++++ b/arch/x86/include/asm/suspend_64.h +@@ -27,6 +27,8 @@ struct saved_context { + u16 ds, es, fs, gs, ss; + unsigned long gs_base, gs_kernel_base, fs_base; + unsigned long cr0, cr2, cr3, cr4, cr8; ++ u64 misc_enable; ++ bool misc_enable_saved; + unsigned long efer; + u16 gdt_pad; + u16 gdt_limit; +--- a/arch/x86/power/cpu.c ++++ b/arch/x86/power/cpu.c +@@ -105,6 +105,8 @@ static void __save_processor_state(struc + ctxt->cr4 = read_cr4(); + ctxt->cr8 = read_cr8(); + #endif ++ ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE, ++ &ctxt->misc_enable); + } + + /* Needed by apm.c */ +@@ -152,6 +154,8 @@ static void fix_processor_context(void) + */ + static void __restore_processor_state(struct saved_context *ctxt) + { ++ if (ctxt->misc_enable_saved) ++ wrmsrl(MSR_IA32_MISC_ENABLE, ctxt->misc_enable); + /* + * control registers + */ diff --git a/queue-2.6.34/series b/queue-2.6.34/series index bf2420e0069..a8af551c135 100644 --- a/queue-2.6.34/series +++ b/queue-2.6.34/series @@ -150,3 +150,19 @@ ethtool-fix-potential-user-buffer-overflow-for-ethtool_-g-s-rxfh.patch 0003-KVM-SVM-Implement-workaround-for-Erratum-383.patch 0004-KVM-MMU-invalidate-and-flush-on-spte-small-large-pag.patch 0005-KVM-read-apic-irr-with-ioapic-lock-held.patch +splice-direct_splice_actor-should-not-use-pos-in-sd.patch +splice-check-f_mode-for-seekable-file.patch +writeback-remove-writeback_inodes_wbc.patch +futex-futex_find_get_task-remove-credentails-check.patch +pm-x86-save-restore-misc_enable-register.patch +pci-pm-do-not-use-native-pcie-pme-by-default.patch +isdn-capi-make-reset_ctr-op-truly-optional.patch +isdn-gigaset-remove-dummy-capi-method-implementations.patch +isdn-gigaset-honor-capi-application-s-buffer-size-request.patch +isdn-gigaset-correct-capi-voice-connection-encoding.patch +isdn-gigaset-correct-capi-data_b3-delivery-confirmation.patch +isdn-gigaset-encode-hlc-and-bc-together.patch +isdn-gigaset-correct-capi-connection-state-storage.patch +acpi-skip-checking-bm_sts-if-the-bios-doesn-t-ask-for-it.patch +acpi-pm-do-not-enable-gpes-for-system-wakeup-in-advance.patch +acpi-unconditionally-set-sci_en-on-resume.patch diff --git a/queue-2.6.34/splice-check-f_mode-for-seekable-file.patch b/queue-2.6.34/splice-check-f_mode-for-seekable-file.patch new file mode 100644 index 00000000000..56aa895905b --- /dev/null +++ b/queue-2.6.34/splice-check-f_mode-for-seekable-file.patch @@ -0,0 +1,45 @@ +From 19c9a49b432f245c6293508d164a4350f1f2c601 Mon Sep 17 00:00:00 2001 +From: Changli Gao +Date: Tue, 29 Jun 2010 13:10:36 +0200 +Subject: splice: check f_mode for seekable file + +From: Changli Gao + +commit 19c9a49b432f245c6293508d164a4350f1f2c601 upstream. + +check f_mode for seekable file + +As a seekable file is allowed without a llseek function, so the old way isn't +work any more. + +Signed-off-by: Changli Gao +Signed-off-by: Miklos Szeredi +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + fs/splice.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1322,8 +1322,7 @@ static long do_splice(struct file *in, l + if (off_in) + return -ESPIPE; + if (off_out) { +- if (!out->f_op || !out->f_op->llseek || +- out->f_op->llseek == no_llseek) ++ if (!(out->f_mode & FMODE_PWRITE)) + return -EINVAL; + if (copy_from_user(&offset, off_out, sizeof(loff_t))) + return -EFAULT; +@@ -1343,8 +1342,7 @@ static long do_splice(struct file *in, l + if (off_out) + return -ESPIPE; + if (off_in) { +- if (!in->f_op || !in->f_op->llseek || +- in->f_op->llseek == no_llseek) ++ if (!(in->f_mode & FMODE_PREAD)) + return -EINVAL; + if (copy_from_user(&offset, off_in, sizeof(loff_t))) + return -EFAULT; diff --git a/queue-2.6.34/splice-direct_splice_actor-should-not-use-pos-in-sd.patch b/queue-2.6.34/splice-direct_splice_actor-should-not-use-pos-in-sd.patch new file mode 100644 index 00000000000..dc674bb9363 --- /dev/null +++ b/queue-2.6.34/splice-direct_splice_actor-should-not-use-pos-in-sd.patch @@ -0,0 +1,33 @@ +From 2cb4b05e7647891b46b91c07c9a60304803d1688 Mon Sep 17 00:00:00 2001 +From: Changli Gao +Date: Tue, 29 Jun 2010 13:09:18 +0200 +Subject: splice: direct_splice_actor() should not use pos in sd + +From: Changli Gao + +commit 2cb4b05e7647891b46b91c07c9a60304803d1688 upstream. + +direct_splice_actor() shouldn't use sd->pos, as sd->pos is for file reading, +file->f_pos should be used instead. + +Signed-off-by: Changli Gao +Signed-off-by: Miklos Szeredi +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + fs/splice.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1232,7 +1232,8 @@ static int direct_splice_actor(struct pi + { + struct file *file = sd->u.file; + +- return do_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags); ++ return do_splice_from(pipe, file, &file->f_pos, sd->total_len, ++ sd->flags); + } + + /** diff --git a/queue-2.6.34/writeback-remove-writeback_inodes_wbc.patch b/queue-2.6.34/writeback-remove-writeback_inodes_wbc.patch new file mode 100644 index 00000000000..503a3256a96 --- /dev/null +++ b/queue-2.6.34/writeback-remove-writeback_inodes_wbc.patch @@ -0,0 +1,147 @@ +From 9c3a8ee8a1d72c5c0d7fbdf426d80e270ddfa54c Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Thu, 10 Jun 2010 12:07:27 +0200 +Subject: writeback: remove writeback_inodes_wbc + +From: Christoph Hellwig + +commit 9c3a8ee8a1d72c5c0d7fbdf426d80e270ddfa54c upstream. + +This was just an odd wrapper around writeback_inodes_wb. Removing this +also allows to get rid of the bdi member of struct writeback_control +which was rather out of place there. + +Signed-off-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + fs/afs/write.c | 1 - + fs/btrfs/extent_io.c | 2 -- + fs/fs-writeback.c | 12 ++---------- + include/linux/writeback.h | 5 ++--- + mm/backing-dev.c | 3 +-- + mm/page-writeback.c | 3 +-- + 6 files changed, 6 insertions(+), 20 deletions(-) + +--- a/fs/afs/write.c ++++ b/fs/afs/write.c +@@ -680,7 +680,6 @@ int afs_writeback_all(struct afs_vnode * + { + struct address_space *mapping = vnode->vfs_inode.i_mapping; + struct writeback_control wbc = { +- .bdi = mapping->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_cyclic = 1, +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -2589,7 +2589,6 @@ int extent_write_full_page(struct extent + .sync_io = wbc->sync_mode == WB_SYNC_ALL, + }; + struct writeback_control wbc_writepages = { +- .bdi = wbc->bdi, + .sync_mode = wbc->sync_mode, + .older_than_this = NULL, + .nr_to_write = 64, +@@ -2623,7 +2622,6 @@ int extent_write_locked_range(struct ext + .sync_io = mode == WB_SYNC_ALL, + }; + struct writeback_control wbc_writepages = { +- .bdi = inode->i_mapping->backing_dev_info, + .sync_mode = mode, + .older_than_this = NULL, + .nr_to_write = nr_pages * 2, +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -660,8 +660,8 @@ static int writeback_sb_inodes(struct su + return 1; + } + +-static void writeback_inodes_wb(struct bdi_writeback *wb, +- struct writeback_control *wbc) ++void writeback_inodes_wb(struct bdi_writeback *wb, ++ struct writeback_control *wbc) + { + int ret = 0; + +@@ -699,13 +699,6 @@ static void writeback_inodes_wb(struct b + /* Leave any unwritten inodes on b_io */ + } + +-void writeback_inodes_wbc(struct writeback_control *wbc) +-{ +- struct backing_dev_info *bdi = wbc->bdi; +- +- writeback_inodes_wb(&bdi->wb, wbc); +-} +- + /* + * The maximum number of pages to writeout in a single bdi flush/kupdate + * operation. We do this so we don't hold I_SYNC against an inode for +@@ -744,7 +737,6 @@ static long wb_writeback(struct bdi_writ + struct wb_writeback_args *args) + { + struct writeback_control wbc = { +- .bdi = wb->bdi, + .sb = args->sb, + .sync_mode = args->sync_mode, + .older_than_this = NULL, +--- a/include/linux/writeback.h ++++ b/include/linux/writeback.h +@@ -27,8 +27,6 @@ enum writeback_sync_modes { + * in a manner such that unspecified fields are set to zero. + */ + struct writeback_control { +- struct backing_dev_info *bdi; /* If !NULL, only write back this +- queue */ + struct super_block *sb; /* if !NULL, only write inodes from + this super_block */ + enum writeback_sync_modes sync_mode; +@@ -75,7 +73,8 @@ int inode_wait(void *); + void writeback_inodes_sb(struct super_block *); + int writeback_inodes_sb_if_idle(struct super_block *); + void sync_inodes_sb(struct super_block *); +-void writeback_inodes_wbc(struct writeback_control *wbc); ++void writeback_inodes_wb(struct bdi_writeback *wb, ++ struct writeback_control *wbc); + long wb_do_writeback(struct bdi_writeback *wb, int force_wait); + void wakeup_flusher_threads(long nr_pages); + +--- a/mm/backing-dev.c ++++ b/mm/backing-dev.c +@@ -341,14 +341,13 @@ int bdi_has_dirty_io(struct backing_dev_ + static void bdi_flush_io(struct backing_dev_info *bdi) + { + struct writeback_control wbc = { +- .bdi = bdi, + .sync_mode = WB_SYNC_NONE, + .older_than_this = NULL, + .range_cyclic = 1, + .nr_to_write = 1024, + }; + +- writeback_inodes_wbc(&wbc); ++ writeback_inodes_wb(&bdi->wb, &wbc); + } + + /* +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -495,7 +495,6 @@ static void balance_dirty_pages(struct a + + for (;;) { + struct writeback_control wbc = { +- .bdi = bdi, + .sync_mode = WB_SYNC_NONE, + .older_than_this = NULL, + .nr_to_write = write_chunk, +@@ -537,7 +536,7 @@ static void balance_dirty_pages(struct a + * up. + */ + if (bdi_nr_reclaimable > bdi_thresh) { +- writeback_inodes_wbc(&wbc); ++ writeback_inodes_wb(&bdi->wb, &wbc); + pages_written += write_chunk - wbc.nr_to_write; + get_dirty_limits(&background_thresh, &dirty_thresh, + &bdi_thresh, bdi);