]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
.34 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 29 Jul 2010 00:13:30 +0000 (17:13 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 29 Jul 2010 00:13:30 +0000 (17:13 -0700)
17 files changed:
queue-2.6.34/acpi-pm-do-not-enable-gpes-for-system-wakeup-in-advance.patch [new file with mode: 0644]
queue-2.6.34/acpi-skip-checking-bm_sts-if-the-bios-doesn-t-ask-for-it.patch [new file with mode: 0644]
queue-2.6.34/acpi-unconditionally-set-sci_en-on-resume.patch [new file with mode: 0644]
queue-2.6.34/futex-futex_find_get_task-remove-credentails-check.patch [new file with mode: 0644]
queue-2.6.34/isdn-capi-make-reset_ctr-op-truly-optional.patch [new file with mode: 0644]
queue-2.6.34/isdn-gigaset-correct-capi-connection-state-storage.patch [new file with mode: 0644]
queue-2.6.34/isdn-gigaset-correct-capi-data_b3-delivery-confirmation.patch [new file with mode: 0644]
queue-2.6.34/isdn-gigaset-correct-capi-voice-connection-encoding.patch [new file with mode: 0644]
queue-2.6.34/isdn-gigaset-encode-hlc-and-bc-together.patch [new file with mode: 0644]
queue-2.6.34/isdn-gigaset-honor-capi-application-s-buffer-size-request.patch [new file with mode: 0644]
queue-2.6.34/isdn-gigaset-remove-dummy-capi-method-implementations.patch [new file with mode: 0644]
queue-2.6.34/pci-pm-do-not-use-native-pcie-pme-by-default.patch [new file with mode: 0644]
queue-2.6.34/pm-x86-save-restore-misc_enable-register.patch [new file with mode: 0644]
queue-2.6.34/series
queue-2.6.34/splice-check-f_mode-for-seekable-file.patch [new file with mode: 0644]
queue-2.6.34/splice-direct_splice_actor-should-not-use-pos-in-sd.patch [new file with mode: 0644]
queue-2.6.34/writeback-remove-writeback_inodes_wbc.patch [new file with mode: 0644]

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 (file)
index 0000000..1dee017
--- /dev/null
@@ -0,0 +1,108 @@
+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;
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 (file)
index 0000000..9396cae
--- /dev/null
@@ -0,0 +1,82 @@
+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];
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 (file)
index 0000000..73f8c08
--- /dev/null
@@ -0,0 +1,252 @@
+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 {
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 (file)
index 0000000..89d8f55
--- /dev/null
@@ -0,0 +1,82 @@
+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,
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 (file)
index 0000000..a376347
--- /dev/null
@@ -0,0 +1,37 @@
+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);
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 (file)
index 0000000..adf8e17
--- /dev/null
@@ -0,0 +1,596 @@
+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 {
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 (file)
index 0000000..142848d
--- /dev/null
@@ -0,0 +1,148 @@
+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);
+ }
+ /*
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 (file)
index 0000000..115a67f
--- /dev/null
@@ -0,0 +1,57 @@
+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,
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 (file)
index 0000000..1ac76cc
--- /dev/null
@@ -0,0 +1,154 @@
+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
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 (file)
index 0000000..347c842
--- /dev/null
@@ -0,0 +1,490 @@
+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;
+               }
+       }
+ }
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 (file)
index 0000000..b7b5bef
--- /dev/null
@@ -0,0 +1,66 @@
+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;
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 (file)
index 0000000..9d04d05
--- /dev/null
@@ -0,0 +1,92 @@
+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);
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 (file)
index 0000000..d17e929
--- /dev/null
@@ -0,0 +1,69 @@
+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
+        */
index bf2420e006929d879ad2f694abd44981186ca807..a8af551c135cccfea63b455e0376892d16073195 100644 (file)
@@ -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 (file)
index 0000000..56aa895
--- /dev/null
@@ -0,0 +1,45 @@
+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;
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 (file)
index 0000000..dc674bb
--- /dev/null
@@ -0,0 +1,33 @@
+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);
+ }
+ /**
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 (file)
index 0000000..503a325
--- /dev/null
@@ -0,0 +1,147 @@
+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);