--- /dev/null
+From cb1cb1780f2025a7d612de09131bf6530f80fb1a Mon Sep 17 00:00:00 2001
+From: Rafael J. Wysocki <rjw@sisk.pl>
+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 <rjw@sisk.pl>
+
+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 <rjw@sisk.pl>
+Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 718be4aaf3613cf7c2d097f925abc3d3553c0605 Mon Sep 17 00:00:00 2001
+From: Len Brown <len.brown@intel.com>
+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 <len.brown@intel.com>
+
+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 <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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];
--- /dev/null
+From b6dacf63e9fb2e7a1369843d6cef332f76fca6a3 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Tue, 11 May 2010 13:49:25 -0400
+Subject: ACPI: Unconditionally set SCI_EN on resume
+
+From: Matthew Garrett <mjg@redhat.com>
+
+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 <mjg@redhat.com>
+Tested-by: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: Kamal Mostafa <kamal@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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 {
--- /dev/null
+From 7a0ea09ad5352efce8fe79ed853150449903b9f5 Mon Sep 17 00:00:00 2001
+From: Michal Hocko <mhocko@suse.cz>
+Date: Wed, 30 Jun 2010 09:51:19 +0200
+Subject: futex: futex_find_get_task remove credentails check
+
+From: Michal Hocko <mhocko@suse.cz>
+
+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 <mhocko@suse.cz>
+Acked-by: Darren Hart <dvhltc@us.ibm.com>
+Cc: Ingo Molnar <mingo@elte.hu>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Nick Piggin <npiggin@suse.de>
+Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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,
--- /dev/null
+From 85a83560afa69862639fb2d6f670b4440a003335 Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Sun, 23 May 2010 01:02:08 +0000
+Subject: isdn/capi: make reset_ctr op truly optional
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Acked-by: Karsten Keil <isdn@linux-pingi.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
--- /dev/null
+From 1b4843c5e8cbab86830da8a53b8288882060c059 Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Mon, 21 Jun 2010 13:55:20 +0000
+Subject: isdn/gigaset: correct CAPI connection state storage
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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 {
--- /dev/null
+From 23b36778b4c82577746d26e4ac0ae66c6f462475 Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Mon, 21 Jun 2010 13:54:50 +0000
+Subject: isdn/gigaset: correct CAPI DATA_B3 Delivery Confirmation
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
+ }
+
+ /*
--- /dev/null
+From 278a582989ade4cb5335762d6c5999562018859d Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Mon, 21 Jun 2010 13:54:35 +0000
+Subject: isdn/gigaset: correct CAPI voice connection encoding
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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,
--- /dev/null
+From 1ce368ff288ed872a8fee93b8a2b7706111feb9a Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Mon, 21 Jun 2010 13:55:05 +0000
+Subject: isdn/gigaset: encode HLC and BC together
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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
--- /dev/null
+From e7752ee280608a24e27f163641121bdc2c68d6af Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Mon, 21 Jun 2010 13:54:19 +0000
+Subject: isdn/gigaset: honor CAPI application's buffer size request
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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 <linux/isdnif.h>
+
++#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;
+ }
+ }
+ }
--- /dev/null
+From e487639dc8ca6bd6c19a4140f45ebc88da56ddd5 Mon Sep 17 00:00:00 2001
+From: Tilman Schmidt <tilman@imap.cc>
+Date: Sun, 23 May 2010 01:02:38 +0000
+Subject: isdn/gigaset: remove dummy CAPI method implementations
+
+From: Tilman Schmidt <tilman@imap.cc>
+
+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 <tilman@imap.cc>
+Acked-by: Karsten Keil <isdn@linux-pingi.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From b27759f880018b0cd43543dc94c921341b64b5ec Mon Sep 17 00:00:00 2001
+From: Rafael J. Wysocki <rjw@sisk.pl>
+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 <rjw@sisk.pl>
+
+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 <rjw@sisk.pl>
+Reported-by: Jaroslav KamenĂk <jaroslav@kamenik.cz>
+Tested-by: Antoni Grzymala <antekgrzymala@gmail.com>
+Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
--- /dev/null
+From 85a0e7539781dad4bfcffd98e72fa9f130f4e40d Mon Sep 17 00:00:00 2001
+From: Ondrej Zary <linux@rainbow-software.org>
+Date: Tue, 8 Jun 2010 00:32:49 +0200
+Subject: PM / x86: Save/restore MISC_ENABLE register
+
+From: Ondrej Zary <linux@rainbow-software.org>
+
+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 <linux@rainbow-software.org>
+Tested-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: H. Peter Anvin <hpa@linux.intel.com>
+Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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
+ */
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
--- /dev/null
+From 19c9a49b432f245c6293508d164a4350f1f2c601 Mon Sep 17 00:00:00 2001
+From: Changli Gao <xiaosuo@gmail.com>
+Date: Tue, 29 Jun 2010 13:10:36 +0200
+Subject: splice: check f_mode for seekable file
+
+From: Changli Gao <xiaosuo@gmail.com>
+
+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 <xiaosuo@gmail.com>
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 2cb4b05e7647891b46b91c07c9a60304803d1688 Mon Sep 17 00:00:00 2001
+From: Changli Gao <xiaosuo@gmail.com>
+Date: Tue, 29 Jun 2010 13:09:18 +0200
+Subject: splice: direct_splice_actor() should not use pos in sd
+
+From: Changli Gao <xiaosuo@gmail.com>
+
+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 <xiaosuo@gmail.com>
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
+ }
+
+ /**
--- /dev/null
+From 9c3a8ee8a1d72c5c0d7fbdf426d80e270ddfa54c Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Thu, 10 Jun 2010 12:07:27 +0200
+Subject: writeback: remove writeback_inodes_wbc
+
+From: Christoph Hellwig <hch@lst.de>
+
+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 <hch@lst.de>
+Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);